Skip to content

templates: type the correlateMessageEvent catch in Abort and Wait, and the no-subscription miss behind it (#7230) - #7308

Merged
delchev merged 2 commits into
masterfrom
issue-7230-typed-correlate-catch
Sep 11, 2026
Merged

templates: type the correlateMessageEvent catch in Abort and Wait, and the no-subscription miss behind it (#7230)#7308
delchev merged 2 commits into
masterfrom
issue-7230-typed-correlate-catch

Conversation

@delchev

@delchev delchev commented Sep 10, 2026

Copy link
Copy Markdown
Contributor

What

#7184 (#7145) typed the blanket catch (RuntimeException) in AbortOnDelete.java.template, but the two siblings that wrap Process.correlateMessageEvent kept swallowing everything:

  • events/Abort.java.templatecatch (RuntimeException notAborting) {}
  • events/Wait.java.templatecatch (RuntimeException notParked) {}

A correlation that fails because the engine/DB is down, the tenant scope is wrong, or the message name was mis-generated was indistinguishable from the expected "the instance is not parked here" — and a wait step that is never resumed is exactly the kind of incident an operator has to explain later with nothing in the log.

The platform half

Typing the catch needed a typed miss to catch. BpmProviderFlowable.correlateMessageEvent queried the execution carrying the message subscription and then called execution.getId() — so an instance that is running but not subscribed to the message surfaced as a NullPointerException, which no listener can honestly single out. It now throws the same IllegalArgumentException that validateProcessInstanceId raises for an instance that has already ended (or belongs to another tenant), naming both the instance and the message.

The template half

Both templates follow the AbortOnDelete recipe:

} catch (IllegalArgumentException notParked) {
    LOG.debug("... was not parked on \"...\" ...", instance, notParked);
} catch (RuntimeException failed) {
    LOG.warn("Could not resume ... - it stays parked", instance, failed);
}

The warn message names the consequence in each case: a flow still running over a record whose status says it is over (abort), an instance that stays parked forever (wait). Fail-soft, but never silent. The class javadocs say the same.

Verification

  • IntentEngineIT77/77 green. Extended: the two catch shapes plus assertFalse that the old empty catch (RuntimeException notParked/notAborting) is gone.
  • IntentEmissionCoverageITgreen. Same assertions on RfqFlowAwaitReplyWait and ApprovalFlowAbort. Both ITs compile the generated handlers, so the new catch order is checked by javac, not only by contains.
  • components/engine/engine-bpm-flowable unit suite — 35/35 green.
  • formatter:validate green on the changed modules with the formatter cache wiped.

Not run: the full reactor test suite, and no runtime test exercises a correlation against a live down-engine (there is no existing harness for it).

Sibling sweep

Grepped every *.template for the same shape: the remaining catch (RuntimeException e) blocks in Trigger.java.template, Repository.java.template and the three Entity*Controller templates all log the throwable already. correlateMessageEvent is called from exactly these two templates.

Fixes #7230

🤖 Generated with Claude Code

delchev and others added 2 commits September 10, 2026 16:33
…d the no-subscription miss behind it (#7230)

The #7145 fix typed the blanket `catch (RuntimeException)` in AbortOnDelete.java.template
only; Abort.java.template and Wait.java.template still swallowed every RuntimeException
around `Process.correlateMessageEvent`. A correlation that fails because the engine is
down, the tenant scope is wrong or the message name was mis-generated was indistinguishable
from the expected "the instance is not parked here" - and a wait that is never resumed is
exactly the incident an operator has to explain later with nothing in the log.

Typing the catch needed the platform to report the expected miss as a type first:
BpmProviderFlowable.correlateMessageEvent dereferenced a null Execution when the instance
carried no subscription for the message, so the "not parked" outcome arrived as a
NullPointerException - not something a listener can honestly single out. It now throws the
same IllegalArgumentException the validator raises for an already-ended instance.

Both templates then follow the AbortOnDelete recipe: IllegalArgumentException is the quiet,
expected miss, logged at debug with its throwable; anything else is logged at warn with its
throwable, naming the consequence (a flow still running over a record whose status says it
is over; an instance that stays parked forever). Fail-soft, but never silent.

The two intent ITs that compile these templates assert the two catch shapes and that the
old empty catch is gone.

Fixes #7230

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
master landed the same #7230 fix (BpmProviderFlowable's typed miss, the two
templates and the IntentEmissionCoverageIT assertions), so those four files
resolve to master's version verbatim - its assertions are the stricter pair
(they also require the throwable in the debug log).

What survives from this branch is the half master did not touch: IntentEngineIT
still asserted only `catch (RuntimeException`, which the new two-catch shape
passes trivially. It now checks the typed miss, the warn-with-throwable, and
that the old empty catch is gone - on both the wait and the abort handler.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@delchev
delchev merged commit d1d94d9 into master Sep 11, 2026
10 checks passed
@delchev
delchev deleted the issue-7230-typed-correlate-catch branch September 11, 2026 06:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant