shashank created CAMEL-26453:
--------------------------------
Summary: camel-dynamic-router - a route that sends to a Dynamic
Router channel cannot be added again after it was removed
Key: CAMEL-26453
URL: https://issues.apache.org/jira/browse/CAMEL-26453
Project: Camel
Issue Type: Bug
Components: camel-core
Reporter: shashank
Assignee: shashank
{{DynamicRouterEndpoint.doInit()}} creates the {{DynamicRouterProcessor}} of
its channel and adds it to the component with
{{DynamicRouterComponent.addRoutingProcessor(channel, processor)}}, which fails
when the channel already has a processor ({noformat}Dynamic Router can have
only one processor per channel; channel 'orders' already has a
processor{noformat}). Nothing ever removes the processor again, except the
{{doShutdown}} of the component (when the CamelContext shuts down).
When a route that sends to {{dynamic-router:orders}} is removed, Camel stops
and removes the endpoints that only that route used, so the endpoint is gone
but its processor stays in the component. Then:
* adding the route again fails with {{FailedToCreateRouteException}} ...
{{already has a processor}} (a route reload in development mode replaces the
routes of a changed file by removing and adding them, and fails the same way);
* a {{toD("dynamic-router:${header.channel}")}} in another route, which used
the same endpoint while the removed route existed (a {{toD}} endpoint does not
keep an endpoint in use), creates the endpoint again on its next message and
fails every exchange with {{ResolveEndpointFailedException}};
* the same happens when the producer cache of a {{toD}} evicts the endpoint and
a later message creates it again.
The subscriptions of the channel are kept by the component (filter service), so
the channel would work again as soon as the new endpoint can register its
processor.
Reproducer (on main 4ab42b192b26):
{code:java}
from("direct:subscribe").to("dynamic-router-control:subscribe?subscribeChannel=orders&subscriptionId=all&destinationUri=mock:result&priority=1&predicate=true");
from("direct:start").routeId("router").to("dynamic-router:orders");
context.getRouteController().stopRoute("router");
context.removeRoute("router");
context.addRoutes(sameRouterRoute); // FailedToCreateRouteException: ...
channel 'orders' already has a processor
{code}
The same check makes an endpoint that is stopped and started again fail, as
{{BaseService.start}} runs {{init}} again after a stop.
*Proposal*
* The component keeps one processor per channel, with the endpoint that uses
it. An endpoint with the same URI takes the same processor (a route removed and
added again, a reload, a {{toD}} re-creating the endpoint, an endpoint started
again); an endpoint with another URI still fails while the endpoint that uses
the processor is in use, and replaces the processor once that endpoint is
stopped (the new processor is created first; the old {{RecipientList}} is
stopped, and its thread pool is only shut down with the component so that
exchanges another route still has in flight in it are not interrupted; replaced
processors are kept until the component shuts down).
* Nothing is stopped when an endpoint stops, so a send that still uses a
removed or evicted endpoint keeps routing, and no processor or
{{parallelProcessing}} pool is created per re-creation.
* The producer fails the exchange with a clear exception naming the channel
when the channel has no processor, instead of a {{NullPointerException}};
{{doShutdown}} of the component stops the processors (it passes the map itself
to {{ServiceHelper.stopAndShutdownService}} today, which stops nothing).
* Tests: remove the route and add it again (with the same and with other
options), a {{toD}} after the route was removed, a stop and start of the
endpoint, a second endpoint for the channel, a send through a removed endpoint,
an exchange in flight with {{parallelProcessing}}.
_Filed with Claude Code on behalf of allthingssecurity._
--
This message was sent by Atlassian Jira
(v10.3.26#10030026)