Skip to content

Conversation

@hunterino
Copy link

After this evaluation, Here is what I cam up with. I noticed a syngificant improvement in performance over 3.0

Moqui Framework - Comprehensive System Evaluation

Evaluation Date: 2025-11-25 (Updated: 2025-12-08)
Framework Version: 3.1.0-rc2
Codebase Size: ~77,000 lines (50,096 Groovy + 26,841 Java)


Recent Updates (2025-12-08)

Jakarta EE 10 Migration - COMPLETED

The framework has been successfully migrated to Jakarta EE 10, enabling full Java 21 compatibility.

Component Previous Current Status
Jetty 10.0.25 12.1.4 Completed
Jakarta Servlet API 5.0.0 6.0.0 Completed
Jakarta WebSocket API 2.0.0 2.1.1 Completed
Apache Shiro 2.0.6 1.13.0:jakarta Completed
Transaction Manager Bitronix Narayana Completed
Jakarta Activation N/A angus-activation 2.0.3 Added

Key Changes Made

  • All javax.* imports converted to jakarta.*
  • Jetty 12 EE10 modules with updated session handling APIs
  • Shiro 1.13.0 with jakarta classifier for servlet compatibility
  • Removed Bitronix TM (incompatible with Java 21), replaced with Narayana
  • Added angus-activation for Jakarta Activation SPI provider

Files Modified

  • framework/build.gradle - Updated dependencies
  • MoquiShiroRealm.groovy - Shiro 1.x import paths
  • ShiroAuthenticationTests.groovy - Updated test imports
  • MoquiStart.java - Jetty 12 session handling
  • WebFacadeImpl.groovy, WebFacadeStub.groovy - Jakarta servlet imports
  • RestClient.java, WebUtilities.java - Jakarta servlet imports
  • ElFinderConnector.groovy - Jakarta servlet imports
  • Removed TransactionInternalBitronix.groovy

Verification

  • Server starts successfully on port 8080
  • Login/authentication works with Shiro 1.13.0:jakarta
  • Session management functional
  • Vue-based Material UI loads correctly

PR: https://github.com/hunterino/moqui/pull/61 (Draft)


Executive Summary

This evaluation covers three key areas: Architecture, Security, and Technical Debt/Modernization. The Moqui Framework demonstrates solid foundational architecture with clear separation of concerns and well-defined layer boundaries. However, critical issues were identified in security (XXE vulnerability, weak password hashing) and significant technical debt exists in dependency management and testing infrastructure.

Overall Ratings

Area Rating Critical Issues
Architecture GOOD Tight coupling to ExecutionContextFactoryImpl
Security HIGH RISK 2 Critical, 5 High severity findings
Technical Debt MODERATE-HIGH Outdated dependencies, low test coverage

1. Architectural Review

SOLID Principles Assessment

Principle Rating Key Finding
SRP MEDIUM-HIGH God classes: ScreenRenderImpl (2,451 lines), EntityFacadeImpl (2,312 lines)
OCP HIGH Good extensibility via ServiceRunner, ToolFactory patterns
LSP MEDIUM ServiceCall hierarchy properly follows LSP
ISP HIGH Clean facade interfaces with focused responsibilities
DIP MEDIUM All facades depend on concrete ExecutionContextFactoryImpl

Key Architectural Strengths

  1. Clear Layered Architecture - Presentation (Screen) → Business Logic (Service) → Data (Entity)
  2. Strong Facade Pattern - Clean public APIs hiding implementation complexity
  3. Excellent Abstraction Quality - ResourceFacade, EntityFind, ServiceCall provide clean interfaces
  4. Consistent Naming Conventions - Intuitive method names and class organization
  5. Flexible Extensibility - Pluggable service runners, tool factories, components

Critical Architectural Issues

Issue 1: Dependency Inversion Violation

Location: All facade implementations
Problem: Every facade depends on concrete ExecutionContextFactoryImpl, not an interface

// Found in EntityFacadeImpl, ServiceFacadeImpl, ScreenFacadeImpl, etc.
protected final ExecutionContextFactoryImpl ecfi  // CONCRETE dependency

Impact: Cannot test facades in isolation, tight coupling across entire framework

Issue 2: God Classes

Class Lines Responsibilities
ScreenForm.groovy 2,683 Form rendering, validation, field handling
ScreenRenderImpl.groovy 2,451 Rendering, transitions, actions, state
EntityFacadeImpl.groovy 2,312 CRUD, caching, metadata, sequencing
ExecutionContextFactoryImpl.groovy 1,897 Factory, config, lifecycle, caching

Issue 3: Circular Dependencies

  • EntityFacadeImpl → ServiceFacadeImpl (for entity-auto services)
  • ServiceFacadeImpl → EntityFacadeImpl (for entity detection)

2. Security Audit (OWASP Top 10)

Critical Findings (Fix Immediately)

CRITICAL-1: XML External Entity (XXE) Vulnerability

Location: /framework/src/main/java/org/moqui/util/MNode.java:102-104
CVSS: 9.1
Impact: File disclosure, SSRF, remote code execution

XMLReader reader = SAXParserFactory.newInstance().newSAXParser().getXMLReader();
// No XXE protections configured

Fix: Disable external entity processing in XML parser

CRITICAL-2: Weak Password Hashing

Location: /framework/src/main/groovy/org/moqui/impl/context/ExecutionContextFactoryImpl.groovy
CVSS: 8.1
Impact: Password database compromise enables rapid cracking
Issue: SHA-256 via Apache Shiro SimpleHash - too fast, no proper KDF
Fix: Migrate to Argon2id, bcrypt, or PBKDF2 with 600,000+ iterations

High Severity Findings

ID Finding Location CVSS
HIGH-1 Session Fixation UserFacadeImpl.groovy:645-646 7.5
HIGH-2 Credentials in Logs UserFacadeImpl.groovy:160, 294 7.2
HIGH-3 Weak CSRF Tokens WebFacadeImpl.groovy:204-212 7.1
HIGH-4 Missing Cookie SameSite UserFacadeImpl.groovy:221-226 6.8
HIGH-5 API Keys in URLs UserFacadeImpl.groovy:169-173 5.9

Medium Severity Findings

ID Finding Location
MED-1 SQL Injection Risk (verify) EntityQueryBuilder.java:290-299
MED-2 Insecure Random (verify) StringUtilities.java
MED-3 Path Traversal Risk ResourceFacadeImpl.groovy
MED-4 Insecure Deserialization 13 files with readObject()
MED-5 Missing Security Headers MoquiServlet.groovy
MED-6 Dependency Vulnerabilities build.gradle

Positive Security Practices

  • Parameterized SQL queries in Entity Engine
  • CSRF token implementation exists
  • Session invalidation on logout
  • HttpOnly cookies for visitor tracking
  • Executable file upload blocking

3. Technical Debt & Modernization

Dependency Analysis

Critical Updates Required

Dependency Current Latest Risk
Apache Shiro 1.13.0 2.0.6 Security vulnerabilities in 1.x
Jetty 10.0.25 12.1.4 Security & HTTP/2 improvements
Jackson 2.18.3 2.20.1 Deserialization vulnerabilities
H2 Database 2.3.232 2.4.240 Performance & security
Groovy 3.0.19 3.0.25 / 4.0.x Security & performance

Legacy Dependencies

  • Bitronix TM: Custom build from 2016 (org.codehaus.btm:btm:3.0.0-20161020)
  • Commons Collections: 3.2.2 (last updated 2015)

Code Quality Metrics

Metric Current Target
Test Coverage <10% 60%
TODO/FIXME Count 167 <50
Average Class Size ~600 lines <300 lines
Dependency Age 18 months avg <6 months
System.out/err Usage 128 occurrences 0
Synchronized Blocks 49 Use j.u.c

Java 21 Modernization Gap

Current: Compiling to Java 11 bytecode, running on Java 21

sourceCompatibility = 11
targetCompatibility = 11

Missing Features: Records, Pattern Matching, Virtual Threads, Sealed Classes

Testing Infrastructure Gaps

  • Only 18 test files for 77,000 lines of code
  • Tests run single-threaded (maxParallelForks 1)
  • No integration tests, performance tests, or security tests
  • No CI/CD pipeline configured

4. Design Principles Evaluation

SOLID Principles

  • SRP: PARTIAL - Multiple God classes violate single responsibility
  • OCP: GOOD - Extensible via factories and runners
  • LSP: GOOD - Interface hierarchies follow substitution
  • ISP: GOOD - Focused facade interfaces
  • DIP: POOR - Concrete dependencies throughout

Coding Practices

  • DRY: PARTIAL - Build script has significant duplication
  • KISS: PARTIAL - Some over-engineered areas
  • YAGNI: GOOD - Limited dead code (167 TODOs)
  • Fail Fast: POOR - Many System.out instead of exceptions/logging

Maintainability

  • Meaningful Names: EXCELLENT - Clear, intuitive naming
  • Modularity: GOOD - Clear component boundaries
  • POLA: GOOD - Predictable behavior patterns
  • Testability: POOR - Tight coupling prevents isolated testing

5. Prioritized Remediation Roadmap

Phase 1: Critical Security (1-2 weeks)

Priority Task Effort
P0 Fix XXE vulnerability in MNode.java 1 day
P0 Upgrade password hashing to Argon2id/bcrypt 1 week
P1 Fix session fixation vulnerability 2 days
P1 Remove credentials from logs 1 day
P1 Add security headers 1 day

Phase 2: High-Priority Security & Dependencies (2-4 weeks)

Priority Task Effort
P1 Update Apache Shiro 1.13 → 2.0 3 weeks
P1 Update Jackson to latest 1 week
P1 Strengthen CSRF tokens with SecureRandom 2 days
P2 Add SameSite cookie attributes 1 day
P2 Move API keys from URL to headers 1 week

Phase 3: Java 21 & Testing (4-8 weeks)

Priority Task Effort
P2 Update sourceCompatibility to 21 1 week
P2 Setup GitHub Actions CI/CD 2 weeks
P2 Add JaCoCo coverage reporting 1 week
P2 Increase test coverage to 30% 4 weeks
P3 Update Groovy 3.0.19 → 3.0.25 2 weeks

Phase 4: Architecture & Refactoring (8-16 weeks)

Priority Task Effort
P3 Create ExecutionContextFactory interface 2 weeks
P3 Refactor God classes (extract responsibilities) 8 weeks
P3 Decouple Service-Entity circular dependency 4 weeks
P3 Replace synchronized with j.u.c 3 weeks
P4 Jetty 10 → 12 migration 6 weeks

Phase 5: Advanced Modernization (16+ weeks)

Priority Task Effort
P4 Achieve 60% test coverage 12 weeks
P4 Containerization (Docker/Kubernetes) 3 weeks
P4 Groovy 4.x migration 8 weeks
P5 GraphQL API layer 6 weeks
P5 Microservices extraction 24 weeks

6. Critical Files Requiring Attention

Security Fixes

  • /framework/src/main/java/org/moqui/util/MNode.java - XXE fix
  • /framework/src/main/groovy/org/moqui/impl/context/UserFacadeImpl.groovy - Auth/session
  • /framework/src/main/groovy/org/moqui/impl/context/WebFacadeImpl.groovy - CSRF, headers
  • /framework/src/main/groovy/org/moqui/impl/util/MoquiShiroRealm.groovy - Password hashing

Architecture Refactoring

  • /framework/src/main/groovy/org/moqui/impl/screen/ScreenForm.groovy - 2,683 lines
  • /framework/src/main/groovy/org/moqui/impl/screen/ScreenRenderImpl.groovy - 2,451 lines
  • /framework/src/main/groovy/org/moqui/impl/entity/EntityFacadeImpl.groovy - 2,312 lines
  • /framework/src/main/groovy/org/moqui/impl/context/ExecutionContextFactoryImpl.groovy - 1,897 lines

Build & Dependencies

  • /build.gradle - 1,320 lines of build logic
  • /framework/build.gradle - Dependency versions

7. Risk Assessment

Risk Probability Impact Mitigation
XXE exploitation HIGH CRITICAL Immediate fix required
Password database breach MEDIUM CRITICAL Upgrade hashing algorithm
Session hijacking MEDIUM HIGH Fix session fixation
Groovy upgrade breakage HIGH HIGH Extensive testing, incremental approach
Shiro 2.x migration issues MEDIUM HIGH Parallel auth testing
Test coverage gaps HIGH HIGH Characterization tests first

8. Success Criteria

Security

  • Zero Critical/High OWASP findings
  • All dependencies free of known CVEs
  • Security headers score A+ on SecurityHeaders.com

Code Quality

  • Test coverage > 60%
  • No classes > 500 lines
  • TODO count < 50
  • All System.out replaced with logging

Performance

  • Build time reduced by 30%
  • Test execution parallelized
  • Java 21 features adopted

9. Definition of Done

For Security Tickets

  • Vulnerability fixed and verified
  • Unit test covering the fix
  • Security scan passes (OWASP Dependency-Check)
  • Code review by security-aware developer

For Dependency Updates

  • Dependency updated in build.gradle
  • All existing tests pass
  • No new deprecation warnings
  • Manual smoke test of affected features

For Test Coverage

  • Tests written following existing patterns
  • Coverage increase verified in JaCoCo report
  • Tests run in CI pipeline
  • No flaky tests

For Architecture Changes

  • 60% test coverage exists for affected code
  • No public API changes (or documented if necessary)
  • All tests pass
  • Performance benchmarked (no regression)

pythys and others added 30 commits June 1, 2025 17:48
this resolves all warnings except java version
Upgrade gradle and Java with many related improvements (major breaking change)
Add secure SAXParserFactory configuration to prevent XML External Entity
(XXE) attacks in MNode XML parsing. This addresses CVSS 9.1 critical
vulnerability.

Changes:
- Create secure SAX parser factory with XXE protections enabled
- Disable DOCTYPE declarations (disallow-doctype-decl)
- Disable external general and parameter entities
- Disable external DTD loading
- Disable XInclude processing
- Enable SECURE_PROCESSING feature

Add comprehensive security tests:
- Test XXE with external entity
- Test XXE with parameter entity
- Test XXE via external DTD
- Test SSRF via XXE
- Test Billion laughs DoS attack
- Verify valid XML still parses correctly

Fixes #1

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Replace weak SHA-256 password hashing with BCrypt for improved security
against brute-force attacks. BCrypt includes adaptive cost factor and
built-in salt management.

Changes:
- Add bcrypt library dependency (at.favre.lib:bcrypt:0.10.2)
- Create PasswordHasher utility class with BCrypt and legacy support
- Implement BcryptCredentialsMatcher for Shiro integration
- Update ExecutionContextFactoryImpl to use BCrypt by default
- Maintain backward compatibility with existing SHA-256 hashes
- Add shouldUpgradePasswordHash() for migration detection
- Default BCrypt cost factor of 12 (configurable 10-14)

Key features:
- New passwords automatically use BCrypt
- Legacy SHA-256/SHA-512 hashes continue to work
- Framework detects when hash upgrade is needed
- BCrypt hashes are self-describing (include algorithm, cost, salt)

Comprehensive test coverage:
- BCrypt hash/verify operations
- Legacy algorithm compatibility
- Upgrade detection logic
- Edge cases (null, empty, special characters)
- Cost factor extraction and upgrade detection

Fixes #2

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Move session regeneration to AFTER successful authentication to prevent
session fixation attacks (CWE-384, CVSS 7.5).

Problem:
- Previous code regenerated session BEFORE authentication
- This created a window where attacker could obtain the new session ID
- After user authenticates, attacker could hijack the authenticated session

Solution:
- Remove premature session regeneration from loginUser()
- Add session regeneration in internalLoginToken() AFTER successful auth
- Session is only regenerated on successful authentication
- Failed login attempts don't regenerate the session

The fix follows OWASP Session Management guidelines:
https://cheatsheetseries.owasp.org/cheatsheets/Session_Management_Cheat_Sheet.html

Fixes #3

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Remove sensitive credential data from log statements to prevent exposure
in log files (CWE-532, CVSS 7.2).

Fixed locations:
- Line 160: HTTP Basic Auth parsing failure - removed credential logging
- Line 294: HTTP Basic Auth parsing failure - removed credential logging
- Line 306: Removed debug statement that logged login_key

Changes:
- Replace credential logging with safe metadata-only messages
- Log that parsing failed without exposing the actual values
- Remove accidental debug logging of API/login keys

This prevents:
- Credentials stored in log files
- Unauthorized access to credentials via log file access
- Compliance violations (PCI-DSS, GDPR)

Follows OWASP Logging Cheat Sheet:
https://cheatsheetseries.owasp.org/cheatsheets/Logging_Cheat_Sheet.html

Fixes #5

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Add comprehensive security headers to all HTTP responses following OWASP
Secure Headers Project recommendations.

Security headers added:
- X-Content-Type-Options: nosniff (prevents MIME-sniffing attacks)
- X-Frame-Options: SAMEORIGIN (prevents clickjacking)
- X-XSS-Protection: 1; mode=block (legacy XSS protection)
- Referrer-Policy: strict-origin-when-cross-origin
- Permissions-Policy: restricts geolocation, microphone, camera
- Strict-Transport-Security: HSTS with 1-year max-age (HTTPS only)
- Content-Security-Policy: conservative default allowing inline scripts

Implementation details:
- Headers added early in request lifecycle (after CORS handling)
- Configurable via webapp response-header elements with type="security"
- Default headers only set if not already configured
- HSTS only sent on secure connections

Configuration override example in MoquiConf.xml:
  <response-header type="security" name="X-Frame-Options" value="DENY"/>
  <response-header type="security" name="Content-Security-Policy"
                   value="default-src 'self'"/>

Fixes #4

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Upgrade Apache Shiro from 1.13.0 to 2.0.6 to address security vulnerabilities
and modernize the authentication/authorization framework.

Breaking changes addressed:
- IniSecurityManagerFactory removed: Use programmatic configuration
- SimpleByteSource moved: org.apache.shiro.util → org.apache.shiro.lang.util
- Crypto/cache/event modules split into separate artifacts

Dependencies added:
- shiro-core:2.0.6
- shiro-web:2.0.6
- shiro-crypto-hash:2.0.6
- shiro-crypto-cipher:2.0.6
- shiro-cache:2.0.6
- shiro-event:2.0.6

Code changes:
- ExecutionContextFactoryImpl: Programmatic SecurityManager initialization
- MoquiShiroRealm: Update SimpleByteSource import

Shiro 2.x benefits:
- Security fixes for CVEs
- Improved session management
- Better crypto support (built-in Argon2/bcrypt)
- Modern Java support

All existing tests pass with Shiro 2.0.6.

Fixes #6, #7, #8, #9

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Add unit tests to verify authentication components work correctly
after the Shiro 2.0.6 migration.

Test coverage:
- DefaultSecurityManager initialization
- HashedCredentialsMatcher with SHA-256 for legacy passwords
- SimpleByteSource with new package location (org.apache.shiro.lang.util)
- BCrypt password hashing integration with Shiro
- UsernamePasswordToken creation and handling
- SimpleHash with multiple algorithms (SHA-256, SHA-512, MD5)
- Multiple hash iterations
- Base64 and Hex encoding for password hashes
- PasswordHasher legacy algorithm compatibility with Shiro SimpleHash

All 10 authentication tests pass with Shiro 2.0.6.

Fixes #10

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
hunterino and others added 30 commits December 19, 2025 18:22
Fixed parameter name inconsistency where service definitions used
'thruUpdateStamp' but the implementation code used 'thruUpdatedStamp'.

Files fixed:
- EntityServices.xml: get#DataFeedDocuments service
- SearchServices.xml: index#DataFeedDocuments service

This caused the thruUpdateStamp parameter to be ignored when calling
these services, as the code was referencing a different variable name.

Fixes #7

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
fix: Correct thruUpdateStamp parameter name mismatch
fix: Add CSV escape character support for embedded quotes
)

Previously, EntityFindBase.oneInternal() would strip all non-PK conditions
when a full primary key was provided, treating them as "over-constrained".
This was semantically incorrect as users may legitimately want to validate
additional conditions alongside PK lookups (e.g., status checks).

Changes:
- Removed the code block that discarded non-PK conditions (lines 783-796)
- Added test to verify non-PK conditions are honored with PK queries

Before: ec.entity.find("Entity").condition("pk", "1").condition("status", "ACTIVE")
        would ignore the status condition entirely.

After: Both pk AND status conditions are included in the query.

Fixes #14

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
…-conditions

fix: Preserve non-PK conditions in entity find when full PK present
Previously, EntityValueBase only logged CREATE and UPDATE operations to
the EntityAuditLog. DELETE operations were not logged, creating a
compliance and security gap.

Changes:
- Added handleAuditLogDelete() method to log field values being deleted
- Modified delete() to call handleAuditLogDelete() after successful delete
- Delete audit logs show oldValueText (deleted value) with null newValueText

The delete audit log behavior:
- Logs all fields that have enable-audit-log="true" or "update"
- Records the deleted value in oldValueText
- Sets newValueText to null to indicate deletion
- Includes changedByUserId, changedDate, and artifactStack

Fixes #9

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
fix: Add audit logging for entity delete operations
When "Clear Parameters" is clicked, the _op parameter is cleared from
inputFieldsMap but field values may remain. Previously, this caused the
query to default to "equals" operator instead of using the operator
specified in defaultParameters.

Changes:
- Modified processInputFields to accept defaultParameters as a parameter
- Updated _op, _not, _ic lookups to use defaultParameters as fallback
  before defaulting to built-in values
- Added test verifying defaultParameters is used when _op not in input

This ensures that clearing parameters doesn't change query behavior
when defaultParameters specifies the intended operator.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
The "Potential lock conflict" message is logged when lock tracking
detects multiple transactions may be holding locks on the same entity.
This is informational - it's a potential conflict, not a confirmed issue.

Changed log level from warn to info to reduce logging noise:
- Potential conflicts are still logged for debugging when needed
- Production logs won't be flooded with these messages
- Users can enable INFO level for this logger if needed

The lock tracking feature is already disabled by default (entity_lock_track=false).
This change reduces noise when it IS enabled for debugging.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
When bulk indexing to Elasticsearch fails, the sync would previously
stop immediately and lose all remaining documents. This caused sync
failures for large datasets where network issues or ES overload could
cause individual batch failures.

Changes:
- Added bulkIndexWithRetry helper method with configurable retries
- Implements exponential backoff (1s, 2s, 4s) between retries
- Continues processing remaining documents even if a batch fails
- Logs warnings for failed batches instead of stopping entirely

This improves reliability when syncing large datasets to Elasticsearch,
addressing the timeout and failure scenarios described in upstream moqui#592.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
The job scheduler uses expireLockTime to detect and recover from
stale locks caused by server crashes during job execution.

Previous behavior: Default of 1440 minutes (24 hours) meant jobs
could be blocked for an entire day if a server crashed mid-execution.

New behavior: Default reduced to 120 minutes (2 hours), which:
- Allows recovery from stale locks much faster
- Still provides enough time for most long-running jobs
- Jobs that need more time can set expireLockTime explicitly

Updated ServiceJob entity documentation to reflect new default.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
BIG: upgrade all dependencies of the system
Execute Groovy shell evaluations off the WebSocket thread to avoid
blocking I/O. Introduce a volatile closing flag to coordinate async
shutdown and prevent races.

Add idle and evaluation timeouts to protect against leaked sessions and
long-running or stuck scripts. Ensure all async paths are guarded with
try/catch and consistently clean up ExecutionContext, timers, and
executor resources on close.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

5 participants