shashank created CAMEL-26286:
--------------------------------
Summary: camel-disruptor - removing one of the routes that use a
disruptor endpoint shuts down its disruptor, so the other routes stop receiving
and producers fail with "Disruptor was not started"
Key: CAMEL-26286
URL: https://issues.apache.org/jira/browse/CAMEL-26286
Project: Camel
Issue Type: Bug
Components: camel-disruptor
Reporter: shashank
Assignee: shashank
Every route and producer that uses the same {{disruptor:}} uri shares one
{{DisruptorEndpoint}}. When a route is removed, the core stops and shuts down
the endpoint of its consumer ({{RouteService.doShutdown}}), also when other
routes still consume from it or send to it. {{DisruptorEndpoint.doStop}} then
calls {{DisruptorReference.removeEndpoint}}, which shuts down the disruptor and
its executor when this was the only endpoint of the reference: all the routes
of one uri share one endpoint, and only another uri with the same queue name
(other options) has another endpoint on the same reference (main 36bebb520a63,
{{DisruptorEndpoint}} line 271, {{DisruptorReference}} lines 422-436).
Example: three routes {{from("disruptor:orders?multipleConsumers=true")}}; one
of them is stopped and removed (a route template removed, a reload,
JMX/controlbus). The two other routes receive nothing any more, and every send
to {{disruptor:orders?multipleConsumers=true}} fails with
{{IllegalStateException: Disruptor was not started}} (caused by
{{DisruptorNotStartedException: Disruptor is not yet started or already shut
down.}}). A {{CamelContext.stop()}} afterwards takes about 10 seconds (event
handlers that do not stop are waited for), with a {{RuntimeException:
java.lang.InterruptedException}} from a disruptor thread.
camel-seda has the same sharing and guards against it: {{SedaEndpoint.stop()}}
and {{shutdown()}} do nothing while the endpoint still has consumers or
producers. The same three-route scenario on
{{seda:orders?multipleConsumers=true}} keeps delivering to the other two routes.
*Fix*: {{DisruptorEndpoint}} overrides {{stop()}} and {{shutdown()}} like
{{SedaEndpoint}}, but only for consumers: they do nothing (DEBUG log) while
other consumers still use the endpoint, so the disruptor stays up for them.
Without consumers the endpoint stops and shuts down as before. Producers are
deliberately not counted: a producer of a removed route's uri (such as a cached
{{ProducerTemplate}} producer) would otherwise keep the old endpoint in the
disruptor, and its replacement (the endpoint is removed from the registry when
no other route uses it) could not join it ({{DisruptorReference}} keeps its
endpoints in a set based on {{equals}}, i.e. on the uri), which broke
{{DisruptorRemoveRouteThenAddAgainTest}}. disruptor-vm endpoints inherit the
change.
*Tests*: new {{DisruptorRemoveRouteOfSharedEndpointTest}}:
{{removingOneOfSeveralConsumersKeepsTheOthersConsuming}} fails on main with the
exception above (3 runs);
{{consumerRouteRemovedAndAddedAgainWhileAProducerRouteUsesTheQueue}} (a reload
of the consumer route while a producer route stays) passes on main and with the
fix; it is a control for the path the fix leaves unchanged. With the fix the
module has 120 tests, 0 failures.
*How it was found*: a random lifecycle-sequence harness (stop, start, suspend,
resume, remove and add of several consumer routes on shared endpoints, checking
after each step which routes receive a probe message) run over seda, disruptor,
timer, scheduler and other consumers; it shrank the failing sequence to a
single remove. The same harness found nothing for seda.
*Affected*: main, camel-4.22.x, camel-4.18.x and camel-4.14.x (same
{{DisruptorEndpoint.doStop}} and core {{RouteService.doShutdown}}; read, not
run).
_Filed with Claude Code on behalf of allthingssecurity._
--
This message was sent by Atlassian Jira
(v10.3.26#10030026)