[
https://issues.apache.org/jira/browse/CAMEL-26541?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
]
Work on CAMEL-26541 started by shashank.
----------------------------------------
> camel-core - interceptSendToEndpoint: an endpoint created while a route
> starts or stops gets the wrong interceptors
> -------------------------------------------------------------------------------------------------------------------
>
> Key: CAMEL-26541
> URL: https://issues.apache.org/jira/browse/CAMEL-26541
> Project: Camel
> Issue Type: Bug
> Components: camel-core
> Reporter: shashank
> Assignee: shashank
> Priority: Major
>
> Found with a TLA+ model of {{InterceptSendToEndpointManager}} (CAMEL-25140):
> a thread that creates an endpoint (a {{toD}} to an endpoint that is not in
> the registry yet) and the lifecycle thread that starts, stops, removes and
> adds again a route with {{interceptSendToEndpoint}}. Then reproduced on the
> real classes.
> Since CAMEL-25140 a route registers its interceptor when it starts and
> unregisters it when it stops. {{register}} and {{unregister}} run under the
> manager's lock and update the wrapped endpoints that are *in the endpoint
> registry*. A new endpoint gets the interceptors in {{registerEndpoint}} (the
> endpoint strategy), without that lock, and
> {{AbstractCamelContext.addEndpointToRegistry}} puts it in the registry only
> after the strategies returned. A route that starts or stops between the two
> steps does not see the new endpoint:
> * *start*: the running route's interceptor is missing on the endpoint, so its
> {{interceptSendToEndpoint}} does not apply to it.
> * *stop or remove*: the stopped route's interceptor stays on the endpoint. It
> runs on the stopped route's error handler, so the sends that use it fail with
> {{RouteStoppingException}} ("The exchange cannot continue: its route is being
> stopped or reloaded"): the sends of routes without an interceptor of their
> own and of a {{ProducerTemplate}}, including the send that created the
> endpoint. After a stop this lasts until the route starts again. After a
> remove it stays when the route is added again, and the new route's own sends
> fail too (the old interceptor has the same route id and runs first).
> Short trace (start):
> {noformat}
> toD thread: registerEndpoint: wrapper created, registrations = [] (no
> interceptor added)
> lifecycle: startRoute -> register: registrations = [r]; scan registry
> (endpoint not there)
> toD thread: endpoints.put(wrapper) ->
> route r running, endpoint not intercepted
> {noformat}
> Reproducer (the test pauses the thread that creates the endpoint just before
> {{endpoints.put}}, with an endpoint registry that waits on a latch, and
> starts or stops the route meanwhile):
> {code:java}
> // builder 1
> interceptSendToEndpoint("mock:dyn*").to("mock:intercepted");
> from("direct:start").routeId("start").toD("mock:${header.name}");
> // builder 2, no interceptor
> from("direct:other").routeId("other").toD("mock:${header.name}");
> // thread A: template.sendBodyAndHeader("direct:other", "Hello", "name",
> "dyn1") -> paused before endpoints.put
> // main: routeController.startRoute("start") (it was stopped before)
> // release A
> template.sendBodyAndHeader("direct:start", "Bye", "name", "dyn1"); //
> mock:intercepted gets nothing
> {code}
> On main (e05c5485d507) the start, stop and remove-and-add-again cases fail;
> the same steps one after the other pass. Without the latch, a stress loop
> (new {{toD}} endpoints while the route starts and stops) hit it on main too.
> The window is small, but route reloads and route policies stop and start
> routes under traffic, and the result stays (until the endpoint is created
> again or, for a missing interceptor, until a route with
> {{interceptSendToEndpoint}} starts).
> *Proposal*
> * {{registerEndpoint}} wraps the endpoint under the manager's lock (a read
> lock; {{addPattern}}, {{register}} and {{unregister}} take the write lock),
> and the manager remembers the wrappers it returns (weak keys, as a {{toD}}
> endpoint can be evicted from the registry), so {{register}} and
> {{unregister}} also update the wrappers that are not in the registry yet.
> Endpoints that match no pattern take no lock. This keeps the CAMEL-25140
> design; the model holds with it.
> * Not covered (it would need the registry put under the same lock): a route
> added at runtime with a new uri pattern, while a matching endpoint is being
> created, can leave that endpoint unwrapped until the next start of a route
> with {{interceptSendToEndpoint}}.
> Affects: 4.23.0 (CAMEL-25140), main. CAMEL-25141 would narrow the stop/remove
> case to the route's own sends, not remove it.
> _Filed with Claude Code on behalf of allthingssecurity._
--
This message was sent by Atlassian Jira
(v10.3.26#10030026)