[
https://issues.apache.org/jira/browse/CAMEL-25701?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
]
Work on CAMEL-25701 started by shashank.
----------------------------------------
> camel-azure-servicebus - the Camel lock renewer waits for its next run when a
> message lock expires within 10 seconds, but runs only every 10 to 11 seconds,
> so locks of long-running exchanges are lost and the messages are delivered
> again
> --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
>
> Key: CAMEL-25701
> URL: https://issues.apache.org/jira/browse/CAMEL-25701
> Project: Camel
> Issue Type: Bug
> Components: camel-azure-servicebus
> Reporter: shashank
> Assignee: shashank
> Priority: Major
>
> Since CAMEL-23937 the Service Bus consumer renews the message locks itself in
> {{PEEK_LOCK}} mode (the default, with the default
> {{maxAutoLockRenewDuration}} of 5 minutes, sessions disabled): the SDK's own
> renewal stops when Camel's callback returns, which is immediately for an
> asynchronous route. {{ServiceBusConsumer}} schedules a {{LockRenewer}} with
> {{PeriodTaskScheduler.schedulePeriodTask(lockRenewer, 10000)}}, and the
> renewer renews a lock when {{now + 10 seconds}} is after the lock's expiry
> ({{LOCK_RENEW_INTERVAL_SECONDS}}, line 347 on main d46d51c24550).
> The period task scheduler is driven by a 1-second timer
> ({{TimerListenerManager}}), and {{PeriodicTaskWrapper}} runs the task when
> more than 10000 ms have passed since the last run, so two runs are 10 or 11
> seconds apart. The window in which the renewer acts is 10 seconds long. When
> the lock expires between 10 and 11 seconds after a run, that run leaves it
> alone ("not yet within 10 seconds") and the next run comes after the lock has
> expired, or so close to the expiry that the renewal request arrives too late.
> The renewal then fails with a lost lock, the entry is dropped (WARN "Failed
> to renew lock"), Service Bus delivers the message again to this or another
> consumer while the first exchange is still being processed, and the final
> {{complete()}} of the first exchange fails.
> A small exhaustive model of the timing (every sequence of 6 run gaps of 10 or
> 11 seconds, lock expiry at every 100 ms phase) loses the lock in 6.0% of the
> cases with the current 10-second margin (11% when the runs come every 11
> seconds, 1% when they come exactly every 10 seconds: an expiry that falls on
> a run), and in none with a margin of two intervals. Which gap the scheduler
> produces depends on sub-millisecond timer jitter. An exchange that is
> processed for 5 minutes with the default 60-second lock duration crosses
> about 5 lock periods, so with 6% per period roughly one such exchange in four
> is delivered twice.
> Trigger: default options ({{PEEK_LOCK}}, {{maxAutoLockRenewDuration}} 5
> minutes), no sessions, an asynchronous route (the case CAMEL-23937 is about),
> and an exchange that takes longer than the lock duration of the queue or
> subscription minus 10 seconds.
> h3. Reproduction
> New test in {{ServiceBusConsumerTest}} (Mockito, no Service Bus): the renewer
> is captured from the scheduler together with its period; a message whose lock
> expires 2 seconds after the earliest possible next run ({{period + 2 s}}) is
> tracked, and the renewer runs once. Waiting for the next run would leave at
> most 2 seconds, or none. On main the renewer does not renew:
> {noformat}
> Wanted but not invoked:
> renewalClient.renewMessageLock(message);
> {noformat}
> A second new test (a lock that expires in 60 seconds is not renewed) passes
> on main and with the fix; it guards against renewing too early.
> h3. Proposed fix
> Renew when the lock expires within two intervals (20 seconds) instead of one:
> every lock is then renewed by a run that comes at least about 9 seconds
> before it expires. A lock is still renewed about once per lock duration
> (somewhat earlier than before); with a lock duration of 20 seconds or less it
> is renewed at every run. No option changes.
> camel-azure-servicebus unit tests with the fix: 79 run, 0 failures, 8 skipped
> (integration tests). Not run: a real namespace.
> How it was found: comparing the lock renewal timing with the visibility
> extender of camel-aws2-sqs (which renews when the deadline falls before the
> next expected run) during a sweep of acknowledge and lock timing; the test
> and the timing model confirmed it.
> Affected: main (tested). camel-4.23.x and camel-4.22.x (line 336) and
> camel-4.18.x (line 310) have the same renewer (read, not run).
> Duplicate check (2026-10-16): JIRA text "renewMessageLock" / "lock renewal"
> with component camel-azure-servicebus (CAMEL-23937, CAMEL-23938 session lock
> renewal, resolved Not A Problem, its PR #25001 closed unmerged; none about
> the margin); GitHub pull requests "servicebus lock renew" (#24511 merged,
> #25001 closed unmerged, sessions).
> _Filed with Claude Code on behalf of allthingssecurity._
--
This message was sent by Atlassian Jira
(v8.20.10#820010)