Skip to content

FOUR-32497: [Octane] MEDIUM — Accumulating State "pmFunctions" - #8962

Open
rodriquelca wants to merge 1 commit into
feature/FOUR-32464from
feature/FOUR-32497
Open

FOUR-32497: [Octane] MEDIUM — Accumulating State "pmFunctions"#8962
rodriquelca wants to merge 1 commit into
feature/FOUR-32464from
feature/FOUR-32497

Conversation

@rodriquelca

Copy link
Copy Markdown
Contributor

Issue & Reproduction Steps

RegisterPMFunction()only stored callables in the static array, but did not register them in the currentExpressionLanguage` instance. This meant:

  1. Custom functions registered after initFormalExpression() were not available for immediate evaluation.
  2. In Octane, registered functions leaked across requests (expected), but were unavailable in the request where they were registered (bug).

Solution

Modified registerPMFunction() to perform dual registration:

  1. Store in static::$pmFunctions (bounded registry for Octane persistence).
  2. Immediately register in $this->feelExpression if the ExpressionLanguage instance exists.

How to Test

un the dedicated Octane test suite:

vendor/bin/phpunit tests/Unit/ProcessMaker/Models/FormalExpressionOctaneTest.php

Related Tickets & Packages

Code Review Checklist

  • I have pulled this code locally and tested it on my instance, along with any associated packages.
  • This code adheres to ProcessMaker Coding Guidelines.
  • This code includes a unit test or an E2E test that tests its functionality, or is covered by an existing test.
  • This solution fixes the bug reported in the original ticket.
  • This solution does not alter the expected output of a component in a way that would break existing Processes.
  • This solution does not implement any breaking changes that would invalidate documentation or cause existing Processes to fail.
  • This solution has been tested with enterprise packages that rely on its functionality and does not introduce bugs in those packages.
  • This code does not duplicate functionality that already exists in the framework or in ProcessMaker.
  • This ticket conforms to the PRD associated with this part of ProcessMaker.

@processmaker-sonarqube

Copy link
Copy Markdown

Quality Gate passed Quality Gate passed

Issues
0 New issues
0 Accepted issues

Measures
0 Security Hotspots
No data about Coverage
0.0% Duplication on New Code

See analysis details on SonarQube

@pmPaulis
pmPaulis changed the base branch from feature/FOUR-30918 to feature/FOUR-32464 July 31, 2026 20:11
@pmPaulis
pmPaulis requested a review from devmiguelangel July 31, 2026 20:19
@gproly
gproly self-requested a review July 31, 2026 20:31

@gproly gproly left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The PR adds late-registration sync to ExpressionLanguage and tests, but does not resolve the Octane issue: FormalExpression::$pmFunctions remains a private static array.

Gap vs ticket: No reset lifecycle, no bounded registry, no Octane integration. The static property still persists across worker requests.

Issue with tests: test_pm_functions_do_not_accumulate_across_requests asserts persistence (assertArrayHasKey('customFn', ...)) — opposite of the leak the ticket targets.

On resetPmFunctions() in ResetRequestState:

  • Non-Octane: registerOctaneListeners() no-ops without RequestTerminated — no impact.
  • Octane: reset prevents accumulation, but the static + registerPMFunctions() foreach implies worker-scoped registration. Clearing after each request breaks boot-time registration in ServiceProvider::boot().
  • Current regression surface: zero — registerPMFunction() has no production callers.

Required before merge:

  1. Define API contract: worker-scoped (stateless callables) vs request-scoped.
  2. Implement accordingly:
    • Worker-scoped → keep static, document stateless requirement, optional dedup by name (already keyed).
    • Request-scoped → reset on RequestTerminated + re-register on RequestReceived or boot listener.
  3. Replace persistence assertions with reset/re-registration tests tied to ResetRequestState / RequestTerminated.

Keep the late-registration block in registerPMFunction() — it is orthogonal and valid.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants