This is an automated email from the ASF dual-hosted git repository.

davsclaus pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel.git


The following commit(s) were added to refs/heads/main by this push:
     new 45034f355d1c CAMEL-23937: Add Camel-managed lock renewal for Azure 
Service Bus async routes
45034f355d1c is described below

commit 45034f355d1c29e4d208fa31b9e285c6948551b5
Author: Claus Ibsen <[email protected]>
AuthorDate: Wed Jul 8 22:29:17 2026 +0200

    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 <[email protected]>
---
 .../azure/servicebus/ServiceBusConsumer.java       | 131 ++++++++++++++++++++
 .../servicebus/client/ServiceBusClientFactory.java |  28 +++++
 .../azure/servicebus/ServiceBusConsumerTest.java   | 133 +++++++++++++++++++++
 .../ROOT/pages/camel-4x-upgrade-guide-4_22.adoc    |  18 +++
 4 files changed, 310 insertions(+)

diff --git 
a/components/camel-azure/camel-azure-servicebus/src/main/java/org/apache/camel/component/azure/servicebus/ServiceBusConsumer.java
 
b/components/camel-azure/camel-azure-servicebus/src/main/java/org/apache/camel/component/azure/servicebus/ServiceBusConsumer.java
index c4b153288f5a..ffe1c1af1c83 100644
--- 
a/components/camel-azure/camel-azure-servicebus/src/main/java/org/apache/camel/component/azure/servicebus/ServiceBusConsumer.java
+++ 
b/components/camel-azure/camel-azure-servicebus/src/main/java/org/apache/camel/component/azure/servicebus/ServiceBusConsumer.java
@@ -16,8 +16,13 @@
  */
 package org.apache.camel.component.azure.servicebus;
 
+import java.time.Duration;
+import java.time.Instant;
+import java.time.OffsetDateTime;
 import java.util.Arrays;
 import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.atomic.AtomicInteger;
 import java.util.stream.Collectors;
 
@@ -25,6 +30,7 @@ import com.azure.messaging.servicebus.ServiceBusErrorContext;
 import com.azure.messaging.servicebus.ServiceBusProcessorClient;
 import com.azure.messaging.servicebus.ServiceBusReceivedMessage;
 import com.azure.messaging.servicebus.ServiceBusReceivedMessageContext;
+import com.azure.messaging.servicebus.ServiceBusReceiverAsyncClient;
 import com.azure.messaging.servicebus.models.DeadLetterOptions;
 import com.azure.messaging.servicebus.models.ServiceBusReceiveMode;
 import com.azure.messaging.servicebus.models.SubQueue;
@@ -34,8 +40,10 @@ import org.apache.camel.Message;
 import org.apache.camel.Processor;
 import org.apache.camel.ShutdownRunningTask;
 import org.apache.camel.spi.HeaderFilterStrategy;
+import org.apache.camel.spi.PeriodTaskScheduler;
 import org.apache.camel.spi.ShutdownAware;
 import org.apache.camel.support.DefaultConsumer;
+import org.apache.camel.support.PluginHelper;
 import org.apache.camel.support.SynchronizationAdapter;
 import org.apache.camel.util.ObjectHelper;
 import org.slf4j.Logger;
@@ -44,7 +52,11 @@ import org.slf4j.LoggerFactory;
 public class ServiceBusConsumer extends DefaultConsumer implements 
ShutdownAware {
 
     private static final Logger LOG = 
LoggerFactory.getLogger(ServiceBusConsumer.class);
+    private static final int LOCK_RENEW_INTERVAL_SECONDS = 10;
+
     private ServiceBusProcessorClient client;
+    private ServiceBusReceiverAsyncClient renewalClient;
+    private LockRenewer lockRenewer;
     private final AtomicInteger pendingExchanges = new AtomicInteger();
 
     public ServiceBusConsumer(final ServiceBusEndpoint endpoint, final 
Processor processor) {
@@ -76,6 +88,23 @@ public class ServiceBusConsumer extends DefaultConsumer 
implements ShutdownAware
         }
 
         client.start();
+
+        // set up Camel-managed lock renewal for PEEK_LOCK mode
+        // the Azure SDK's built-in lock renewal is tied to the processMessage 
callback duration,
+        // which returns immediately for async routes, making 
maxAutoLockRenewDuration ineffective
+        if (getConfiguration().getProcessorClient() == null
+                && getConfiguration().getServiceBusReceiveMode() == 
ServiceBusReceiveMode.PEEK_LOCK
+                && getConfiguration().getMaxAutoLockRenewDuration() > 0
+                && !getConfiguration().isSessionEnabled()) {
+            renewalClient = getEndpoint().getServiceBusClientFactory()
+                    .createServiceBusReceiverAsyncClient(getConfiguration());
+
+            long maxRenewMs = getConfiguration().getMaxAutoLockRenewDuration();
+            lockRenewer = new LockRenewer(renewalClient, 
Duration.ofMillis(maxRenewMs));
+
+            PeriodTaskScheduler scheduler = 
PluginHelper.getPeriodTaskScheduler(getEndpoint().getCamelContext());
+            scheduler.schedulePeriodTask(lockRenewer, 
LOCK_RENEW_INTERVAL_SECONDS * 1000L);
+        }
     }
 
     private void processMessage(ServiceBusReceivedMessageContext 
messageContext) {
@@ -85,6 +114,10 @@ public class ServiceBusConsumer extends DefaultConsumer 
implements ShutdownAware
         final ConsumerOnCompletion onCompletion = new 
ConsumerOnCompletion(messageContext);
         // add exchange callback
         exchange.getExchangeExtension().addOnCompletion(onCompletion);
+        // track for Camel-managed lock renewal
+        if (lockRenewer != null) {
+            lockRenewer.add(exchange, message);
+        }
         // use default consumer callback
         AsyncCallback cb = defaultConsumerCallback(exchange, true);
         getAsyncProcessor().process(exchange, cb);
@@ -102,6 +135,14 @@ public class ServiceBusConsumer extends DefaultConsumer 
implements ShutdownAware
 
     @Override
     protected void doStop() throws Exception {
+        if (lockRenewer != null) {
+            lockRenewer.cancel();
+            lockRenewer = null;
+        }
+        if (renewalClient != null) {
+            renewalClient.close();
+            renewalClient = null;
+        }
         if (client != null) {
             // stop accepting new messages but keep the connection open
             // so that in-flight exchanges can still complete/abandon messages
@@ -114,6 +155,15 @@ public class ServiceBusConsumer extends DefaultConsumer 
implements ShutdownAware
 
     @Override
     protected void doShutdown() throws Exception {
+        // defensive cleanup in case doStop() was not called
+        if (lockRenewer != null) {
+            lockRenewer.cancel();
+            lockRenewer = null;
+        }
+        if (renewalClient != null) {
+            renewalClient.close();
+            renewalClient = null;
+        }
         if (client != null) {
             // close the client after all in-flight exchanges have completed
             client.close();
@@ -198,6 +248,87 @@ public class ServiceBusConsumer extends DefaultConsumer 
implements ShutdownAware
         return exchange;
     }
 
+    private class LockRenewer implements Runnable {
+
+        private final ServiceBusReceiverAsyncClient client;
+        private final Duration maxRenewDuration;
+        private final AtomicBoolean run = new AtomicBoolean(true);
+        private final Map<String, LockRenewerEntry> entries = new 
ConcurrentHashMap<>();
+
+        LockRenewer(ServiceBusReceiverAsyncClient client, Duration 
maxRenewDuration) {
+            this.client = client;
+            this.maxRenewDuration = maxRenewDuration;
+        }
+
+        public void add(Exchange exchange, ServiceBusReceivedMessage message) {
+            exchange.getExchangeExtension().addOnCompletion(new 
SynchronizationAdapter() {
+                @Override
+                public void onComplete(Exchange exchange) {
+                    remove(exchange);
+                }
+
+                @Override
+                public void onFailure(Exchange exchange) {
+                    remove(exchange);
+                }
+
+                private void remove(Exchange exchange) {
+                    LOG.trace("Removing exchangeId {} from the LockRenewer, 
processing done", exchange.getExchangeId());
+                    entries.remove(exchange.getExchangeId());
+                }
+            });
+
+            entries.put(exchange.getExchangeId(),
+                    new LockRenewerEntry(message, message.getLockedUntil(), 
Instant.now()));
+        }
+
+        public void cancel() {
+            run.set(false);
+        }
+
+        @Override
+        public void run() {
+            if (!run.get()) {
+                return;
+            }
+
+            Instant now = Instant.now();
+            for (Map.Entry<String, LockRenewerEntry> mapEntry : 
entries.entrySet()) {
+                String exchangeId = mapEntry.getKey();
+                LockRenewerEntry entry = mapEntry.getValue();
+
+                // skip if max renewal duration exceeded
+                Duration elapsed = Duration.between(entry.startTime, now);
+                if (elapsed.compareTo(maxRenewDuration) >= 0) {
+                    LOG.debug("Max lock renewal duration exceeded for 
exchangeId {}, stopping renewal", exchangeId);
+                    entries.remove(exchangeId);
+                    continue;
+                }
+
+                // renew if lock is approaching expiry
+                Instant lockExpiry = entry.lockedUntil.toInstant();
+                if 
(now.plusSeconds(LOCK_RENEW_INTERVAL_SECONDS).isAfter(lockExpiry)) {
+                    client.renewMessageLock(entry.message)
+                            .subscribe(
+                                    newLockedUntil -> {
+                                        LOG.trace("Renewed lock for exchangeId 
{}, new expiry: {}", exchangeId,
+                                                newLockedUntil);
+                                        entries.computeIfPresent(exchangeId,
+                                                (k, e) -> new 
LockRenewerEntry(e.message, newLockedUntil, e.startTime));
+                                    },
+                                    error -> {
+                                        LOG.warn("Failed to renew lock for 
exchangeId {}: {}", exchangeId,
+                                                error.getMessage());
+                                        entries.remove(exchangeId);
+                                    });
+                }
+            }
+        }
+
+        private record LockRenewerEntry(ServiceBusReceivedMessage message, 
OffsetDateTime lockedUntil, Instant startTime) {
+        }
+    }
+
     private class ConsumerOnCompletion extends SynchronizationAdapter {
         private final ServiceBusReceivedMessageContext messageContext;
 
diff --git 
a/components/camel-azure/camel-azure-servicebus/src/main/java/org/apache/camel/component/azure/servicebus/client/ServiceBusClientFactory.java
 
b/components/camel-azure/camel-azure-servicebus/src/main/java/org/apache/camel/component/azure/servicebus/client/ServiceBusClientFactory.java
index 84070214d6ce..91ea8ab77d41 100644
--- 
a/components/camel-azure/camel-azure-servicebus/src/main/java/org/apache/camel/component/azure/servicebus/client/ServiceBusClientFactory.java
+++ 
b/components/camel-azure/camel-azure-servicebus/src/main/java/org/apache/camel/component/azure/servicebus/client/ServiceBusClientFactory.java
@@ -97,11 +97,39 @@ public final class ServiceBusClientFactory {
         return processorClientBuilder;
     }
 
+    private static ServiceBusClientBuilder.ServiceBusReceiverClientBuilder 
createBaseServiceBusReceiverClient(
+            final ServiceBusClientBuilder busClientBuilder, final 
ServiceBusConfiguration configuration) {
+        final ServiceBusClientBuilder.ServiceBusReceiverClientBuilder 
receiverClientBuilder = busClientBuilder.receiver();
+
+        receiverClientBuilder.disableAutoComplete();
+
+        switch (configuration.getServiceBusType()) {
+            case queue -> 
receiverClientBuilder.queueName(configuration.getTopicOrQueueName());
+            case topic -> 
receiverClientBuilder.topicName(configuration.getTopicOrQueueName());
+        }
+
+        return receiverClientBuilder;
+    }
+
     public ServiceBusSenderClient createServiceBusSenderClient(final 
ServiceBusConfiguration configuration) {
         return 
createBaseServiceBusSenderClient(createBaseServiceBusClient(configuration), 
configuration)
                 .buildClient();
     }
 
+    public ServiceBusReceiverAsyncClient 
createServiceBusReceiverAsyncClient(final ServiceBusConfiguration 
configuration) {
+        ServiceBusClientBuilder.ServiceBusReceiverClientBuilder clientBuilder
+                = 
createBaseServiceBusReceiverClient(createBaseServiceBusClient(configuration), 
configuration);
+
+        clientBuilder
+                .subscriptionName(configuration.getSubscriptionName())
+                .receiveMode(configuration.getServiceBusReceiveMode())
+                .maxAutoLockRenewDuration(Duration.ZERO)
+                .prefetchCount(configuration.getPrefetchCount())
+                .subQueue(configuration.getSubQueue());
+
+        return clientBuilder.buildAsyncClient();
+    }
+
     public ServiceBusProcessorClient createServiceBusProcessorClient(
             ServiceBusConfiguration configuration, 
Consumer<ServiceBusReceivedMessageContext> processMessage,
             Consumer<ServiceBusErrorContext> processError) {
diff --git 
a/components/camel-azure/camel-azure-servicebus/src/test/java/org/apache/camel/component/azure/servicebus/ServiceBusConsumerTest.java
 
b/components/camel-azure/camel-azure-servicebus/src/test/java/org/apache/camel/component/azure/servicebus/ServiceBusConsumerTest.java
index 0965859c715f..7153a3325c1f 100644
--- 
a/components/camel-azure/camel-azure-servicebus/src/test/java/org/apache/camel/component/azure/servicebus/ServiceBusConsumerTest.java
+++ 
b/components/camel-azure/camel-azure-servicebus/src/test/java/org/apache/camel/component/azure/servicebus/ServiceBusConsumerTest.java
@@ -34,7 +34,9 @@ import 
org.apache.camel.component.azure.servicebus.client.ServiceBusClientFactor
 import org.apache.camel.spi.ExceptionHandler;
 import org.apache.camel.spi.ExchangeFactory;
 import org.apache.camel.spi.HeaderFilterStrategy;
+import org.apache.camel.spi.PeriodTaskScheduler;
 import org.apache.camel.spi.Synchronization;
+import org.apache.camel.spi.UuidGenerator;
 import org.apache.camel.support.DefaultExchange;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
@@ -44,6 +46,7 @@ import org.mockito.ArgumentCaptor;
 
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyLong;
 import static org.mockito.Mockito.*;
 
 public class ServiceBusConsumerTest {
@@ -87,6 +90,9 @@ public class ServiceBusConsumerTest {
     private final ExchangeFactory ef = mock();
     private final HeaderFilterStrategy headerFilterStrategy = mock();
     private final ExceptionHandler exceptionHandler = mock();
+    private final PeriodTaskScheduler periodTaskScheduler = mock();
+    private final UuidGenerator uuidGenerator = mock();
+    private final ServiceBusReceiverAsyncClient renewalClient = mock();
     private final ArgumentCaptor<Consumer<ServiceBusReceivedMessageContext>> 
processMessageCaptor = ArgumentCaptor.captor();
     private final ArgumentCaptor<Consumer<ServiceBusErrorContext>> 
processErrorCaptor = ArgumentCaptor.captor();
     private final ArgumentCaptor<Exchange> exchangeCaptor = 
ArgumentCaptor.captor();
@@ -110,6 +116,10 @@ public class ServiceBusConsumerTest {
                 .thenReturn(client);
         when(processor.process(exchangeCaptor.capture(), 
asyncCallbackCaptor.capture())).thenReturn(true);
         
when(configuration.getHeaderFilterStrategy()).thenReturn(headerFilterStrategy);
+        
when(ecc.getContextPlugin(PeriodTaskScheduler.class)).thenReturn(periodTaskScheduler);
+        when(context.getUuidGenerator()).thenReturn(uuidGenerator);
+        
when(uuidGenerator.generateExchangeUuid()).thenReturn("test-exchange-id");
+        
when(clientFactory.createServiceBusReceiverAsyncClient(any())).thenReturn(renewalClient);
     }
 
     @Test
@@ -507,6 +517,129 @@ public class ServiceBusConsumerTest {
         }
     }
 
+    @Test
+    void lockRenewerCreatedForPeekLockMode() throws Exception {
+        
when(configuration.getServiceBusReceiveMode()).thenReturn(ServiceBusReceiveMode.PEEK_LOCK);
+        when(configuration.getMaxAutoLockRenewDuration()).thenReturn(300000L);
+        try (ServiceBusConsumer consumer = new ServiceBusConsumer(endpoint, 
processor)) {
+            consumer.doStart();
+            verify(clientFactory).createServiceBusReceiverAsyncClient(any());
+            verify(periodTaskScheduler).schedulePeriodTask(any(), anyLong());
+        }
+    }
+
+    @Test
+    void lockRenewerNotCreatedForReceiveAndDeleteMode() throws Exception {
+        
when(configuration.getServiceBusReceiveMode()).thenReturn(ServiceBusReceiveMode.RECEIVE_AND_DELETE);
+        when(configuration.getMaxAutoLockRenewDuration()).thenReturn(300000L);
+        try (ServiceBusConsumer consumer = new ServiceBusConsumer(endpoint, 
processor)) {
+            consumer.doStart();
+            verify(clientFactory, 
never()).createServiceBusReceiverAsyncClient(any());
+        }
+    }
+
+    @Test
+    void lockRenewerNotCreatedWhenMaxAutoLockRenewDurationIsZero() throws 
Exception {
+        
when(configuration.getServiceBusReceiveMode()).thenReturn(ServiceBusReceiveMode.PEEK_LOCK);
+        when(configuration.getMaxAutoLockRenewDuration()).thenReturn(0L);
+        try (ServiceBusConsumer consumer = new ServiceBusConsumer(endpoint, 
processor)) {
+            consumer.doStart();
+            verify(clientFactory, 
never()).createServiceBusReceiverAsyncClient(any());
+        }
+    }
+
+    @Test
+    void lockRenewerNotCreatedForSessionEnabledConsumer() throws Exception {
+        when(configuration.isSessionEnabled()).thenReturn(true);
+        
when(configuration.getServiceBusReceiveMode()).thenReturn(ServiceBusReceiveMode.PEEK_LOCK);
+        when(configuration.getMaxAutoLockRenewDuration()).thenReturn(300000L);
+        try (ServiceBusConsumer consumer = new ServiceBusConsumer(endpoint, 
processor)) {
+            consumer.doStart();
+            verify(clientFactory, 
never()).createServiceBusReceiverAsyncClient(any());
+        }
+    }
+
+    @Test
+    void lockRenewerNotCreatedWhenCustomProcessorClientProvided() throws 
Exception {
+        ServiceBusProcessorClient customClient = mock();
+        when(configuration.getProcessorClient()).thenReturn(customClient);
+        
when(configuration.getServiceBusReceiveMode()).thenReturn(ServiceBusReceiveMode.PEEK_LOCK);
+        when(configuration.getMaxAutoLockRenewDuration()).thenReturn(300000L);
+        try (ServiceBusConsumer consumer = new ServiceBusConsumer(endpoint, 
processor)) {
+            consumer.doStart();
+            verify(clientFactory, 
never()).createServiceBusReceiverAsyncClient(any());
+        }
+    }
+
+    @Test
+    void lockRenewerTracksAndRemovesExchanges() throws Exception {
+        
when(configuration.getServiceBusReceiveMode()).thenReturn(ServiceBusReceiveMode.PEEK_LOCK);
+        when(configuration.getMaxAutoLockRenewDuration()).thenReturn(300000L);
+        when(messageContext.getMessage()).thenReturn(message);
+        // lock expiring soon so the renewer would attempt renewal
+        
when(message.getLockedUntil()).thenReturn(OffsetDateTime.now().plusSeconds(5));
+        try (ServiceBusConsumer consumer = new ServiceBusConsumer(endpoint, 
processor)) {
+            consumer.doStart();
+
+            // capture the lock renewer task scheduled with PeriodTaskScheduler
+            ArgumentCaptor<Runnable> taskCaptor = ArgumentCaptor.captor();
+            
verify(periodTaskScheduler).schedulePeriodTask(taskCaptor.capture(), anyLong());
+            Runnable lockRenewerTask = taskCaptor.getValue();
+
+            processMessageCaptor.getValue().accept(messageContext);
+
+            // complete the exchange — should remove from lock renewer tracking
+            Exchange exchange = exchangeCaptor.getValue();
+            for (Synchronization sync : 
exchange.getExchangeExtension().handoverCompletions()) {
+                sync.onComplete(exchange);
+            }
+
+            // run the lock renewer — it should NOT attempt renewal for the 
completed exchange
+            lockRenewerTask.run();
+            verify(renewalClient, 
never()).renewMessageLock(any(ServiceBusReceivedMessage.class));
+        }
+    }
+
+    @Test
+    void doStopCleansUpLockRenewer() throws Exception {
+        
when(configuration.getServiceBusReceiveMode()).thenReturn(ServiceBusReceiveMode.PEEK_LOCK);
+        when(configuration.getMaxAutoLockRenewDuration()).thenReturn(300000L);
+        ServiceBusConsumer consumer = new ServiceBusConsumer(endpoint, 
processor);
+        consumer.doStart();
+
+        verify(clientFactory).createServiceBusReceiverAsyncClient(any());
+
+        consumer.doStop();
+
+        verify(renewalClient).close();
+        verify(client).stop();
+        verify(client, never()).close();
+    }
+
+    @Test
+    void stopStartCycleRecreatesLockRenewer() throws Exception {
+        
when(configuration.getServiceBusReceiveMode()).thenReturn(ServiceBusReceiveMode.PEEK_LOCK);
+        when(configuration.getMaxAutoLockRenewDuration()).thenReturn(300000L);
+        ServiceBusConsumer consumer = new ServiceBusConsumer(endpoint, 
processor);
+        consumer.doStart();
+
+        verify(clientFactory, 
times(1)).createServiceBusReceiverAsyncClient(any());
+
+        consumer.doStop();
+        verify(renewalClient).close();
+
+        // second start should create a fresh renewal client
+        ServiceBusReceiverAsyncClient renewalClient2 = mock();
+        
when(clientFactory.createServiceBusReceiverAsyncClient(any())).thenReturn(renewalClient2);
+        consumer.doStart();
+
+        verify(clientFactory, 
times(2)).createServiceBusReceiverAsyncClient(any());
+        verify(periodTaskScheduler, times(2)).schedulePeriodTask(any(), 
anyLong());
+
+        consumer.doShutdown();
+        verify(renewalClient2).close();
+    }
+
     @Test
     void customProcessorClient() throws Exception {
         ServiceBusProcessorClient customClient = mock();
diff --git 
a/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_22.adoc 
b/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_22.adoc
index 02f1788a73b9..d6a7b9e751b7 100644
--- a/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_22.adoc
+++ b/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_22.adoc
@@ -69,6 +69,24 @@ to the true average throughput rather than oscillating 
between zero and spike va
 If you have tooling that consumes the JMX throughput value and expects the old 
instantaneous
 behavior, be aware that the reported value will now ramp up and decay 
gradually.
 
+=== camel-azure-servicebus - Camel-managed message lock renewal
+
+When consuming from Azure Service Bus in `PEEK_LOCK` mode with 
`maxAutoLockRenewDuration > 0`, Camel now
+actively renews message locks using a dedicated 
`ServiceBusReceiverAsyncClient` and Camel's internal
+`PeriodTaskScheduler`. This addresses a limitation where the Azure SDK's 
built-in lock renewal is tied
+to the `processMessage` callback duration, which returns immediately for 
asynchronous Camel routes —
+causing long-running exchanges to silently lose their message locks.
+
+The new behavior activates automatically when all of the following are true:
+
+* No custom `processorClient` is provided
+* Receive mode is `PEEK_LOCK`
+* `maxAutoLockRenewDuration > 0`
+* Session mode is disabled
+
+No configuration changes are required. The existing `maxAutoLockRenewDuration` 
option controls how long
+Camel will continue renewing a message's lock.
+
 === camel-debezium
 
 The `camel-debezium` component has upgraded from Debezium 3.5.2 to 3.6.0.

Reply via email to