[ 
https://issues.apache.org/jira/browse/CAMEL-26310?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
 ]

Work on CAMEL-26310 started by shashank.
----------------------------------------
> camel-core - a component created on first use can be used by another thread 
> before it has started (endpoints created on a component that is still 
> starting)
> -----------------------------------------------------------------------------------------------------------------------------------------------------------
>
>                 Key: CAMEL-26310
>                 URL: https://issues.apache.org/jira/browse/CAMEL-26310
>             Project: Camel
>          Issue Type: Bug
>          Components: camel-core
>            Reporter: shashank
>            Assignee: shashank
>            Priority: Major
>
> A component that is created on first use after CamelContext has started is 
> started by the thread that created it, after {{components.computeIfAbsent}} 
> has returned ({{AbstractCamelContext.getComponent}}, camel-base-engine, main 
> c536c99caaaa). Another thread that asks for the same component meanwhile gets 
> it from the map before it has started ({{created}} is false for that thread, 
> so it does not start it), and {{doGetEndpoint}} goes on to 
> {{component.createEndpoint(...)}} and starts the new endpoint on a component 
> that is still starting (or not started at all yet).
> A component that sets up in {{doStart}} what its endpoints use then fails for 
> that thread. For example {{VertxHttpComponent.doStart}} creates its managed 
> {{Vertx}}, and {{VertxHttpEndpoint.doStart}} creates its {{WebClient}} from 
> {{getComponent().getVertx()}}: the second thread gets 
> {{WebClient.create(null, ...)}}. The first sends to a new scheme after 
> startup are usually made from several threads at once (a ProducerTemplate in 
> a web service, a toD, recipient list, routing slip or enrich with a scheme 
> that is only known at runtime), so they fail intermittently with 
> {{ResolveEndpointFailedException}} or a NullPointerException from the 
> component.
> CAMEL-14891 (3.3.0, toD) and CAMEL-20230 (4.4.0, enrich and pollEnrich) work 
> around it by resolving the component of a uri with a fixed scheme when the 
> route starts; the race in {{getComponent}} remains for the other paths (a 
> {{ProducerTemplate}}, recipient list, routing slip, or a toD / enrich whose 
> scheme is only known at runtime). It also happens while CamelContext is 
> starting: the consumers of the routes that have already started can send 
> while the later routes start.
> Reproduced on main (latches, no sleeps): a component bound in the registry 
> whose {{doStart}} waits on a latch and creates a client its 
> {{createEndpoint}} uses; after context start, thread 1 calls 
> {{context.getEndpoint("slow:a")}} (creates and starts the component, held in 
> {{doStart}}), then thread 2 calls {{context.getEndpoint("slow:b")}}: thread 2 
> creates its endpoint while the component is {{Starting}} and fails 
> ({{ResolveEndpointFailedException}} ... {{Cannot invoke "Object.hashCode()" 
> because "this.client" is null}}). The same from a 
> {{StartupListener.onCamelContextStarting}} (CamelContext starting).
> *Fix*: when {{getComponent}} returns a component that another thread has just 
> created and that has not started yet or is starting (CamelContext started or 
> starting, {{autoStart}}), it starts it with {{ServiceHelper.startService}}: 
> the service lock of the component makes it wait while the creating thread is 
> in {{doStart}}, and it is a no-op once started. If the creating thread failed 
> to start it, the waiting thread tries to start it once more and gets an 
> exception or a started component. A component that has been stopped (such as 
> by {{removeComponent}}) or that failed to start before is returned as it is, 
> as before. The component is still started outside {{computeIfAbsent}} (the 
> deadlock the comment there mentions).
> *Tests*: new {{ComponentStartedBeforeUseTest}} (camel-core; latches, no 
> sleeps; a component whose {{doStart}} waits on a latch and then creates the 
> client its {{createEndpoint}} uses): 
> {{testOtherThreadWaitsForTheComponentToStart}} (after CamelContext has 
> started) and 
> {{testOtherThreadWaitsForTheComponentToStartWhileCamelContextStarts}} (from 
> {{StartupListener.onCamelContextStarting}}) fail on main 
> ({{ResolveEndpointFailedException}} caused by a null client) and pass with 
> the fix; {{testStoppedComponentIsNotStartedAgain}} is a control that passes 
> on both. camel-management component, endpoint and CamelContext tests: 94, 0 
> failures.
> *How it was found*: by reading the check-then-act uses of 
> {{ConcurrentHashMap}} in camel-base-engine ({{computeIfAbsent}} with a side 
> effect after it returns); reproduced on HotSpot with the test above.
> *Affected*: main, camel-4.22.x, camel-4.18.x and camel-4.14.x have the same 
> {{getComponent}} (read, not run).
> _Filed with Claude Code on behalf of allthingssecurity._



--
This message was sent by Atlassian Jira
(v10.3.26#10030026)

Reply via email to