[
https://issues.apache.org/jira/browse/CAMEL-25037?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
]
Claus Ibsen updated CAMEL-25037:
--------------------------------
Fix Version/s: 4.23.0
> camel-support - an interrupted EventDrivenPollingConsumer.receive() never
> returns: it loops at 100 % CPU and logs a WARN on every iteration (regression
> of CAMEL-20297, 4.4)
> ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------
>
> Key: CAMEL-25037
> URL: https://issues.apache.org/jira/browse/CAMEL-25037
> Project: Camel
> Issue Type: Bug
> Components: camel-core
> Reporter: shashank
> Priority: Minor
> Fix For: 4.23.0
>
>
> {{EventDrivenPollingConsumer.receive()}}
> ({{core/camel-support/.../EventDrivenPollingConsumer.java:128-153}}) loops
> {{while (isRunAllowed())}} around {{queue.take()}}. On
> {{InterruptedException}} it calls {{handleInterruptedException}}
> ({{:236-239}}). Since CAMEL-20297 (commit ff48bbc4d2, 4.4.0) that method
> restores the interrupt flag ({{Thread.currentThread().interrupt()}}) and then
> logs through the {{LoggingExceptionHandler}} at WARN. The loop then calls
> {{take()}} again, which throws at once because the flag is set, and so on.
> The thread never leaves {{receive()}}, even when a message is queued, because
> {{take()}} checks the flag first. It uses a full core and writes one WARN
> line per iteration.
> This is the same pattern as CAMEL-22390 (SedaConsumer infinite loop on
> interrupt, also caused by CAMEL-20297). That issue was closed as "Information
> Provided" with the advice that end users should not interrupt Camel's own
> threads. The case here is different. {{ConsumerTemplate.receive()}} and
> {{PollingConsumer.receive()}} run on the caller's own thread, which the
> application may legitimately interrupt or cancel. Camel itself also
> interrupts route threads during a forced shutdown. A blocking {{receive()}}
> that is interrupted should return, not spin.
> A thread in {{receive()}} gets interrupted when, for example:
> * a task doing {{consumerTemplate.receive(uri)}} is cancelled with
> {{Future.cancel(true)}}, or its executor is shut down with {{shutdownNow()}};
> * the thread pool of a route that waits in {{pollEnrich}} (default timeout
> -1) is shut down with {{shutdownNow()}}, which Camel does on a forced
> shutdown (for example the Threads EIP pool in
> {{ThreadsProcessor.doShutdown}}, or {{BaseExecutorServiceManager.doShutdown}}
> after its await timeout).
> Affected: 4.4.0 and later (4.4.x, 4.8.x, 4.14.x, 4.18.x, main).
> *Reproduction* (4.23.0-SNAPSHOT):
> {noformat}
> thread A: consumerTemplate.receive("direct:idle") -> waiting in
> EventDrivenPollingConsumer.receive:141
> A.interrupt()
> 2 s later: A alive=true state=RUNNABLE, CPU time used by A in those 2 s =
> 1979 ms
> 200 stack samples of A: EventDrivenPollingConsumer.receive:141 /
> handleInterruptedException:237 / LoggingExceptionHandler
> with log4j at WARN: 603,114 lines "WARN EventDrivenPollingConsumer - Caused
> by: [java.lang.InterruptedException - null]"
> in about 3 s (the log file reached 544 MB)
> {noformat}
> With the fix below {{receive()}} returns null 591 ms after the interrupt and
> the thread ends.
> TLA+: the same model with interrupts violates {{ReceiveEndsAfterInterrupt}}
> ({{pc_shared_interrupt_live}}). The lasso is Interrupt -> RIntr -> RLoop ->
> RAcq -> RIntr ..., and it holds even with a message in the queue. The fix
> variant ({{pc_fix_interrupt}}) satisfies it.
> *Proposed fix:* on {{InterruptedException}} in {{receive()}} /
> {{receive(timeout)}}, restore the interrupt flag and return null (leave the
> loop). Do not call {{take()}} again. Optionally log once at DEBUG, like
> {{process()}} does for an interrupted put.
> _Filed with Claude Code on behalf of allthingssecurity._
--
This message was sent by Atlassian Jira
(v8.20.10#820010)