shashank created CAMEL-26541:
--------------------------------

             Summary: 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


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)

Reply via email to