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

jamesnetherton 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 7ee5afcd2f86 CAMEL-22784: Use predictable scheduling for 
FileLockClusterService lock acquisition
7ee5afcd2f86 is described below

commit 7ee5afcd2f86c191d19c4abae2f2cd0112f97104
Author: James Netherton <[email protected]>
AuthorDate: Mon Jan 5 07:58:44 2026 +0000

    CAMEL-22784: Use predictable scheduling for FileLockClusterService lock 
acquisition
---
 .../catalog/beans/FileLockClusterService.json      |  2 +-
 .../apache/camel/bean/FileLockClusterService.json  |  2 +-
 .../file/cluster/FileLockClusterService.java       | 22 +++++--
 .../file/cluster/FileLockClusterView.java          | 71 +++++++++++++++-------
 ...FileLockClusterServiceAdvancedFailoverTest.java | 15 +++++
 .../FileLockClusterServiceBasicFailoverTest.java   | 65 +++++++++++++++++++-
 .../cluster/FileLockClusterServiceTestBase.java    | 13 +++-
 .../user-manual/modules/ROOT/pages/clustering.adoc |  4 +-
 8 files changed, 161 insertions(+), 33 deletions(-)

diff --git 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/beans/FileLockClusterService.json
 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/beans/FileLockClusterService.json
index 565e43eaa573..bf17eaf82202 100644
--- 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/beans/FileLockClusterService.json
+++ 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/beans/FileLockClusterService.json
@@ -10,7 +10,7 @@
     "groupId": "org.apache.camel",
     "artifactId": "camel-file",
     "version": "4.17.0-SNAPSHOT",
-    "properties": { "root": { "index": 0, "kind": "property", "displayName": 
"Root", "required": true, "type": "string", "javaType": "java.lang.String", 
"deprecated": false, "autowired": false, "secret": false, "description": "The 
root file path" }, "acquireLockDelay": { "index": 1, "kind": "property", 
"displayName": "Acquire Lock Delay", "required": false, "type": "integer", 
"javaType": "long", "deprecated": false, "autowired": false, "secret": false, 
"defaultValue": 1, "description": " [...]
+    "properties": { "root": { "index": 0, "kind": "property", "displayName": 
"Root", "required": true, "type": "string", "javaType": "java.lang.String", 
"deprecated": false, "autowired": false, "secret": false, "description": "The 
root file path" }, "acquireLockDelay": { "index": 1, "kind": "property", 
"displayName": "Acquire Lock Delay", "required": false, "type": "integer", 
"javaType": "long", "deprecated": false, "autowired": false, "secret": false, 
"defaultValue": 1, "description": " [...]
   }
 }
 
diff --git 
a/components/camel-file/src/generated/resources/META-INF/services/org/apache/camel/bean/FileLockClusterService.json
 
b/components/camel-file/src/generated/resources/META-INF/services/org/apache/camel/bean/FileLockClusterService.json
index 565e43eaa573..bf17eaf82202 100644
--- 
a/components/camel-file/src/generated/resources/META-INF/services/org/apache/camel/bean/FileLockClusterService.json
+++ 
b/components/camel-file/src/generated/resources/META-INF/services/org/apache/camel/bean/FileLockClusterService.json
@@ -10,7 +10,7 @@
     "groupId": "org.apache.camel",
     "artifactId": "camel-file",
     "version": "4.17.0-SNAPSHOT",
-    "properties": { "root": { "index": 0, "kind": "property", "displayName": 
"Root", "required": true, "type": "string", "javaType": "java.lang.String", 
"deprecated": false, "autowired": false, "secret": false, "description": "The 
root file path" }, "acquireLockDelay": { "index": 1, "kind": "property", 
"displayName": "Acquire Lock Delay", "required": false, "type": "integer", 
"javaType": "long", "deprecated": false, "autowired": false, "secret": false, 
"defaultValue": 1, "description": " [...]
+    "properties": { "root": { "index": 0, "kind": "property", "displayName": 
"Root", "required": true, "type": "string", "javaType": "java.lang.String", 
"deprecated": false, "autowired": false, "secret": false, "description": "The 
root file path" }, "acquireLockDelay": { "index": 1, "kind": "property", 
"displayName": "Acquire Lock Delay", "required": false, "type": "integer", 
"javaType": "long", "deprecated": false, "autowired": false, "secret": false, 
"defaultValue": 1, "description": " [...]
   }
 }
 
diff --git 
a/components/camel-file/src/main/java/org/apache/camel/component/file/cluster/FileLockClusterService.java
 
b/components/camel-file/src/main/java/org/apache/camel/component/file/cluster/FileLockClusterService.java
index 0d0eeb8dcb91..40415e75ceed 100644
--- 
a/components/camel-file/src/main/java/org/apache/camel/component/file/cluster/FileLockClusterService.java
+++ 
b/components/camel-file/src/main/java/org/apache/camel/component/file/cluster/FileLockClusterService.java
@@ -38,11 +38,16 @@ public class FileLockClusterService extends 
AbstractCamelClusterService<FileLock
 
     @Metadata(description = "The root file path", required = true)
     private String root;
-    @Metadata(description = "The time to wait before starting to try to 
acquire lock.", defaultValue = "1")
+    @Metadata(description = "The time to wait before starting to try to 
acquire the cluster lock. Note that if FileLockClusterService"
+                            + " determines no cluster members are running or 
cannot reliably determine the cluster state, the initial delay is"
+                            + " computed from the acquireLockInterval.",
+              defaultValue = "1")
     private long acquireLockDelay;
     @Metadata(description = "The time unit for the acquireLockDelay", 
defaultValue = "SECONDS")
     private TimeUnit acquireLockDelayUnit;
-    @Metadata(description = "The time to wait between attempts to try to 
acquire lock", defaultValue = "10")
+    @Metadata(description = "The time to wait between attempts to try to 
acquire the cluster lock evaluated using wall-clock time."
+                            + " All cluster members must use the same value so 
leadership checks and leader liveness detection remain consistent.",
+              defaultValue = "10")
     private long acquireLockInterval;
     @Metadata(description = "The time unit for the acquireLockInterval", 
defaultValue = "SECONDS")
     private TimeUnit acquireLockIntervalUnit;
@@ -97,9 +102,14 @@ public class FileLockClusterService extends 
AbstractCamelClusterService<FileLock
     }
 
     /**
-     * The time to wait before starting to try to acquire lock, default 1.
+     * The time to wait before starting to try to acquire the cluster lock. 
Note that if FileLockClusterService
+     * determines no cluster members are running or cannot reliably determine 
the cluster state, the initial delay is
+     * computed from the acquireLockInterval, default 1.
      */
     public void setAcquireLockDelay(long acquireLockDelay) {
+        if (acquireLockDelay <= 0) {
+            throw new IllegalArgumentException("acquireLockDelay must be 
greater than 0");
+        }
         this.acquireLockDelay = acquireLockDelay;
     }
 
@@ -124,9 +134,13 @@ public class FileLockClusterService extends 
AbstractCamelClusterService<FileLock
     }
 
     /**
-     * The time to wait between attempts to try to acquire lock, default 10.
+     * The time to wait between attempts to try to acquire the cluster lock 
evaluated using wall-clock time. All cluster
+     * members must use the same value so leadership checks and leader 
liveness detection remain consistent, default 10.
      */
     public void setAcquireLockInterval(long acquireLockInterval) {
+        if (acquireLockInterval <= 0) {
+            throw new IllegalArgumentException("acquireLockInterval must be 
greater than 0");
+        }
         this.acquireLockInterval = acquireLockInterval;
     }
 
diff --git 
a/components/camel-file/src/main/java/org/apache/camel/component/file/cluster/FileLockClusterView.java
 
b/components/camel-file/src/main/java/org/apache/camel/component/file/cluster/FileLockClusterView.java
index c7b5971728a3..4c24bb6ff2ac 100644
--- 
a/components/camel-file/src/main/java/org/apache/camel/component/file/cluster/FileLockClusterView.java
+++ 
b/components/camel-file/src/main/java/org/apache/camel/component/file/cluster/FileLockClusterView.java
@@ -30,7 +30,6 @@ import java.util.Objects;
 import java.util.Optional;
 import java.util.UUID;
 import java.util.concurrent.ExecutionException;
-import java.util.concurrent.ScheduledExecutorService;
 import java.util.concurrent.ScheduledFuture;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.TimeoutException;
@@ -104,7 +103,7 @@ public class FileLockClusterView extends 
AbstractCamelClusterView {
                 fireLeadershipChangedEvent((CamelClusterMember) null);
             }
 
-            // Attempt to pre-create cluster data files & directories. On 
failure, it will either be attempted by another cluster member or run again 
within the tryLock task loop
+            // Attempt to pre-create cluster data directories. On failure, it 
will either be attempted by another cluster member or run again within the 
tryLock task loop
             try {
                 if (!Files.exists(leaderLockPath.getParent())) {
                     Files.createDirectories(leaderLockPath.getParent());
@@ -112,22 +111,6 @@ public class FileLockClusterView extends 
AbstractCamelClusterView {
             } catch (IOException e) {
                 LOGGER.debug("Error creating directory {}", 
leaderLockPath.getParent(), e);
             }
-
-            try {
-                if (!Files.exists(leaderLockPath)) {
-                    Files.createFile(leaderLockPath);
-                }
-            } catch (IOException e) {
-                LOGGER.debug("Error creating cluster leader lock file {}", 
leaderLockPath, e);
-            }
-
-            try {
-                if (!Files.exists(leaderDataPath)) {
-                    Files.createFile(leaderDataPath);
-                }
-            } catch (IOException e) {
-                LOGGER.debug("Error creating cluster leader data file {}", 
leaderDataPath, e);
-            }
         } finally {
             // End critical section
             contextStartLock.unlock();
@@ -141,11 +124,7 @@ public class FileLockClusterView extends 
AbstractCamelClusterView {
 
         heartbeatTimeoutMultiplier = service.getHeartbeatTimeoutMultiplier();
 
-        ScheduledExecutorService executor = service.getExecutor();
-        task = executor.scheduleWithFixedDelay(this::tryLock,
-                TimeUnit.MILLISECONDS.convert(service.getAcquireLockDelay(), 
service.getAcquireLockDelayUnit()),
-                
TimeUnit.MILLISECONDS.convert(service.getAcquireLockInterval(), 
service.getAcquireLockIntervalUnit()),
-                TimeUnit.MILLISECONDS);
+        scheduleTryLock(true);
 
         localMember.setStatus(ClusterMemberStatus.STARTED);
     }
@@ -250,6 +229,10 @@ public class FileLockClusterView extends 
AbstractCamelClusterView {
                 LOGGER.debug("Reading cluster leader state from {}", 
leaderDataPath);
                 FileLockClusterLeaderInfo latestClusterLeaderInfo = 
readClusterLeaderInfo();
                 FileLockClusterLeaderInfo previousClusterLeaderInfo = 
clusterLeaderInfoRef.getAndSet(latestClusterLeaderInfo);
+
+                // Compare the cluster leader lock interval to our own and 
warn if not in sync
+                validateAcquireLockInterval(latestClusterLeaderInfo);
+
                 // Check if we can attempt to take cluster leadership
                 if (isLeaderStale(latestClusterLeaderInfo, 
previousClusterLeaderInfo)
                         || canReclaimLeadership(latestClusterLeaderInfo)) {
@@ -294,8 +277,50 @@ public class FileLockClusterView extends 
AbstractCamelClusterView {
                             reason);
                     closeLockFiles();
                 }
+                scheduleTryLock(false);
+            }
+        }
+    }
+
+    void validateAcquireLockInterval(FileLockClusterLeaderInfo 
clusterLeaderInfo) {
+        if (clusterLeaderInfo != null
+                && clusterLeaderInfo.getHeartbeatUpdateIntervalMilliseconds() 
!= acquireLockIntervalMilliseconds) {
+            LOGGER.warn(
+                    "This cluster member (cluster-member-id={}) 
acquireLockIntervalMilliseconds configuration {}ms does not match {}ms set on 
the cluster leader (cluster-member-id={}). This can lead to unpredictable 
behavior. Please ensure the configuration is set consistently for all cluster 
members.",
+                    localMember.getUuid(), acquireLockIntervalMilliseconds,
+                    clusterLeaderInfo.getHeartbeatUpdateIntervalMilliseconds(),
+                    clusterLeaderInfo.getId());
+        }
+    }
+
+    void scheduleTryLock(boolean isFirstRun) {
+        long offset = System.currentTimeMillis() % 
acquireLockIntervalMilliseconds;
+        long delay = acquireLockIntervalMilliseconds - offset;
+        if (delay <= 0) {
+            delay = acquireLockIntervalMilliseconds;
+        }
+
+        if (isFirstRun) {
+            // If it seems that other members are running, apply the user 
provided initial delay
+            if (Files.exists(leaderLockPath.getParent()) && 
Files.exists(leaderLockPath) && Files.exists(leaderDataPath)) {
+                FileLockClusterService service = 
getClusterService().unwrap(FileLockClusterService.class);
+                delay = 
TimeUnit.MILLISECONDS.convert(service.getAcquireLockDelay(), 
service.getAcquireLockDelayUnit());
+            }
+
+            if (delay > 30000) {
+                LOGGER.warn(
+                        "Initial acquire lock delay is high ({} ms). Consider 
reducing acquireLockIntervalMilliseconds or acquireLockDelay for faster leader 
acquisition.",
+                        delay);
             }
+
+            LOGGER.info("Waiting {}ms to attempt initial cluster leadership 
acquisition", delay);
         }
+
+        LOGGER.debug("Scheduling tryLock with delay {}ms", delay);
+
+        getClusterService().unwrap(FileLockClusterService.class)
+                .getExecutor()
+                .schedule(this::tryLock, delay, TimeUnit.MILLISECONDS);
     }
 
     boolean isLeaderStale(FileLockClusterLeaderInfo clusterLeaderInfo, 
FileLockClusterLeaderInfo previousClusterLeaderInfo) {
diff --git 
a/components/camel-master/src/test/java/org/apache/camel/component/file/cluster/FileLockClusterServiceAdvancedFailoverTest.java
 
b/components/camel-master/src/test/java/org/apache/camel/component/file/cluster/FileLockClusterServiceAdvancedFailoverTest.java
index 29c9a60536bf..11bae8215caf 100644
--- 
a/components/camel-master/src/test/java/org/apache/camel/component/file/cluster/FileLockClusterServiceAdvancedFailoverTest.java
+++ 
b/components/camel-master/src/test/java/org/apache/camel/component/file/cluster/FileLockClusterServiceAdvancedFailoverTest.java
@@ -55,6 +55,9 @@ class FileLockClusterServiceAdvancedFailoverTest extends 
FileLockClusterServiceT
 
             clusterLeader.start();
 
+            Awaitility.await().atMost(Duration.ofSeconds(30))
+                    .until(() -> 
getClusterView(clusterLeader).getLocalMember().isLeader());
+
             mockEndpoint.assertIsSatisfied();
 
             AtomicReference<String> leaderId = new AtomicReference<>();
@@ -120,6 +123,10 @@ class FileLockClusterServiceAdvancedFailoverTest extends 
FileLockClusterServiceT
             mockEndpointLeader.expectedMinimumMessageCount(1);
 
             clusterLeader.start();
+
+            Awaitility.await().atMost(Duration.ofSeconds(30))
+                    .until(() -> 
getClusterView(clusterLeader).getLocalMember().isLeader());
+
             clusterFollower.start();
 
             mockEndpointLeader.assertIsSatisfied();
@@ -198,6 +205,10 @@ class FileLockClusterServiceAdvancedFailoverTest extends 
FileLockClusterServiceT
             mockEndpointLeader.expectedMinimumMessageCount(1);
 
             clusterLeader.start();
+
+            Awaitility.await().atMost(Duration.ofSeconds(30))
+                    .until(() -> 
getClusterView(clusterLeader).getLocalMember().isLeader());
+
             clusterFollower.start();
 
             mockEndpointLeader.assertIsSatisfied();
@@ -276,6 +287,10 @@ class FileLockClusterServiceAdvancedFailoverTest extends 
FileLockClusterServiceT
             mockEndpointLeader.expectedMessageCount(5);
 
             clusterLeader.start();
+
+            Awaitility.await().atMost(Duration.ofSeconds(30))
+                    .until(() -> 
getClusterView(clusterLeader).getLocalMember().isLeader());
+
             clusterFollower.start();
 
             mockEndpointLeader.assertIsSatisfied();
diff --git 
a/components/camel-master/src/test/java/org/apache/camel/component/file/cluster/FileLockClusterServiceBasicFailoverTest.java
 
b/components/camel-master/src/test/java/org/apache/camel/component/file/cluster/FileLockClusterServiceBasicFailoverTest.java
index 5bb4da929715..8bce74e2c5c5 100644
--- 
a/components/camel-master/src/test/java/org/apache/camel/component/file/cluster/FileLockClusterServiceBasicFailoverTest.java
+++ 
b/components/camel-master/src/test/java/org/apache/camel/component/file/cluster/FileLockClusterServiceBasicFailoverTest.java
@@ -37,12 +37,17 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
 class FileLockClusterServiceBasicFailoverTest extends 
FileLockClusterServiceTestBase {
     @Test
     void singleClusterMemberLeaderElection() throws Exception {
+        ClusterConfig leaderConfig = new ClusterConfig();
+        leaderConfig.setAcquireLockInterval(10);
         try (CamelContext clusterLeader = createCamelContext()) {
             MockEndpoint mockEndpoint = 
clusterLeader.getEndpoint("mock:result", MockEndpoint.class);
             mockEndpoint.expectedMessageCount(5);
 
             clusterLeader.start();
 
+            Awaitility.await().atMost(Duration.ofSeconds(30))
+                    .until(() -> 
getClusterView(clusterLeader).getLocalMember().isLeader());
+
             mockEndpoint.assertIsSatisfied();
 
             Awaitility.await().atMost(Duration.ofSeconds(30)).untilAsserted(() 
-> {
@@ -63,10 +68,13 @@ class FileLockClusterServiceBasicFailoverTest extends 
FileLockClusterServiceTest
 
     @Test
     void multiClusterMemberLeaderElection() throws Exception {
-        CamelContext clusterLeader = createCamelContext();
+        ClusterConfig leaderConfig = new ClusterConfig();
+        leaderConfig.setAcquireLockInterval(10);
+        CamelContext clusterLeader = createCamelContext(leaderConfig);
 
         ClusterConfig followerConfig = new ClusterConfig();
         followerConfig.setAcquireLockDelay(2);
+        followerConfig.setAcquireLockInterval(10);
         CamelContext clusterFollower = createCamelContext(followerConfig);
 
         try {
@@ -74,6 +82,10 @@ class FileLockClusterServiceBasicFailoverTest extends 
FileLockClusterServiceTest
             mockEndpointClustered.expectedMessageCount(5);
 
             clusterLeader.start();
+
+            Awaitility.await().atMost(Duration.ofSeconds(30))
+                    .until(() -> 
getClusterView(clusterLeader).getLocalMember().isLeader());
+
             clusterFollower.start();
 
             mockEndpointClustered.assertIsSatisfied();
@@ -118,6 +130,10 @@ class FileLockClusterServiceBasicFailoverTest extends 
FileLockClusterServiceTest
             mockEndpointClustered.expectedMessageCount(5);
 
             clusterLeader.start();
+
+            Awaitility.await().atMost(Duration.ofSeconds(30))
+                    .until(() -> 
getClusterView(clusterLeader).getLocalMember().isLeader());
+
             clusterFollower.start();
 
             mockEndpointClustered.assertIsSatisfied();
@@ -174,6 +190,9 @@ class FileLockClusterServiceBasicFailoverTest extends 
FileLockClusterServiceTest
 
             clusterLeader.start();
 
+            Awaitility.await().atMost(Duration.ofSeconds(30))
+                    .until(() -> 
getClusterView(clusterLeader).getLocalMember().isLeader());
+
             mockEndpoint.assertIsSatisfied();
 
             AtomicReference<String> leaderId = new AtomicReference<>();
@@ -219,6 +238,50 @@ class FileLockClusterServiceBasicFailoverTest extends 
FileLockClusterServiceTest
         assertEquals(0, Files.size(dataFile));
     }
 
+    @Test
+    void negativeAcquireLockDelayThrowsException() {
+        ClusterConfig config = new ClusterConfig();
+        config.setAcquireLockDelay(-1);
+        assertThrows(IllegalArgumentException.class, () -> {
+            try (CamelContext camelContext = createCamelContext(config)) {
+                camelContext.start();
+            }
+        });
+    }
+
+    @Test
+    void zeroAcquireLockDelayThrowsException() {
+        ClusterConfig config = new ClusterConfig();
+        config.setAcquireLockDelay(0);
+        assertThrows(IllegalArgumentException.class, () -> {
+            try (CamelContext camelContext = createCamelContext(config)) {
+                camelContext.start();
+            }
+        });
+    }
+
+    @Test
+    void negativeAcquireLockIntervalThrowsException() {
+        ClusterConfig config = new ClusterConfig();
+        config.setAcquireLockInterval(-1);
+        assertThrows(IllegalArgumentException.class, () -> {
+            try (CamelContext camelContext = createCamelContext(config)) {
+                camelContext.start();
+            }
+        });
+    }
+
+    @Test
+    void zeroAcquireLockIntervalThrowsException() {
+        ClusterConfig config = new ClusterConfig();
+        config.setAcquireLockInterval(0);
+        assertThrows(IllegalArgumentException.class, () -> {
+            try (CamelContext camelContext = createCamelContext(config)) {
+                camelContext.start();
+            }
+        });
+    }
+
     @Test
     void negativeHeartbeatTimeoutMultiplierThrowsException() {
         ClusterConfig config = new ClusterConfig();
diff --git 
a/components/camel-master/src/test/java/org/apache/camel/component/file/cluster/FileLockClusterServiceTestBase.java
 
b/components/camel-master/src/test/java/org/apache/camel/component/file/cluster/FileLockClusterServiceTestBase.java
index b7f7bfbbde55..526ae16af716 100644
--- 
a/components/camel-master/src/test/java/org/apache/camel/component/file/cluster/FileLockClusterServiceTestBase.java
+++ 
b/components/camel-master/src/test/java/org/apache/camel/component/file/cluster/FileLockClusterServiceTestBase.java
@@ -24,6 +24,7 @@ import org.apache.camel.LoggingLevel;
 import org.apache.camel.builder.RouteBuilder;
 import org.apache.camel.cluster.CamelClusterMember;
 import org.apache.camel.cluster.CamelClusterView;
+import org.apache.camel.component.master.MasterComponent;
 import org.apache.camel.impl.DefaultCamelContext;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.io.TempDir;
@@ -48,6 +49,7 @@ abstract class FileLockClusterServiceTestBase {
 
     protected CamelContext createCamelContext(ClusterConfig config) throws 
Exception {
         CamelContext context = new DefaultCamelContext();
+        context.getComponent("master", 
MasterComponent.class).setBackOffDelay(1000);
         context.addService(createFileLockClusterService(config));
         context.addRoutes(new RouteBuilder() {
             @Override
@@ -64,7 +66,7 @@ abstract class FileLockClusterServiceTestBase {
     protected FileLockClusterService 
createFileLockClusterService(ClusterConfig config) {
         FileLockClusterService service = new FileLockClusterService();
         service.setAcquireLockDelay(config.getAcquireLockDelay());
-        service.setAcquireLockInterval(1);
+        service.setAcquireLockInterval(config.getAcquireLockInterval());
         service.setRoot(clusterDir.toString());
         
service.setHeartbeatTimeoutMultiplier(config.getHeartbeatTimeoutMultiplier());
         
service.setClusterDataTaskMaxAttempts(config.getClusterDataTaskMaxAttempts());
@@ -83,6 +85,7 @@ abstract class FileLockClusterServiceTestBase {
 
     static final class ClusterConfig {
         private long acquireLockDelay = 1;
+        private long acquireLockInterval = 2;
         private long timerRepeatCount = 5;
         private int heartbeatTimeoutMultiplier = 5;
         private int clusterDataTaskMaxAttempts = 5;
@@ -96,6 +99,14 @@ abstract class FileLockClusterServiceTestBase {
             this.acquireLockDelay = acquireLockDelay;
         }
 
+        public long getAcquireLockInterval() {
+            return acquireLockInterval;
+        }
+
+        public void setAcquireLockInterval(long acquireLockInterval) {
+            this.acquireLockInterval = acquireLockInterval;
+        }
+
         long getTimerRepeatCount() {
             return timerRepeatCount;
         }
diff --git a/docs/user-manual/modules/ROOT/pages/clustering.adoc 
b/docs/user-manual/modules/ROOT/pages/clustering.adoc
index 322443e064c1..29d70b10ba76 100644
--- a/docs/user-manual/modules/ROOT/pages/clustering.adoc
+++ b/docs/user-manual/modules/ROOT/pages/clustering.adoc
@@ -61,9 +61,9 @@ Configuration options:
 [options="header", cols="15,55,15,15"]
 |===
 | Name | Description | Default | Type
-| acquireLockDelay | The time to wait before starting to try to acquire the 
cluster lock | 1 | long
+| acquireLockDelay | The time to wait before starting to try to acquire the 
cluster lock. Note that if FileLockClusterService determines no cluster members 
are running or cannot reliably determine the cluster state, the initial delay 
is computed from the acquireLockInterval | 1 | long
 | acquireLockDelayUnit | The time unit for acquireLockDelay | SECONDS | 
TimeUnit
-| acquireLockInterval | The time to wait between attempts to try to acquire 
the cluster lock | 10 | long
+| acquireLockInterval | The time to wait between attempts to try to acquire 
the cluster lock evaluated using wall-clock time. All cluster members must use 
the same value so leadership checks and leader liveness detection remain 
consistent | 10 | long
 | acquireLockIntervalUnit | The time unit for acquireLockInterval | SECONDS | 
TimeUnit
 | clusterDataTaskMaxAttempts | Sets how many times a cluster data task will 
run, counting both the first execution and subsequent retries in case of 
failure or timeout. This can be useful when the cluster data root is on network 
based file storage, where I/O operations may occasionally block for long or 
unpredictable periods | 5 | int
 | clusterDataTaskTimeout | Sets the timeout for a cluster data task (reading 
or writing cluster data). Timeouts are useful when the cluster data root is on 
network storage, where I/O operations may occasionally block for long or 
unpredictable periods | 10 | long

Reply via email to