shashank created CAMEL-26630:
--------------------------------
Summary: camel-core - exchange sanitizer: dev-mode checks that
each exchange's callback runs exactly once and each consumer commit runs once
Key: CAMEL-26630
URL: https://issues.apache.org/jira/browse/CAMEL-26630
Project: Camel
Issue Type: New Feature
Components: camel-core
Reporter: shashank
Assignee: shashank
A dev-mode checker for exchanges, proposed on Zulip and asked for as a design
proposal, a JIRA and a PR, as was done for camel-chaos (CAMEL-26330).
*Motivation*
Several concurrency bugs found this year broke the contracts of
{{AsyncProcessor}} and of on completions without failing at the place of the
bug:
* an exchange completed twice: CAMEL-25095 (camel-jms) and CAMEL-25122
(camel-sjms), InOut, where a send failure completes an exchange that the
request timeout or the reply already completed; CAMEL-26446, a throw on the
first delivery that could continue the exchange twice;
* a processor that throws from {{process(exchange, callback)}} instead of
calling the callback, so the exchange hangs: CAMEL-26430, CAMEL-26445,
CAMEL-26461, CAMEL-26464, CAMEL-26601;
* the consumer's commit with a shared unit of work: CAMEL-26569, CAMEL-26576.
User code breaks the same contracts the same way: a custom {{AsyncProcessor}}
with a timeout of its own that calls the callback from the timeout and again
from the reply, a custom consumer whose commit runs twice, an
{{AggregationStrategy}} that throws. The sanitizer checks Camel's code and the
user's alike, in the tests the user already has.
*Rules*
* R1: the callback of each call of a step's processor is called exactly once.
Reported: completed twice (logged at the second call, before it continues the
exchange, with the stack of the first call kept), threw before calling the
callback, a callback after the processor threw, and, as a warning that
complements the inflight console, a call still pending.
* R2: each consumer commit (an on completion the consumer adds before routing,
which can be handed over to a seda copy or shared with shareUnitOfWork; not
{{UnitOfWork.done}}) runs exactly once, in the unit of work that holds it, and
is handed over only by the exchange its unit of work was created for.
* R3: an exchange is never used by two threads at the same time, checked
through the {{AsyncProcessor}} contract ({{doneSync}} equals what {{process}}
returned) and sampled overlaps in time of the engine's accesses (as KCSAN
does), with no dependency on a handover API.
* R4: the tasks an executor drops at shutdown are listed.
Pooled exchanges (deprecated in 4.23) are not supported.
*SPI*
Two small listener SPIs in camel-api, {{StepListener}} (the call of a step's
processor, its return, its throw, each call of its callback) and
{{OnCompletionListener}} (a unit of work set, an on completion added, handed
over, taken and run). They only observe, and more than one can be installed, so
the sanitizer runs together with chaos (which uses the one-per-context
{{StepHook}}, CAMEL-26338), the debugger, the tracer and JMX. The step listener
is a wrapper built by the channel around the step's processor only when a
listener is installed, so with none a step costs nothing more; the on
completion places check an empty list (measured with JMH).
*Switch*
A {{camel-sanitizer}} module with a {{ContextServicePlugin}}, as camel-chaos:
on with profile {{dev}} or {{camel.sanitizer.enabled=true}}, never with profile
{{prod}}. A JUnit extension ({{@CamelSanitizer}}) fails a test on the first
violation; the test dependency and system properties run an existing suite with
it in CI; a dev console and {{camel get sanitizer}} show the report.
*Plan*
R1 first, run on the commits before the fixes above to show each one is
reported at the right step, and on the camel-core suite and the netty,
netty-http, vertx-http and JMS request/reply suites to show it is quiet on
main; JMH for the cost; then R2, R3, the console and CLI, and R4 last. Each
step is its own PR.
Design: design/exchange-sanitizer.adoc (PR to follow).
_Filed with Claude Code on behalf of allthingssecurity._
--
This message was sent by Atlassian Jira
(v10.3.26#10030026)