CAMEL-23937: Add Camel-managed lock renewal for Azure Service Bus async routes#24511
Conversation
…nc routes The Azure SDK's built-in lock renewal is tied to the processMessage callback duration, which returns immediately for async Camel routes. This makes maxAutoLockRenewDuration ineffective, causing silent message-lock expiry, duplicate delivery, and data loss. This adds a LockRenewer that uses a ServiceBusReceiverAsyncClient to periodically renew message locks for in-flight exchanges. It integrates with Camel's PeriodTaskScheduler for operational visibility and uses non-blocking Reactor Mono subscriptions for concurrent renewals. Session-enabled consumers are excluded (follow-up in CAMEL-23938). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: Claus Ibsen <claus.ibsen@gmail.com>
|
🌟 Thank you for your contribution to the Apache Camel project! 🌟 🐫 Apache Camel Committers, please review the following items:
|
|
🧪 CI tested the following changed modules:
🔬 Scalpel shadow comparison — Scalpel: 10 tested, 28 compile-only — current: 9 all testedMaveniverse Scalpel detected 38 affected modules (current approach: 9).
|
oscerd
left a comment
There was a problem hiding this comment.
Nice feature, Claus — plugging the dead SDK lock-renewal for async routes is a real gap, and the test coverage (7 tests, no Thread.sleep) is good. One concern I would like to raise before merge:
Renewal resources have an asymmetric lifecycle across route restarts. renewalClient and lockRenewer are created in doStart() and scheduled via PluginHelper.getPeriodTaskScheduler(...).schedulePeriodTask(...), but they are only torn down in doShutdown() — doStop() is left untouched. A route stop/start cycle (suspend/resume, dynamic route control) invokes doStop() → doStart() without doShutdown(), so on restart:
doStart()overwritesrenewalClientwith a new async AMQP client without closing the previous one → connection leak; and- it calls
schedulePeriodTask(...)again.PeriodTaskScheduler(core SPI) exposes onlyschedulePeriodTask/scheduledTask— there is no unschedule — andlockRenewer.cancel()only flips an internalrun=falseguard, it does not remove the registered task. So renewals accumulate for the CamelContext lifetime.
The sibling Sqs2Consumer.TimeoutExtender avoids this by owning its own ScheduledExecutorService and shutting it down in doStop(). Moving the renewer/client teardown to doStop() (and re-creating in doStart()) would make the lifecycle symmetric.
Minor:
- The new behavior (Camel now opens an extra async client and actively renews locks) is user-visible — worth a short note in
azure-servicebus-component.adoc/ the upgrade guide, even though it reuses the existingmaxAutoLockRenewDurationoption. lockRenewerTracksAndRemovesExchangesassertsgetPendingExchangesSize()(theConsumerOnCompletioncounter) rather than theLockRenewer's ownentriesmap, so it does not actually verify renewer tracking/removal.
If consumer restarts are considered out of scope here, feel free to treat the lifecycle point as a non-blocking note.
Reviewed with Claude Code on behalf of Andrea Cosentino. This review was generated by an AI agent and may contain inaccuracies; please verify all suggestions before applying.
- Fix lifecycle asymmetry: move lock renewer and renewal client cleanup to doStop() so route stop/start cycles don't leak AMQP connections - Keep defensive cleanup in doShutdown() for safety - Add test for stop/start cycle verifying resources are recreated - Improve lockRenewerTracksAndRemovesExchanges test to verify actual renewer behavior rather than just the pendingExchanges counter - Add upgrade guide note for the new lock renewal behavior Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: Claus Ibsen <claus.ibsen@gmail.com>
|
@oscerd Thanks for the thorough review! All three points addressed in de75e63: Lifecycle asymmetry (blocking): Moved lock renewer cancel + renewal client close into Documentation (suggestion): Added upgrade guide note in Test assertion (suggestion): Reworked Claude Code on behalf of davsclaus |
…or Azure Service Bus async routes (#24559) CAMEL-23937: Add Camel-managed lock renewal for Azure Service Bus async routes The Azure SDK's built-in lock renewal (maxAutoLockRenewDuration) is tied to the processMessage callback duration, which returns immediately for async Camel routes. This adds a LockRenewer that uses a ServiceBusReceiverAsyncClient to periodically renew message locks for in-flight exchanges in PEEK_LOCK mode. Integrates with Camel's PeriodTaskScheduler for operational visibility. Session-enabled consumers are excluded (follow-up in CAMEL-23938). Closes #24511 Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Summary
Claude Code on behalf of davsclaus
ServiceBusReceiverAsyncClientwith non-blocking ReactorMonosubscriptions for concurrent lock renewalsPeriodTaskSchedulerfor operational visibility (visible viacamel get internal-tasks)Problem
The Azure SDK's built-in lock renewal (
maxAutoLockRenewDuration) is tied to theprocessMessagecallback duration. For async Camel routes, this callback returns immediately — the SDK disposes its lock-renewal subscription, and long-running exchanges silently lose their message locks, causing duplicate delivery and data loss.Solution
A
LockRenewerinner class (modeled after SQSTimeoutExtender) tracks in-flight exchanges in aConcurrentHashMapand periodically renews their message locks viaServiceBusReceiverAsyncClient.renewMessageLock(). Lock renewal activates when:processorClientis providedPEEK_LOCKmaxAutoLockRenewDuration > 0Exchanges are automatically removed from tracking on completion/failure via
SynchronizationAdapter.Lock renewer resources (renewal client and scheduled task) are cleaned up in
doStop()so that route stop/start cycles do not leak AMQP connections. Defensive cleanup is also indoShutdown().Files changed
ServiceBusClientFactory.java— AddedcreateServiceBusReceiverAsyncClient()factory methodServiceBusConsumer.java— AddedLockRenewerinner class and lifecycle integrationServiceBusConsumerTest.java— Added 9 tests for lock renewal behavior including stop/start lifecyclecamel-4x-upgrade-guide-4_22.adoc— Documented the new lock renewal behaviorTest plan
mvn verify)🤖 Generated with Claude Code
Co-Authored-By: Claude Opus 4.6 noreply@anthropic.com