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

frankgh pushed a commit to branch trunk
in repository https://gitbox.apache.org/repos/asf/cassandra-sidecar.git


The following commit(s) were added to refs/heads/trunk by this push:
     new 259cffe2 CASSSIDECAR-232: Enhance the Cluster Lease Claim task feature 
(#211)
259cffe2 is described below

commit 259cffe2885f7def2d1ef20a298fa7ec898eee71
Author: Francisco Guerrero <fran...@apache.org>
AuthorDate: Wed Mar 19 20:59:06 2025 -0700

    CASSSIDECAR-232: Enhance the Cluster Lease Claim task feature (#211)
    
    Patch by Francisco Guerrero; reviewed by Yifan Cai for CASSSIDECAR-232
---
 CHANGES.txt                                        |   1 +
 conf/sidecar.yaml                                  |  27 ++-
 examples/conf/sidecar-ccm.yaml                     |  93 +++++++-
 ...on.java => ClusterLeaseClaimConfiguration.java} |   8 +-
 .../sidecar/config/CoordinationConfiguration.java  |   2 +-
 .../sidecar/config/RandomInitialDelayDelta.java    |  49 ++++
 .../yaml/ClusterLeaseClaimConfigurationImpl.java   | 141 ++++++++++++
 .../config/yaml/CoordinationConfigurationImpl.java |  13 +-
 .../config/yaml/PeriodicTaskConfigurationImpl.java | 101 ++++++++-
 .../yaml/SchemaKeyspaceConfigurationImpl.java      |   2 +-
 ...ctTokenZeroOfKeyspaceElectorateMembership.java} | 110 ++-------
 .../coordination/ClusterLeaseClaimTask.java        |  25 ++-
 ...catedKeyspaceTokenZeroElectorateMembership.java | 104 +--------
 ...decarInternalTokenZeroElectorateMembership.java |  46 ++++
 .../sidecar/db/SidecarLeaseDatabaseAccessor.java   |  14 +-
 .../sidecar/modules/CoordinationModule.java        |   3 +-
 .../modules/ElectorateMembershipFactory.java       |  62 ++++++
 ...kenZeroElectorateMembershipIntegrationTest.java |  46 ++--
 .../sidecar/testing/IntegrationTestModule.java     |  11 +-
 .../sidecar/config/SidecarConfigurationTest.java   |  57 ++++-
 .../coordination/ClusterLeaseClaimTaskTest.java    |  10 +-
 .../cassandra/sidecar/db/SidecarSchemaTest.java    |   4 +-
 .../modules/ElectorateMembershipFactoryTest.java   |  93 ++++++++
 .../resources/config/sidecar_coordination.yaml     | 247 ---------------------
 .../config/sidecar_multiple_instances.yaml         |  10 +-
 .../resources/config/sidecar_single_instance.yaml  |   5 +-
 26 files changed, 768 insertions(+), 516 deletions(-)

diff --git a/CHANGES.txt b/CHANGES.txt
index baef5ee7..b51f2024 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -1,5 +1,6 @@
 0.2.0
 -----
+ * Enhance the Cluster Lease Claim task feature (CASSSIDECAR-232)
  * Capture Metrics for Schema Reporting (CASSSIDECAR-216)
  * SidecarInstanceCodec is failing to find codec for type (CASSSIDECAR-229)
  * Retry Failed Schema Reports (CASSSIDECAR-217)
diff --git a/conf/sidecar.yaml b/conf/sidecar.yaml
index ada43657..246ed486 100644
--- a/conf/sidecar.yaml
+++ b/conf/sidecar.yaml
@@ -121,20 +121,42 @@ sidecar:
     replication_strategy: SimpleStrategy
     replication_factor: 1
     # The TTL in seconds used to insert entries into the sidecar_lease schema
-    lease_schema_ttl: 2m
+    lease_schema_ttl: 5m
   coordination:
     # Captures configuration parameters for the task that performs the cluster 
lease claim process
     cluster_lease_claim:
+      # The name of the strategy used to determine the electorate membership 
(defaults to MostReplicatedKeyspaceTokenZeroElectorateMembership)
+      # Out of the box Sidecar provides the 
MostReplicatedKeyspaceTokenZeroElectorateMembership, and
+      # SidecarInternalTokenZeroElectorateMembership implementations.
+      # - MostReplicatedKeyspaceTokenZeroElectorateMembership the current 
Sidecar will be determined to be part
+      #                                                       of the 
electorate iff one of the Cassandra instances it
+      #                                                       manages owns 
token 0 for the user keyspace that has the
+      #                                                       highest 
replication factor. If multiple keyspaces have
+      #                                                       the highest 
replication factor, the keyspace to be used
+      #                                                       is decided by 
the keyspace with the name that sorts
+      #                                                       first in the 
lexicographic sort order. If no user
+      #                                                       keyspaces are 
created, the internal sidecar keyspace will
+      #                                                       be used.
+      # - SidecarInternalTokenZeroElectorateMembership        the current 
Sidecar will be determined to be part of the
+      #                                                       electorate iff 
one of the Cassandra instances it manages
+      #                                                       owns token 
{@code 0} for the {@code sidecar_internal}
+      #                                                       keyspace.
+      electorate_membership_strategy: 
MostReplicatedKeyspaceTokenZeroElectorateMembership
       # Whether the process is enabled
       enabled: true
       # The initial delay for the first execution of the cluster lease claim 
process task after being
       # scheduled or rescheduled.
       # The minimum value for the initial delay is 0ms.
       initial_delay: 1s
+      # A random delta value to add jitter to the initial delay for the first 
execution of the cluster
+      # lease claim process. The actual initial delay for the task will be a 
millisecond value of the
+      # initial_delay + RANDOM(initial_delay_random_delta) configuration.
+      # The minimum value for the initial delay random delta is 0ms, which in 
practice disables the jitter.
+      initial_delay_random_delta: 30s
       # How often the cluster lease claim process task will execute after the 
previous task has completed
       # the execution.
       # The minimum value allowed for the cluster lease claim process task 
implementation is 30 seconds
-      execute_interval: 1m
+      execute_interval: 100s
 
 vertx:
   filesystem_options:
@@ -234,7 +256,6 @@ access_control:
 driver_parameters:
   contact_points:
     - "127.0.0.1:9042"
-    - "127.0.0.2:9042"
   username: cassandra
   password: cassandra
   ssl:
diff --git a/examples/conf/sidecar-ccm.yaml b/examples/conf/sidecar-ccm.yaml
index 7fb4f814..bbd41e12 100644
--- a/examples/conf/sidecar-ccm.yaml
+++ b/examples/conf/sidecar-ccm.yaml
@@ -213,26 +213,57 @@ sidecar:
     replication_strategy: SimpleStrategy
     replication_factor: 1
     # The TTL in seconds used to insert entries into the sidecar_lease schema
-    lease_schema_ttl: 2m
+    lease_schema_ttl: 5m
   coordination:
     # Captures configuration parameters for the task that performs the cluster 
lease claim process
     cluster_lease_claim:
+      # The name of the strategy used to determine the electorate membership 
(defaults to MostReplicatedKeyspaceTokenZeroElectorateMembership)
+      # Out of the box Sidecar provides the 
MostReplicatedKeyspaceTokenZeroElectorateMembership, and
+      # SidecarInternalTokenZeroElectorateMembership implementations.
+      # - MostReplicatedKeyspaceTokenZeroElectorateMembership the current 
Sidecar will be determined to be part
+      #                                                       of the 
electorate iff one of the Cassandra instances it
+      #                                                       manages owns 
token 0 for the user keyspace that has the
+      #                                                       highest 
replication factor. If multiple keyspaces have
+      #                                                       the highest 
replication factor, the keyspace to be used
+      #                                                       is decided by 
the keyspace with the name that sorts
+      #                                                       first in the 
lexicographic sort order. If no user
+      #                                                       keyspaces are 
created, the internal sidecar keyspace will
+      #                                                       be used.
+      # - SidecarInternalTokenZeroElectorateMembership        the current 
Sidecar will be determined to be part of the
+      #                                                       electorate iff 
one of the Cassandra instances it manages
+      #                                                       owns token 
{@code 0} for the {@code sidecar_internal}
+      #                                                       keyspace.
+      electorate_membership_strategy: 
MostReplicatedKeyspaceTokenZeroElectorateMembership
       # Whether the process is enabled
       enabled: true
       # The initial delay for the first execution of the cluster lease claim 
process task after being
       # scheduled or rescheduled.
       # The minimum value for the initial delay is 0ms.
       initial_delay: 1s
+      # A random delta value to add jitter to the initial delay for the first 
execution of the cluster
+      # lease claim process. The actual initial delay for the task will be a 
millisecond value of the
+      # initial_delay + RANDOM(initial_delay_random_delta) configuration.
+      # The minimum value for the initial delay random delta is 0ms, which in 
practice disables the jitter.
+      initial_delay_random_delta: 30s
       # How often the cluster lease claim process task will execute after the 
previous task has completed
       # the execution.
       # The minimum value allowed for the cluster lease claim process task 
implementation is 30 seconds
-      execute_interval: 1m
+      execute_interval: 100s
 
 vertx:
   filesystem_options:
     classpath_resolving_enabled: false
     file_caching_enabled: false
 
+schema_reporting:                            # Schema Reporting configuration
+  enabled:          false                    # Disabled by default
+  initial_delay:    6h                       # Maximum delay before the first 
schema report (actual delay is randomized)
+  execute_interval: 12h                      # Exact interval between two 
sequential schema reports
+  endpoint:         http://localhost/schema  # Endpoint address for schema 
reporting
+  method:           PUT                      # HTTP verb to use for schema 
reporting
+  max_retries:      3                        # Number of times a failing 
schema report is retried
+  retry_delay:      1m                       # Delay before a failing schema 
report is retried
+
 #
 # Enable SSL configuration (Disabled by default)
 #
@@ -257,8 +288,12 @@ vertx:
 access_control:
   # When enabled requests need to be authenticated and authorized before 
servicing.
   enabled: false
-  # Supports setting multiple authenticators, request is authenticated if it 
is authenticated by any of the
-  # configured authenticators
+  # Supports setting multiple authenticators, request is authenticated when 
the first authenticator allows the request
+  # to go through.
+  # Out of the box, Cassandra Sidecar provides following authenticator 
provider factories
+  # 
org.apache.cassandra.sidecar.acl.authentication.{MutualTlsAuthenticationHandlerFactory,
 JwtAuthenticationHandlerFactory}.
+  # - MutualTlsAuthenticationHandlerFactory  allows authenticating based on 
user certificates
+  # - JwtAuthenticationHandlerFactory        allows authenticating with user 
JWT tokens
   authenticators:
     - class_name: 
org.apache.cassandra.sidecar.acl.authentication.MutualTlsAuthenticationHandlerFactory
       parameters:
@@ -277,6 +312,19 @@ access_control:
         #
         # other options are, 
io.vertx.ext.auth.mtls.impl.SpiffeIdentityExtractor.
         certificate_identity_extractor: 
org.apache.cassandra.sidecar.acl.authentication.CassandraIdentityExtractor
+      # JwtAuthenticationHandlerFactory adds support to authenticate users 
with their JWT tokens. It also includes
+      # supports for OpenID discovery.
+    - class_name: 
org.apache.cassandra.sidecar.acl.authentication.JwtAuthenticationHandlerFactory
+      parameters:
+        # To selectively enable or disable JWT authentication
+        enabled: false
+        # Site for sidecar to dynamically retrieve the configuration 
information of an OpenID provider, without
+        # having to manually configure settings like issuer etc.
+        site: https://authorization.com
+        # Client Id is a unique identifier assigned by OpenID provider. It is 
used to identity applications/users
+        # trying to connect.
+        client_id: recognized_client_id
+        config_discover_interval: 1h
   authorizer:
     # Authorization backend, implementing 
io.vertx.ext.auth.authorization.AuthorizationProvider; used to
     # provide permissions a user holds.
@@ -321,6 +369,43 @@ healthcheck:
   initial_delay: 0ms
   execute_interval: 30s
 
+# Sidecar Peer Health Monitor settings
+# Enables a periodic task checking for the health of adjacent Sidecar peers in 
the token ring
+sidecar_peer_health:
+  # Determines if the peer health monitor periodic task is enabled or not
+  enabled: false
+  # Time between peer health checks
+  execute_interval: 30s
+  # The amount of retries the client will attempt a request
+  max_retries: 5
+  # The initial delay between the retries the client will attempt a request
+  retry_delay: 10s
+
+# Sidecar client settings used to interact with other sidecars
+sidecar_client:
+  request_timeout: 30s                      # Time in which a request made by 
the sidecar client will time out
+  request_idle_timeout: 30s                 # How long the request can be idle
+
+  # More advanced options to configure the sidecar client
+
+  #connection_pool_max_size: 10              # Max size of the client 
connection pool
+  #connection_pool_clearing_period: 5s       # Period of time for the 
connection pool to clear
+  #connection_pool_event_loop_size: 0        # Defines the size of the event 
loop pool, set to 0 to reuse current event-loop
+  #connection_pool_max_wait_queue_size: -1   # Connection pool max time to 
wait on the queue size, set to -1 for an unbounded queue
+  #max_retries: 5                            # The amount of retries the 
client will attempt a request
+  #retry_delay: 500ms                        # The initial delay between the 
retries the client will attempt a request
+  #max_retry_delay: 10s                      # The max delay between the 
retries the client will attempt a request
+  #ssl:                                      # if ssl is enabled, this is the 
ssl configuration used for the sidecar client
+  #  enabled: false
+  #  keystore:
+  #    type: PKCS12                          # Keystore type
+  #    path: path/to/client/keystore.p12     # Path to the client keystore file
+  #    password: password                    # Keystore password
+  #  truststore:
+  #    type: PKCS12                          # Truststore type
+  #    path: path/to/truststore.p12          # Path to the truststore file
+  #    password: password                    # Truststore password
+
 metrics:
   registry_name: cassandra_sidecar
   vertx:
diff --git 
a/server/src/main/java/org/apache/cassandra/sidecar/config/CoordinationConfiguration.java
 
b/server/src/main/java/org/apache/cassandra/sidecar/config/ClusterLeaseClaimConfiguration.java
similarity index 74%
copy from 
server/src/main/java/org/apache/cassandra/sidecar/config/CoordinationConfiguration.java
copy to 
server/src/main/java/org/apache/cassandra/sidecar/config/ClusterLeaseClaimConfiguration.java
index d6df84f7..cb8093f9 100644
--- 
a/server/src/main/java/org/apache/cassandra/sidecar/config/CoordinationConfiguration.java
+++ 
b/server/src/main/java/org/apache/cassandra/sidecar/config/ClusterLeaseClaimConfiguration.java
@@ -19,12 +19,12 @@
 package org.apache.cassandra.sidecar.config;
 
 /**
- * Configuration relevant to the coordination functionality of Sidecar
+ * Exposes configuration in Sidecar for the cluster lease claim task
  */
-public interface CoordinationConfiguration
+public interface ClusterLeaseClaimConfiguration extends 
PeriodicTaskConfiguration, RandomInitialDelayDelta
 {
     /**
-     * @return configuration parameters for the cluster lease claim task
+     * @return the name of the strategy used to determine the electorate 
membership
      */
-    PeriodicTaskConfiguration clusterLeaseClaimConfiguration();
+    String electorateMembershipStrategy();
 }
diff --git 
a/server/src/main/java/org/apache/cassandra/sidecar/config/CoordinationConfiguration.java
 
b/server/src/main/java/org/apache/cassandra/sidecar/config/CoordinationConfiguration.java
index d6df84f7..08ea9da3 100644
--- 
a/server/src/main/java/org/apache/cassandra/sidecar/config/CoordinationConfiguration.java
+++ 
b/server/src/main/java/org/apache/cassandra/sidecar/config/CoordinationConfiguration.java
@@ -26,5 +26,5 @@ public interface CoordinationConfiguration
     /**
      * @return configuration parameters for the cluster lease claim task
      */
-    PeriodicTaskConfiguration clusterLeaseClaimConfiguration();
+    ClusterLeaseClaimConfiguration clusterLeaseClaimConfiguration();
 }
diff --git 
a/server/src/main/java/org/apache/cassandra/sidecar/config/RandomInitialDelayDelta.java
 
b/server/src/main/java/org/apache/cassandra/sidecar/config/RandomInitialDelayDelta.java
new file mode 100644
index 00000000..09e22a11
--- /dev/null
+++ 
b/server/src/main/java/org/apache/cassandra/sidecar/config/RandomInitialDelayDelta.java
@@ -0,0 +1,49 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.cassandra.sidecar.config;
+
+import java.util.concurrent.ThreadLocalRandom;
+
+import 
org.apache.cassandra.sidecar.common.server.utils.MillisecondBoundConfiguration;
+
+/**
+ * A randomized delta value that adds jitter to the initial delay 
configuration of a
+ * {@link org.apache.cassandra.sidecar.tasks.PeriodicTask}
+ */
+public interface RandomInitialDelayDelta
+{
+    /**
+     * @return the configured value for the initial delay
+     */
+    MillisecondBoundConfiguration initialDelayRandomDelta();
+
+    /**
+     * Returns a random delta delay in milliseconds. Internally it uses 
current's {@link ThreadLocalRandom}
+     * to calculate the next long value.
+     *
+     * @return a random delta delay in milliseconds
+     */
+    default long randomDeltaDelayMillis()
+    {
+        long delta = initialDelayRandomDelta().toMillis();
+        return delta > 0
+               ? ThreadLocalRandom.current().nextLong(delta)
+               : 0;
+    }
+}
diff --git 
a/server/src/main/java/org/apache/cassandra/sidecar/config/yaml/ClusterLeaseClaimConfigurationImpl.java
 
b/server/src/main/java/org/apache/cassandra/sidecar/config/yaml/ClusterLeaseClaimConfigurationImpl.java
new file mode 100644
index 00000000..cb029bb8
--- /dev/null
+++ 
b/server/src/main/java/org/apache/cassandra/sidecar/config/yaml/ClusterLeaseClaimConfigurationImpl.java
@@ -0,0 +1,141 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.cassandra.sidecar.config.yaml;
+
+import java.util.Objects;
+import java.util.function.Consumer;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import org.apache.cassandra.sidecar.common.DataObjectBuilder;
+import 
org.apache.cassandra.sidecar.common.server.utils.MillisecondBoundConfiguration;
+import org.apache.cassandra.sidecar.config.ClusterLeaseClaimConfiguration;
+
+/**
+ * Configuration for the {@link 
org.apache.cassandra.sidecar.coordination.ClusterLeaseClaimTask}
+ */
+public class ClusterLeaseClaimConfigurationImpl extends 
PeriodicTaskConfigurationImpl implements ClusterLeaseClaimConfiguration
+{
+    private static final String DEFAULT_ELECTORATE_MEMBERSHIP_STRATEGY = 
"MostReplicatedKeyspaceTokenZeroElectorateMembership";
+    private static final MillisecondBoundConfiguration 
DEFAULT_INITIAL_DELAY_RANDOM_DELTA = MillisecondBoundConfiguration.parse("30s");
+    public static final PeriodicTaskConfigurationImpl.Builder 
DEFAULT_PERIODIC_TASK_BUILDER = PeriodicTaskConfigurationImpl.Builder
+                                                                               
               .builder()
+                                                                               
               .enabled(true)
+                                                                               
               .initialDelay(MillisecondBoundConfiguration.parse("1s"))
+                                                                               
               .executeInterval(MillisecondBoundConfiguration.parse("100s"));
+
+    @JsonProperty("electorate_membership_strategy")
+    private final String electorateMembershipStrategy;
+
+    @JsonProperty("initial_delay_random_delta")
+    private final MillisecondBoundConfiguration initialDelayRandomDelta;
+
+    @JsonCreator
+    public ClusterLeaseClaimConfigurationImpl()
+    {
+        super(DEFAULT_PERIODIC_TASK_BUILDER);
+        this.electorateMembershipStrategy = 
DEFAULT_ELECTORATE_MEMBERSHIP_STRATEGY;
+        this.initialDelayRandomDelta = DEFAULT_INITIAL_DELAY_RANDOM_DELTA;
+    }
+
+    private ClusterLeaseClaimConfigurationImpl(Builder builder)
+    {
+        super(builder.periodicTaskBuilder);
+        electorateMembershipStrategy = 
Objects.requireNonNull(builder.electorateMembershipStrategy, 
"electorateMembershipStrategy is required");
+        initialDelayRandomDelta = builder.initialDelayRandomDelta;
+    }
+
+    @Override
+    @JsonProperty("electorate_membership_strategy")
+    public String electorateMembershipStrategy()
+    {
+        return electorateMembershipStrategy;
+    }
+
+    @Override
+    @JsonProperty("initial_delay_random_delta")
+    public MillisecondBoundConfiguration initialDelayRandomDelta()
+    {
+        return initialDelayRandomDelta;
+    }
+
+    public static Builder builder()
+    {
+        return new Builder();
+    }
+
+    /**
+     * {@code ClusterLeaseClaimConfigurationImpl} builder static inner class.
+     */
+    public static final class Builder implements DataObjectBuilder<Builder, 
ClusterLeaseClaimConfigurationImpl>
+    {
+        private String electorateMembershipStrategy = 
DEFAULT_ELECTORATE_MEMBERSHIP_STRATEGY;
+        private MillisecondBoundConfiguration initialDelayRandomDelta = 
DEFAULT_INITIAL_DELAY_RANDOM_DELTA;
+        private final PeriodicTaskConfigurationImpl.Builder 
periodicTaskBuilder = DEFAULT_PERIODIC_TASK_BUILDER;
+
+        private Builder()
+        {
+        }
+
+        @Override
+        public Builder self()
+        {
+            return this;
+        }
+
+        /**
+         * Sets the {@code electorateMembershipStrategy} and returns a 
reference to this Builder enabling method chaining.
+         *
+         * @param electorateMembershipStrategy the {@code 
electorateMembershipStrategy} to set
+         * @return a reference to this Builder
+         */
+        public Builder electorateMembershipStrategy(String 
electorateMembershipStrategy)
+        {
+            return update(b -> b.electorateMembershipStrategy = 
electorateMembershipStrategy);
+        }
+
+        /**
+         * Sets the {@code initialDelayRandomDelta} and returns a reference to 
this Builder enabling method chaining.
+         *
+         * @param initialDelayRandomDelta the {@code initialDelayRandomDelta} 
to set
+         * @return a reference to this Builder
+         */
+        public Builder initialDelayRandomDelta(MillisecondBoundConfiguration 
initialDelayRandomDelta)
+        {
+            return update(b -> b.initialDelayRandomDelta = 
initialDelayRandomDelta);
+        }
+
+        public Builder 
overridePeriodicTaskConfiguration(Consumer<PeriodicTaskConfigurationImpl.Builder>
 overrides)
+        {
+            periodicTaskBuilder.update(overrides);
+            return self();
+        }
+
+        /**
+         * Returns a {@code ClusterLeaseClaimConfigurationImpl} built from the 
parameters previously set.
+         *
+         * @return a {@code ClusterLeaseClaimConfigurationImpl} built with 
parameters of this {@code ClusterLeaseClaimConfigurationImpl.Builder}
+         */
+        @Override
+        public ClusterLeaseClaimConfigurationImpl build()
+        {
+            return new ClusterLeaseClaimConfigurationImpl(this);
+        }
+    }
+}
diff --git 
a/server/src/main/java/org/apache/cassandra/sidecar/config/yaml/CoordinationConfigurationImpl.java
 
b/server/src/main/java/org/apache/cassandra/sidecar/config/yaml/CoordinationConfigurationImpl.java
index e0f6b7cb..c33231b2 100644
--- 
a/server/src/main/java/org/apache/cassandra/sidecar/config/yaml/CoordinationConfigurationImpl.java
+++ 
b/server/src/main/java/org/apache/cassandra/sidecar/config/yaml/CoordinationConfigurationImpl.java
@@ -19,9 +19,8 @@
 package org.apache.cassandra.sidecar.config.yaml;
 
 import com.fasterxml.jackson.annotation.JsonProperty;
-import 
org.apache.cassandra.sidecar.common.server.utils.MillisecondBoundConfiguration;
+import org.apache.cassandra.sidecar.config.ClusterLeaseClaimConfiguration;
 import org.apache.cassandra.sidecar.config.CoordinationConfiguration;
-import org.apache.cassandra.sidecar.config.PeriodicTaskConfiguration;
 
 /**
  * Configuration relevant to the coordination functionality of Sidecar
@@ -29,16 +28,14 @@ import 
org.apache.cassandra.sidecar.config.PeriodicTaskConfiguration;
 public class CoordinationConfigurationImpl implements CoordinationConfiguration
 {
     @JsonProperty("cluster_lease_claim")
-    private final PeriodicTaskConfiguration clusterLeaseClaimConfiguration;
+    private final ClusterLeaseClaimConfiguration 
clusterLeaseClaimConfiguration;
 
     public CoordinationConfigurationImpl()
     {
-        this(new PeriodicTaskConfigurationImpl(true,
-                                               
MillisecondBoundConfiguration.parse("1s"),
-                                               
MillisecondBoundConfiguration.parse("1m")));
+        this(ClusterLeaseClaimConfigurationImpl.builder().build());
     }
 
-    public CoordinationConfigurationImpl(PeriodicTaskConfiguration 
clusterLeaseClaimConfiguration)
+    public CoordinationConfigurationImpl(ClusterLeaseClaimConfiguration 
clusterLeaseClaimConfiguration)
     {
         this.clusterLeaseClaimConfiguration = clusterLeaseClaimConfiguration;
     }
@@ -48,7 +45,7 @@ public class CoordinationConfigurationImpl implements 
CoordinationConfiguration
      */
     @Override
     @JsonProperty("cluster_lease_claim")
-    public PeriodicTaskConfiguration clusterLeaseClaimConfiguration()
+    public ClusterLeaseClaimConfiguration clusterLeaseClaimConfiguration()
     {
         return clusterLeaseClaimConfiguration;
     }
diff --git 
a/server/src/main/java/org/apache/cassandra/sidecar/config/yaml/PeriodicTaskConfigurationImpl.java
 
b/server/src/main/java/org/apache/cassandra/sidecar/config/yaml/PeriodicTaskConfigurationImpl.java
index 78d115cb..6ee982c7 100644
--- 
a/server/src/main/java/org/apache/cassandra/sidecar/config/yaml/PeriodicTaskConfigurationImpl.java
+++ 
b/server/src/main/java/org/apache/cassandra/sidecar/config/yaml/PeriodicTaskConfigurationImpl.java
@@ -18,6 +18,7 @@
 
 package org.apache.cassandra.sidecar.config.yaml;
 
+import java.util.Objects;
 import java.util.concurrent.TimeUnit;
 
 import org.slf4j.Logger;
@@ -25,13 +26,16 @@ import org.slf4j.LoggerFactory;
 
 import com.fasterxml.jackson.annotation.JsonAlias;
 import com.fasterxml.jackson.annotation.JsonProperty;
+import org.apache.cassandra.sidecar.common.DataObjectBuilder;
 import 
org.apache.cassandra.sidecar.common.server.utils.MillisecondBoundConfiguration;
 import org.apache.cassandra.sidecar.config.PeriodicTaskConfiguration;
+import org.apache.cassandra.sidecar.tasks.PeriodicTask;
+import org.jetbrains.annotations.NotNull;
 
 import static 
org.apache.cassandra.sidecar.common.server.utils.MillisecondBoundConfiguration.ONE;
 
 /**
- * Configuration for the {@link 
org.apache.cassandra.sidecar.tasks.PeriodicTask}
+ * Configuration for the {@link PeriodicTask}
  */
 public class PeriodicTaskConfigurationImpl implements PeriodicTaskConfiguration
 {
@@ -60,6 +64,13 @@ public class PeriodicTaskConfigurationImpl implements 
PeriodicTaskConfiguration
         this.executeInterval = executeInterval;
     }
 
+    protected PeriodicTaskConfigurationImpl(Builder builder)
+    {
+        enabled = builder.enabled;
+        setInitialDelay(builder.initialDelay);
+        setExecuteInterval(Objects.requireNonNull(builder.executeInterval, 
"executeInterval must be configured"));
+    }
+
     /**
      * {@inheritDoc}
      */
@@ -75,6 +86,7 @@ public class PeriodicTaskConfigurationImpl implements 
PeriodicTaskConfiguration
      */
     @Override
     @JsonProperty("initial_delay")
+    @NotNull
     public MillisecondBoundConfiguration initialDelay()
     {
         if (initialDelay == null)
@@ -87,14 +99,17 @@ public class PeriodicTaskConfigurationImpl implements 
PeriodicTaskConfiguration
     @JsonProperty("initial_delay")
     public void setInitialDelay(MillisecondBoundConfiguration initialDelay)
     {
-        if (initialDelay.compareTo(MillisecondBoundConfiguration.ZERO) > 0)
-        {
-            this.initialDelay = initialDelay;
-        }
-        else
+        if (initialDelay != null)
         {
-            LOGGER.warn("Invalid initialDelay configuration {}, the minimum 
value is 0", initialDelay);
-            this.initialDelay = MillisecondBoundConfiguration.ZERO;
+            if (initialDelay.compareTo(MillisecondBoundConfiguration.ZERO) > 0)
+            {
+                this.initialDelay = initialDelay;
+            }
+            else
+            {
+                LOGGER.warn("Invalid initialDelay configuration {}, the 
minimum value is 0", initialDelay);
+                this.initialDelay = MillisecondBoundConfiguration.ZERO;
+            }
         }
     }
 
@@ -117,6 +132,7 @@ public class PeriodicTaskConfigurationImpl implements 
PeriodicTaskConfiguration
      */
     @Override
     @JsonProperty("execute_interval")
+    @NotNull
     public MillisecondBoundConfiguration executeInterval()
     {
         return executeInterval;
@@ -150,4 +166,73 @@ public class PeriodicTaskConfigurationImpl implements 
PeriodicTaskConfiguration
                     "use 'execute_interval' instead.");
         setExecuteInterval(new 
MillisecondBoundConfiguration(executeIntervalMillis, TimeUnit.MILLISECONDS));
     }
+
+    /**
+     * {@code PeriodicTaskConfigurationImpl} builder static inner class.
+     */
+    public static class Builder implements DataObjectBuilder<Builder, 
PeriodicTaskConfigurationImpl>
+    {
+        private boolean enabled;
+        private MillisecondBoundConfiguration initialDelay;
+        private MillisecondBoundConfiguration executeInterval;
+
+        private Builder()
+        {
+        }
+
+        public static Builder builder()
+        {
+            return new Builder();
+        }
+
+        @Override
+        public Builder self()
+        {
+            return this;
+        }
+
+        /**
+         * Sets the {@code enabled} and returns a reference to this Builder 
enabling method chaining.
+         *
+         * @param enabled the {@code enabled} to set
+         * @return a reference to this Builder
+         */
+        public Builder enabled(boolean enabled)
+        {
+            return update(b -> b.enabled = enabled);
+        }
+
+        /**
+         * Sets the {@code initialDelay} and returns a reference to this 
Builder enabling method chaining.
+         *
+         * @param initialDelay the {@code initialDelay} to set
+         * @return a reference to this Builder
+         */
+        public Builder initialDelay(MillisecondBoundConfiguration initialDelay)
+        {
+            return update(b -> b.initialDelay = initialDelay);
+        }
+
+        /**
+         * Sets the {@code executeInterval} and returns a reference to this 
Builder enabling method chaining.
+         *
+         * @param executeInterval the {@code executeInterval} to set
+         * @return a reference to this Builder
+         */
+        public Builder executeInterval(MillisecondBoundConfiguration 
executeInterval)
+        {
+            return update(b -> b.executeInterval = executeInterval);
+        }
+
+        /**
+         * Returns a {@code PeriodicTaskConfigurationImpl} built from the 
parameters previously set.
+         *
+         * @return a {@code PeriodicTaskConfigurationImpl} built with 
parameters of this {@code PeriodicTaskConfigurationImpl.Builder}
+         */
+        @Override
+        public PeriodicTaskConfigurationImpl build()
+        {
+            return new PeriodicTaskConfigurationImpl(this);
+        }
+    }
 }
diff --git 
a/server/src/main/java/org/apache/cassandra/sidecar/config/yaml/SchemaKeyspaceConfigurationImpl.java
 
b/server/src/main/java/org/apache/cassandra/sidecar/config/yaml/SchemaKeyspaceConfigurationImpl.java
index c8846e9a..31c0ffaa 100644
--- 
a/server/src/main/java/org/apache/cassandra/sidecar/config/yaml/SchemaKeyspaceConfigurationImpl.java
+++ 
b/server/src/main/java/org/apache/cassandra/sidecar/config/yaml/SchemaKeyspaceConfigurationImpl.java
@@ -39,7 +39,7 @@ public class SchemaKeyspaceConfigurationImpl implements 
SchemaKeyspaceConfigurat
     public static final String DEFAULT_KEYSPACE = "sidecar_internal";
     public static final String DEFAULT_REPLICATION_STRATEGY = "SimpleStrategy";
     public static final int DEFAULT_REPLICATION_FACTOR = 1;
-    public static final SecondBoundConfiguration DEFAULT_LEASE_SCHEMA_TTL = 
SecondBoundConfiguration.parse("2m");
+    public static final SecondBoundConfiguration DEFAULT_LEASE_SCHEMA_TTL = 
SecondBoundConfiguration.parse("5m");
     public static final SecondBoundConfiguration MINIMUM_LEASE_SCHEMA_TTL = 
SecondBoundConfiguration.parse("1m");
 
     @JsonProperty(value = "is_enabled")
diff --git 
a/server/src/main/java/org/apache/cassandra/sidecar/coordination/MostReplicatedKeyspaceTokenZeroElectorateMembership.java
 
b/server/src/main/java/org/apache/cassandra/sidecar/coordination/AbstractTokenZeroOfKeyspaceElectorateMembership.java
similarity index 52%
copy from 
server/src/main/java/org/apache/cassandra/sidecar/coordination/MostReplicatedKeyspaceTokenZeroElectorateMembership.java
copy to 
server/src/main/java/org/apache/cassandra/sidecar/coordination/AbstractTokenZeroOfKeyspaceElectorateMembership.java
index 8a907830..163eaf3c 100644
--- 
a/server/src/main/java/org/apache/cassandra/sidecar/coordination/MostReplicatedKeyspaceTokenZeroElectorateMembership.java
+++ 
b/server/src/main/java/org/apache/cassandra/sidecar/coordination/AbstractTokenZeroOfKeyspaceElectorateMembership.java
@@ -20,7 +20,6 @@ package org.apache.cassandra.sidecar.coordination;
 
 import java.math.BigInteger;
 import java.net.InetSocketAddress;
-import java.util.Comparator;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
@@ -28,43 +27,28 @@ import java.util.Set;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import com.datastax.driver.core.KeyspaceMetadata;
-import com.datastax.driver.core.Session;
 import org.apache.cassandra.sidecar.cluster.CassandraAdapterDelegate;
 import org.apache.cassandra.sidecar.cluster.instance.InstanceMetadata;
 import org.apache.cassandra.sidecar.common.response.NodeSettings;
 import org.apache.cassandra.sidecar.common.response.TokenRangeReplicasResponse;
-import org.apache.cassandra.sidecar.common.server.CQLSessionProvider;
 import org.apache.cassandra.sidecar.common.server.StorageOperations;
 import org.apache.cassandra.sidecar.common.server.data.Name;
 import org.apache.cassandra.sidecar.common.server.utils.StringUtils;
-import org.apache.cassandra.sidecar.config.SidecarConfiguration;
 import org.apache.cassandra.sidecar.exceptions.CassandraUnavailableException;
 import org.apache.cassandra.sidecar.utils.InstanceMetadataFetcher;
 
 /**
- * An implementation of {@link ElectorateMembership} where the current Sidecar 
will
- * be determined to be part of the electorate iff one of the Cassandra 
instances it
- * manages owns token {@code 0} for the user keyspace that has the highest 
replication
- * factor. If multiple keyspaces have the highest replication factor, the 
keyspace
- * to be used is decided by the keyspace with the name that sorts first in the
- * lexicographic sort order. If no user keyspaces are created, the internal 
sidecar
- * keyspace will be used.
+ * Provides common functionality for {@link ElectorateMembership} 
implementations
+ * that rely on token zero replication of a keyspace to determine eligibility.
  */
-public class MostReplicatedKeyspaceTokenZeroElectorateMembership implements 
ElectorateMembership
+public abstract class AbstractTokenZeroOfKeyspaceElectorateMembership 
implements ElectorateMembership
 {
-    private static final Logger LOGGER = 
LoggerFactory.getLogger(MostReplicatedKeyspaceTokenZeroElectorateMembership.class);
-    private final InstanceMetadataFetcher instanceMetadataFetcher;
-    private final CQLSessionProvider cqlSessionProvider;
-    private final SidecarConfiguration configuration;
+    private static final Logger LOGGER = 
LoggerFactory.getLogger(AbstractTokenZeroOfKeyspaceElectorateMembership.class);
+    protected final InstanceMetadataFetcher instanceMetadataFetcher;
 
-    public 
MostReplicatedKeyspaceTokenZeroElectorateMembership(InstanceMetadataFetcher 
instanceMetadataFetcher,
-                                                               
CQLSessionProvider cqlSessionProvider,
-                                                               
SidecarConfiguration sidecarConfiguration)
+    public 
AbstractTokenZeroOfKeyspaceElectorateMembership(InstanceMetadataFetcher 
instanceMetadataFetcher)
     {
         this.instanceMetadataFetcher = instanceMetadataFetcher;
-        this.cqlSessionProvider = cqlSessionProvider;
-        this.configuration = sidecarConfiguration;
     }
 
     /**
@@ -80,24 +64,30 @@ public class 
MostReplicatedKeyspaceTokenZeroElectorateMembership implements Elec
             return false;
         }
 
-        String userKeyspace = highestReplicationFactorKeyspace();
-        if (userKeyspace == null)
+        String keyspace = keyspaceToDetermineElectorateMembership();
+        if (keyspace == null)
         {
             // pre-checks failed
             return false;
         }
+        LOGGER.debug("Using keyspace={} to determine electorate membership", 
keyspace);
 
         TokenRangeReplicasResponse tokenRangeReplicas = 
instanceMetadataFetcher.callOnFirstAvailableInstance(instance -> {
             CassandraAdapterDelegate delegate = instance.delegate();
             StorageOperations operations = delegate.storageOperations();
             NodeSettings nodeSettings = delegate.nodeSettings();
-            return operations.tokenRangeReplicas(new Name(userKeyspace), 
nodeSettings.partitioner());
+            return operations.tokenRangeReplicas(new Name(keyspace), 
nodeSettings.partitioner());
         });
 
         return anyInstanceOwnsTokenZero(tokenRangeReplicas, 
localInstancesHostsAndPorts);
     }
 
-    Set<String> collectLocalInstancesHostsAndPorts()
+    /**
+     * @return the name of the keyspace that will be used to determine the 
electorate membership
+     */
+    protected abstract String keyspaceToDetermineElectorateMembership();
+
+    protected Set<String> collectLocalInstancesHostsAndPorts()
     {
         Set<String> result = new HashSet<>();
         for (InstanceMetadata instance : 
instanceMetadataFetcher.allLocalInstances())
@@ -116,56 +106,13 @@ public class 
MostReplicatedKeyspaceTokenZeroElectorateMembership implements Elec
         return result;
     }
 
-    /**
-     * Performs pre-checks ensuring local instances are configured; an active 
session to the database is present;
-     * and returns the keyspace with the highest replication factor. If 
multiple keyspaces have the highest
-     * replication factor, the keyspace to be used is decided by the keyspace 
with the name that sorts first in
-     * the lexicographic sort order. Defaults to the sidecar keyspace when 
there are no user keyspaces.
-     *
-     * @return user keyspace
-     */
-    String highestReplicationFactorKeyspace()
-    {
-        if (instanceMetadataFetcher.allLocalInstances().isEmpty())
-        {
-            LOGGER.warn("There are no local Cassandra instances managed by 
this Sidecar");
-            return null;
-        }
-
-        Session activeSession;
-        try
-        {
-            activeSession = cqlSessionProvider.get();
-        }
-        catch (CassandraUnavailableException exception)
-        {
-            LOGGER.warn("There is no active session to Cassandra");
-            return null;
-        }
-
-        Set<String> forbiddenKeyspaces = 
configuration.cassandraInputValidationConfiguration().forbiddenKeyspaces();
-        String sidecarKeyspaceName = 
configuration.serviceConfiguration().schemaKeyspaceConfiguration().keyspace();
-
-        return activeSession.getCluster().getMetadata().getKeyspaces().stream()
-                            .filter(keyspace -> 
!forbiddenKeyspaces.contains(keyspace.getName()))
-                            // Sort by the keyspace with the highest 
replication factor
-                            // and then sort by the keyspace name to guarantee 
in the
-                            // sorting order across all Sidecar instances
-                            
.sorted(Comparator.comparingInt(this::aggregateReplicationFactor)
-                                              .reversed()
-                                              
.thenComparing(KeyspaceMetadata::getName))
-                            .map(KeyspaceMetadata::getName)
-                            .findFirst()
-                            .orElse(sidecarKeyspaceName);
-    }
-
     /**
      * @param tokenRangeReplicas         the token range replicas for a 
keyspace
      * @param localInstancesHostAndPorts local instance(s) IP(s) and port(s)
      * @return {@code true} if any of the local instances is a replica of 
token zero for a single keyspace,
      * {@code false} otherwise
      */
-    boolean anyInstanceOwnsTokenZero(TokenRangeReplicasResponse 
tokenRangeReplicas, Set<String> localInstancesHostAndPorts)
+    protected boolean anyInstanceOwnsTokenZero(TokenRangeReplicasResponse 
tokenRangeReplicas, Set<String> localInstancesHostAndPorts)
     {
         return tokenRangeReplicas.readReplicas()
                                  .stream()
@@ -192,32 +139,11 @@ public class 
MostReplicatedKeyspaceTokenZeroElectorateMembership implements Elec
      * @param replicaInfo the replica info
      * @return {@code true} if the replica info owns token zero, {@code false} 
otherwise
      */
-    boolean replicaOwnsTokenZero(TokenRangeReplicasResponse.ReplicaInfo 
replicaInfo)
+    protected boolean 
replicaOwnsTokenZero(TokenRangeReplicasResponse.ReplicaInfo replicaInfo)
     {
         BigInteger start = new BigInteger(replicaInfo.start());
         BigInteger end = new BigInteger(replicaInfo.end());
         // start is exclusive; end is inclusive
         return start.compareTo(BigInteger.ZERO) < 0 && 
end.compareTo(BigInteger.ZERO) >= 0;
     }
-
-    /**
-     * @param keyspace the keyspace
-     * @return the aggregate replication factor for the {@link 
KeyspaceMetadata keyspace}
-     */
-    int aggregateReplicationFactor(KeyspaceMetadata keyspace)
-    {
-        int replicationFactor = 0;
-        for (String value : keyspace.getReplication().values())
-        {
-            try
-            {
-                replicationFactor += Integer.parseInt(value);
-            }
-            catch (NumberFormatException ignored)
-            {
-                // skips the class property of the replication factor
-            }
-        }
-        return replicationFactor;
-    }
 }
diff --git 
a/server/src/main/java/org/apache/cassandra/sidecar/coordination/ClusterLeaseClaimTask.java
 
b/server/src/main/java/org/apache/cassandra/sidecar/coordination/ClusterLeaseClaimTask.java
index 1cc62fb0..49ace97d 100644
--- 
a/server/src/main/java/org/apache/cassandra/sidecar/coordination/ClusterLeaseClaimTask.java
+++ 
b/server/src/main/java/org/apache/cassandra/sidecar/coordination/ClusterLeaseClaimTask.java
@@ -21,6 +21,7 @@ package org.apache.cassandra.sidecar.coordination;
 import java.time.Instant;
 import java.time.temporal.ChronoUnit;
 import java.util.Objects;
+import java.util.concurrent.TimeUnit;
 import java.util.function.Function;
 
 import org.slf4j.Logger;
@@ -32,8 +33,9 @@ import io.vertx.core.Promise;
 import io.vertx.core.Vertx;
 import io.vertx.core.eventbus.EventBus;
 import org.apache.cassandra.sidecar.common.server.utils.DurationSpec;
+import 
org.apache.cassandra.sidecar.common.server.utils.MillisecondBoundConfiguration;
 import 
org.apache.cassandra.sidecar.common.server.utils.SecondBoundConfiguration;
-import org.apache.cassandra.sidecar.config.PeriodicTaskConfiguration;
+import org.apache.cassandra.sidecar.config.ClusterLeaseClaimConfiguration;
 import org.apache.cassandra.sidecar.config.ServiceConfiguration;
 import org.apache.cassandra.sidecar.db.SidecarLeaseDatabaseAccessor;
 import org.apache.cassandra.sidecar.metrics.CoordinationMetrics;
@@ -75,7 +77,7 @@ public class ClusterLeaseClaimTask implements PeriodicTask
     private final SidecarLeaseDatabaseAccessor accessor;
     private final ClusterLease clusterLease;
     private final CoordinationMetrics metrics;
-    private final PeriodicTaskConfiguration periodicTaskConfiguration;
+    private final ClusterLeaseClaimConfiguration configuration;
     private final ServiceConfiguration config;
     private EventBus eventBus;
     private String currentLeaseholder;
@@ -87,7 +89,7 @@ public class ClusterLeaseClaimTask implements PeriodicTask
                                  ClusterLease clusterLease,
                                  SidecarMetrics metrics)
     {
-        this.periodicTaskConfiguration = 
serviceConfiguration.coordinationConfiguration().clusterLeaseClaimConfiguration();
+        this.configuration = 
serviceConfiguration.coordinationConfiguration().clusterLeaseClaimConfiguration();
         this.config = serviceConfiguration;
         this.electorateMembership = electorateMembership;
         this.accessor = accessor;
@@ -110,7 +112,7 @@ public class ClusterLeaseClaimTask implements PeriodicTask
     {
         // The Sidecar schema feature is required for this implementation
         // so skip when the feature is not enabled
-        boolean isEnabled = config.schemaKeyspaceConfiguration().isEnabled() 
&& periodicTaskConfiguration.enabled();
+        boolean isEnabled = config.schemaKeyspaceConfiguration().isEnabled() 
&& configuration.enabled();
         boolean isMember = false;
         if (isEnabled)
         {
@@ -144,7 +146,16 @@ public class ClusterLeaseClaimTask implements PeriodicTask
     @Override
     public DurationSpec initialDelay()
     {
-        return periodicTaskConfiguration.initialDelay();
+        // Return a randomized delay to introduce jitter among all the 
instances participating
+        // in the lease claim process
+        long randomDeltaDelayMillis = configuration.randomDeltaDelayMillis();
+        if (randomDeltaDelayMillis == 0)
+        {
+            // no jitter
+            return configuration.initialDelay();
+        }
+        long initialDelayMillis = configuration.initialDelay().toMillis() + 
randomDeltaDelayMillis;
+        return new MillisecondBoundConfiguration(initialDelayMillis, 
TimeUnit.MILLISECONDS);
     }
 
     /**
@@ -153,7 +164,7 @@ public class ClusterLeaseClaimTask implements PeriodicTask
     @Override
     public DurationSpec delay()
     {
-        DurationSpec delay = periodicTaskConfiguration.executeInterval();
+        DurationSpec delay = configuration.executeInterval();
 
         if (delay.compareTo(MINIMUM_DELAY) < 0)
         {
@@ -207,7 +218,7 @@ public class ClusterLeaseClaimTask implements PeriodicTask
             LOGGER.debug("Attempting to {} lease for sidecarHostId={}", 
actionName, sidecarHostId);
             return actionFn.apply(sidecarHostId).currentOwner;
         }
-        catch (QueryConsistencyException | NoHostAvailableException e)
+        catch (QueryConsistencyException | NoHostAvailableException | 
IllegalArgumentException e)
         {
             LOGGER.debug("Unable to {} lease for sidecarHostId={}", 
actionName, sidecarHostId, e);
         }
diff --git 
a/server/src/main/java/org/apache/cassandra/sidecar/coordination/MostReplicatedKeyspaceTokenZeroElectorateMembership.java
 
b/server/src/main/java/org/apache/cassandra/sidecar/coordination/MostReplicatedKeyspaceTokenZeroElectorateMembership.java
index 8a907830..8d9f2fae 100644
--- 
a/server/src/main/java/org/apache/cassandra/sidecar/coordination/MostReplicatedKeyspaceTokenZeroElectorateMembership.java
+++ 
b/server/src/main/java/org/apache/cassandra/sidecar/coordination/MostReplicatedKeyspaceTokenZeroElectorateMembership.java
@@ -18,11 +18,7 @@
 
 package org.apache.cassandra.sidecar.coordination;
 
-import java.math.BigInteger;
-import java.net.InetSocketAddress;
 import java.util.Comparator;
-import java.util.HashSet;
-import java.util.List;
 import java.util.Set;
 
 import org.slf4j.Logger;
@@ -30,14 +26,7 @@ import org.slf4j.LoggerFactory;
 
 import com.datastax.driver.core.KeyspaceMetadata;
 import com.datastax.driver.core.Session;
-import org.apache.cassandra.sidecar.cluster.CassandraAdapterDelegate;
-import org.apache.cassandra.sidecar.cluster.instance.InstanceMetadata;
-import org.apache.cassandra.sidecar.common.response.NodeSettings;
-import org.apache.cassandra.sidecar.common.response.TokenRangeReplicasResponse;
 import org.apache.cassandra.sidecar.common.server.CQLSessionProvider;
-import org.apache.cassandra.sidecar.common.server.StorageOperations;
-import org.apache.cassandra.sidecar.common.server.data.Name;
-import org.apache.cassandra.sidecar.common.server.utils.StringUtils;
 import org.apache.cassandra.sidecar.config.SidecarConfiguration;
 import org.apache.cassandra.sidecar.exceptions.CassandraUnavailableException;
 import org.apache.cassandra.sidecar.utils.InstanceMetadataFetcher;
@@ -51,10 +40,9 @@ import 
org.apache.cassandra.sidecar.utils.InstanceMetadataFetcher;
  * lexicographic sort order. If no user keyspaces are created, the internal 
sidecar
  * keyspace will be used.
  */
-public class MostReplicatedKeyspaceTokenZeroElectorateMembership implements 
ElectorateMembership
+public class MostReplicatedKeyspaceTokenZeroElectorateMembership extends 
AbstractTokenZeroOfKeyspaceElectorateMembership
 {
     private static final Logger LOGGER = 
LoggerFactory.getLogger(MostReplicatedKeyspaceTokenZeroElectorateMembership.class);
-    private final InstanceMetadataFetcher instanceMetadataFetcher;
     private final CQLSessionProvider cqlSessionProvider;
     private final SidecarConfiguration configuration;
 
@@ -62,58 +50,15 @@ public class 
MostReplicatedKeyspaceTokenZeroElectorateMembership implements Elec
                                                                
CQLSessionProvider cqlSessionProvider,
                                                                
SidecarConfiguration sidecarConfiguration)
     {
-        this.instanceMetadataFetcher = instanceMetadataFetcher;
+        super(instanceMetadataFetcher);
         this.cqlSessionProvider = cqlSessionProvider;
         this.configuration = sidecarConfiguration;
     }
 
-    /**
-     * {@inheritDoc}
-     */
     @Override
-    public boolean isMember()
+    protected String keyspaceToDetermineElectorateMembership()
     {
-        Set<String> localInstancesHostsAndPorts = 
collectLocalInstancesHostsAndPorts();
-        if (localInstancesHostsAndPorts.isEmpty())
-        {
-            // Unable to retrieve local instances, maybe all Cassandra 
connections are down?
-            return false;
-        }
-
-        String userKeyspace = highestReplicationFactorKeyspace();
-        if (userKeyspace == null)
-        {
-            // pre-checks failed
-            return false;
-        }
-
-        TokenRangeReplicasResponse tokenRangeReplicas = 
instanceMetadataFetcher.callOnFirstAvailableInstance(instance -> {
-            CassandraAdapterDelegate delegate = instance.delegate();
-            StorageOperations operations = delegate.storageOperations();
-            NodeSettings nodeSettings = delegate.nodeSettings();
-            return operations.tokenRangeReplicas(new Name(userKeyspace), 
nodeSettings.partitioner());
-        });
-
-        return anyInstanceOwnsTokenZero(tokenRangeReplicas, 
localInstancesHostsAndPorts);
-    }
-
-    Set<String> collectLocalInstancesHostsAndPorts()
-    {
-        Set<String> result = new HashSet<>();
-        for (InstanceMetadata instance : 
instanceMetadataFetcher.allLocalInstances())
-        {
-            try
-            {
-                InetSocketAddress address = 
instance.delegate().localStorageBroadcastAddress();
-                result.add(StringUtils.cassandraFormattedHostAndPort(address));
-            }
-            catch (CassandraUnavailableException exception)
-            {
-                // Log a warning message and continue
-                LOGGER.warn("Unable to determine local storage broadcast 
address for instance. instance={}", instance, exception);
-            }
-        }
-        return result;
+        return highestReplicationFactorKeyspace();
     }
 
     /**
@@ -159,47 +104,6 @@ public class 
MostReplicatedKeyspaceTokenZeroElectorateMembership implements Elec
                             .orElse(sidecarKeyspaceName);
     }
 
-    /**
-     * @param tokenRangeReplicas         the token range replicas for a 
keyspace
-     * @param localInstancesHostAndPorts local instance(s) IP(s) and port(s)
-     * @return {@code true} if any of the local instances is a replica of 
token zero for a single keyspace,
-     * {@code false} otherwise
-     */
-    boolean anyInstanceOwnsTokenZero(TokenRangeReplicasResponse 
tokenRangeReplicas, Set<String> localInstancesHostAndPorts)
-    {
-        return tokenRangeReplicas.readReplicas()
-                                 .stream()
-                                 // only returns replicas that contain token 
zero
-                                 .filter(this::replicaOwnsTokenZero)
-                                 // and then see if any of the replicas 
matches the
-                                 // local instance's host and port
-                                 .anyMatch(replicaInfo -> {
-                                     for (List<String> replicas : 
replicaInfo.replicasByDatacenter().values())
-                                     {
-                                         for (String replica : replicas)
-                                         {
-                                             if 
(localInstancesHostAndPorts.contains(replica))
-                                             {
-                                                 return true;
-                                             }
-                                         }
-                                     }
-                                     return false;
-                                 });
-    }
-
-    /**
-     * @param replicaInfo the replica info
-     * @return {@code true} if the replica info owns token zero, {@code false} 
otherwise
-     */
-    boolean replicaOwnsTokenZero(TokenRangeReplicasResponse.ReplicaInfo 
replicaInfo)
-    {
-        BigInteger start = new BigInteger(replicaInfo.start());
-        BigInteger end = new BigInteger(replicaInfo.end());
-        // start is exclusive; end is inclusive
-        return start.compareTo(BigInteger.ZERO) < 0 && 
end.compareTo(BigInteger.ZERO) >= 0;
-    }
-
     /**
      * @param keyspace the keyspace
      * @return the aggregate replication factor for the {@link 
KeyspaceMetadata keyspace}
diff --git 
a/server/src/main/java/org/apache/cassandra/sidecar/coordination/SidecarInternalTokenZeroElectorateMembership.java
 
b/server/src/main/java/org/apache/cassandra/sidecar/coordination/SidecarInternalTokenZeroElectorateMembership.java
new file mode 100644
index 00000000..dca2ca0a
--- /dev/null
+++ 
b/server/src/main/java/org/apache/cassandra/sidecar/coordination/SidecarInternalTokenZeroElectorateMembership.java
@@ -0,0 +1,46 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.cassandra.sidecar.coordination;
+
+import org.apache.cassandra.sidecar.config.SchemaKeyspaceConfiguration;
+import org.apache.cassandra.sidecar.config.SidecarConfiguration;
+import org.apache.cassandra.sidecar.utils.InstanceMetadataFetcher;
+
+/**
+ * An implementation of {@link ElectorateMembership} where the current Sidecar 
will
+ * be determined to be part of the electorate iff one of the Cassandra 
instances it
+ * manages owns token {@code 0} for the {@code sidecar_internal} keyspace.
+ */
+public class SidecarInternalTokenZeroElectorateMembership extends 
AbstractTokenZeroOfKeyspaceElectorateMembership
+{
+    private final SchemaKeyspaceConfiguration configuration;
+
+    public 
SidecarInternalTokenZeroElectorateMembership(InstanceMetadataFetcher 
instanceMetadataFetcher,
+                                                        SidecarConfiguration 
sidecarConfiguration)
+    {
+        super(instanceMetadataFetcher);
+        configuration = 
sidecarConfiguration.serviceConfiguration().schemaKeyspaceConfiguration();
+    }
+
+    @Override
+    protected String keyspaceToDetermineElectorateMembership()
+    {
+        return configuration.keyspace();
+    }
+}
diff --git 
a/server/src/main/java/org/apache/cassandra/sidecar/db/SidecarLeaseDatabaseAccessor.java
 
b/server/src/main/java/org/apache/cassandra/sidecar/db/SidecarLeaseDatabaseAccessor.java
index aed5b36c..94ce415e 100644
--- 
a/server/src/main/java/org/apache/cassandra/sidecar/db/SidecarLeaseDatabaseAccessor.java
+++ 
b/server/src/main/java/org/apache/cassandra/sidecar/db/SidecarLeaseDatabaseAccessor.java
@@ -50,6 +50,7 @@ public class SidecarLeaseDatabaseAccessor extends 
DatabaseAccessor<SidecarLeaseS
      *
      * @param leaseClaimer the identifier of the instances attempting to claim 
the lease
      * @return the results of performing the lease claim
+     * @throws IllegalArgumentException when the owner information is not 
available from the lease claim operation
      */
     public LeaseClaimResult claimLease(String leaseClaimer)
     {
@@ -63,6 +64,7 @@ public class SidecarLeaseDatabaseAccessor extends 
DatabaseAccessor<SidecarLeaseS
      *
      * @param currentOwner the current owner extending the lease
      * @return the results of performing the lease extension
+     * @throws IllegalArgumentException when the owner information is not 
available from the lease extension operation
      */
     public LeaseClaimResult extendLease(String currentOwner)
     {
@@ -76,20 +78,22 @@ public class SidecarLeaseDatabaseAccessor extends 
DatabaseAccessor<SidecarLeaseS
      */
     public static class LeaseClaimResult
     {
-        public final boolean leaseAcquired;
         public final String currentOwner;
 
-        LeaseClaimResult(boolean leaseAcquired, String currentOwner)
+        LeaseClaimResult(String currentOwner)
         {
-            this.leaseAcquired = leaseAcquired;
             this.currentOwner = currentOwner;
         }
 
         static LeaseClaimResult from(ResultSet resultSet, String newOwner)
         {
             return resultSet.wasApplied()
-                   ? new LeaseClaimResult(true, newOwner)
-                   : new LeaseClaimResult(false, 
resultSet.one().getString("owner"));
+                   ? new LeaseClaimResult(newOwner)
+                   // In some rare cases, the resultSet will not contain the 
owner information
+                   // even though the resultSet was not applied. This will 
translate into an
+                   // IllegalArgumentException being thrown when trying to 
retrieve the non-existing
+                   // owner string. This exception is left to be handled by 
the caller method
+                   : new LeaseClaimResult(resultSet.one().getString("owner"));
         }
     }
 }
diff --git 
a/server/src/main/java/org/apache/cassandra/sidecar/modules/CoordinationModule.java
 
b/server/src/main/java/org/apache/cassandra/sidecar/modules/CoordinationModule.java
index b1a3b81f..c291af0c 100644
--- 
a/server/src/main/java/org/apache/cassandra/sidecar/modules/CoordinationModule.java
+++ 
b/server/src/main/java/org/apache/cassandra/sidecar/modules/CoordinationModule.java
@@ -28,7 +28,6 @@ import 
org.apache.cassandra.sidecar.config.SidecarConfiguration;
 import org.apache.cassandra.sidecar.coordination.ClusterLease;
 import org.apache.cassandra.sidecar.coordination.ClusterLeaseClaimTask;
 import org.apache.cassandra.sidecar.coordination.ElectorateMembership;
-import 
org.apache.cassandra.sidecar.coordination.MostReplicatedKeyspaceTokenZeroElectorateMembership;
 import org.apache.cassandra.sidecar.db.SidecarLeaseDatabaseAccessor;
 import org.apache.cassandra.sidecar.db.schema.SidecarLeaseSchema;
 import org.apache.cassandra.sidecar.db.schema.TableSchema;
@@ -70,6 +69,6 @@ public class CoordinationModule extends AbstractModule
                                               CQLSessionProvider 
cqlSessionProvider,
                                               SidecarConfiguration 
configuration)
     {
-        return new 
MostReplicatedKeyspaceTokenZeroElectorateMembership(instanceMetadataFetcher, 
cqlSessionProvider, configuration);
+        return new 
ElectorateMembershipFactory().create(instanceMetadataFetcher, 
cqlSessionProvider, configuration);
     }
 }
diff --git 
a/server/src/main/java/org/apache/cassandra/sidecar/modules/ElectorateMembershipFactory.java
 
b/server/src/main/java/org/apache/cassandra/sidecar/modules/ElectorateMembershipFactory.java
new file mode 100644
index 00000000..401e68b3
--- /dev/null
+++ 
b/server/src/main/java/org/apache/cassandra/sidecar/modules/ElectorateMembershipFactory.java
@@ -0,0 +1,62 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.cassandra.sidecar.modules;
+
+import org.apache.cassandra.sidecar.common.server.CQLSessionProvider;
+import org.apache.cassandra.sidecar.config.SidecarConfiguration;
+import org.apache.cassandra.sidecar.coordination.ElectorateMembership;
+import 
org.apache.cassandra.sidecar.coordination.MostReplicatedKeyspaceTokenZeroElectorateMembership;
+import 
org.apache.cassandra.sidecar.coordination.SidecarInternalTokenZeroElectorateMembership;
+import org.apache.cassandra.sidecar.exceptions.ConfigurationException;
+import org.apache.cassandra.sidecar.utils.InstanceMetadataFetcher;
+
+/**
+ * Factory class to initialize the {@link 
org.apache.cassandra.sidecar.coordination.ElectorateMembership} instance
+ * based on the configured strategy
+ */
+public class ElectorateMembershipFactory
+{
+    /**
+     * Creates the {@link ElectorateMembership} based on the strategy 
configuration
+     *
+     * @param fetcher         the interface to retrieve instance metadata
+     * @param sessionProvider the provider for the CQL session
+     * @param config          the configuration for running Sidecar
+     * @return the created {@link ElectorateMembership} instance
+     * @throws ConfigurationException when an invalid strategy is used
+     */
+    public ElectorateMembership create(InstanceMetadataFetcher fetcher,
+                                       CQLSessionProvider sessionProvider,
+                                       SidecarConfiguration config)
+    {
+        String strategy = config.serviceConfiguration()
+                                .coordinationConfiguration()
+                                .clusterLeaseClaimConfiguration()
+                                .electorateMembershipStrategy();
+        switch (strategy)
+        {
+            case "MostReplicatedKeyspaceTokenZeroElectorateMembership":
+                return new 
MostReplicatedKeyspaceTokenZeroElectorateMembership(fetcher, sessionProvider, 
config);
+            case "SidecarInternalTokenZeroElectorateMembership":
+                return new 
SidecarInternalTokenZeroElectorateMembership(fetcher, config);
+            default:
+                throw new ConfigurationException("Invalid electorate 
membership strategy value '" + strategy + "'");
+        }
+    }
+}
diff --git 
a/server/src/test/integration/org/apache/cassandra/sidecar/coordination/MostReplicatedKeyspaceTokenZeroElectorateMembershipIntegrationTest.java
 
b/server/src/test/integration/org/apache/cassandra/sidecar/coordination/MostReplicatedKeyspaceTokenZeroElectorateMembershipIntegrationTest.java
index b6a4c151..82759a45 100644
--- 
a/server/src/test/integration/org/apache/cassandra/sidecar/coordination/MostReplicatedKeyspaceTokenZeroElectorateMembershipIntegrationTest.java
+++ 
b/server/src/test/integration/org/apache/cassandra/sidecar/coordination/MostReplicatedKeyspaceTokenZeroElectorateMembershipIntegrationTest.java
@@ -20,6 +20,7 @@ package org.apache.cassandra.sidecar.coordination;
 
 import java.io.IOException;
 import java.net.InetSocketAddress;
+import java.util.AbstractMap;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
@@ -79,6 +80,7 @@ class 
MostReplicatedKeyspaceTokenZeroElectorateMembershipIntegrationTest
     Vertx vertx = Vertx.vertx();
     DriverUtils driverUtils = new DriverUtils();
     CassandraVersionProvider cassandraVersionProvider = 
cassandraVersionProvider(DnsResolver.DEFAULT);
+    MetricRegistryFactory metricRegistryProvider = new 
MetricRegistryFactory("cassandra_sidecar", List.of(), List.of());
 
     @ParameterizedTest(name = "{index} => version {0}")
     
@MethodSource("org.apache.cassandra.testing.TestVersionSupplier#testVersions")
@@ -107,12 +109,18 @@ class 
MostReplicatedKeyspaceTokenZeroElectorateMembershipIntegrationTest
 
     private void runTestScenario(AbstractCluster<?> cluster)
     {
-        List<MostReplicatedKeyspaceTokenZeroElectorateMembership> memberships 
= buildElectorateMembershipPerCassandraInstance(cluster);
+        AbstractMap.SimpleEntry<List<? extends ElectorateMembership>, List<? 
extends ElectorateMembership>> pair
+        = buildElectorateMembershipPerCassandraInstance(cluster);
+        List<? extends ElectorateMembership> mostReplicatedMemberships = 
pair.getKey();
+        List<? extends ElectorateMembership> sidecarInternalMemberships = 
pair.getValue();
         // When there are no user keyspaces, we default to the 
sidecar_internal keyspace
         // and therefore guaranteeing that we have at least one keyspace to 
use for the
         // determination of the membership, and that's why we expect the 
membership count
         // to be one, even if we have not created user keyspaces yet.
-        assertMembership(memberships, 1);
+        assertMembership(mostReplicatedMemberships, 1);
+        // For the sidecar internal keyspace based membership, the membership 
count will
+        // always be the same.
+        assertMembership(sidecarInternalMemberships, 1);
 
         // Now let's create keyspaces with RF 1-3 replicated in a single DC 
and validate
         String dc0 = "dc0";
@@ -121,7 +129,10 @@ class 
MostReplicatedKeyspaceTokenZeroElectorateMembershipIntegrationTest
             cluster.schemaChange(String.format("CREATE KEYSPACE ks_dc0_%d WITH 
REPLICATION={'class':'NetworkTopologyStrategy','%s':%d}", rf, dc0, rf));
             // introduce delay until schema change information propagates
             sleepUninterruptibly(10, TimeUnit.SECONDS);
-            assertMembership(memberships, rf);
+            assertMembership(mostReplicatedMemberships, rf);
+            // For the sidecar internal keyspace based membership, the 
membership count will
+            // always be the same.
+            assertMembership(sidecarInternalMemberships, 1);
         }
 
         // Now let's create keyspaces with RF 1-4 replicated in DC2 and 
validate
@@ -133,7 +144,10 @@ class 
MostReplicatedKeyspaceTokenZeroElectorateMembershipIntegrationTest
             cluster.schemaChange(String.format("CREATE KEYSPACE ks_dc1_%d WITH 
REPLICATION={'class':'NetworkTopologyStrategy','%s':%d}", rf, dc1, rf));
             // introduce delay until schema change information propagates
             sleepUninterruptibly(10, TimeUnit.SECONDS);
-            assertMembership(memberships, Math.max(3, rf));
+            assertMembership(mostReplicatedMemberships, Math.max(3, rf));
+            // For the sidecar internal keyspace based membership, the 
membership count will
+            // always be the same.
+            assertMembership(sidecarInternalMemberships, 1);
         }
 
         // Now let's create a keyspace with RF=3 replicated across both DCs
@@ -142,13 +156,16 @@ class 
MostReplicatedKeyspaceTokenZeroElectorateMembershipIntegrationTest
         sleepUninterruptibly(10, TimeUnit.SECONDS);
         // We expect the same instances in the existing keyspaces to own token 
0 as the new keyspace
         // so a total of 6 instances own token 0, 3 on each DC.
-        assertMembership(memberships, 6);
+        assertMembership(mostReplicatedMemberships, 6);
+        // For the sidecar internal keyspace based membership, the membership 
count will
+        // always be the same.
+        assertMembership(sidecarInternalMemberships, 1);
     }
 
-    static void 
assertMembership(List<MostReplicatedKeyspaceTokenZeroElectorateMembership> 
memberships, int expectedElectorateSize)
+    static void assertMembership(List<? extends ElectorateMembership> 
memberships, int expectedElectorateSize)
     {
         int localElectorateCount = 0;
-        for (MostReplicatedKeyspaceTokenZeroElectorateMembership membership : 
memberships)
+        for (ElectorateMembership membership : memberships)
         {
             boolean shouldParticipate = membership.isMember();
             if (shouldParticipate)
@@ -160,13 +177,13 @@ class 
MostReplicatedKeyspaceTokenZeroElectorateMembershipIntegrationTest
                                         .isEqualTo(expectedElectorateSize);
     }
 
-    List<MostReplicatedKeyspaceTokenZeroElectorateMembership> 
buildElectorateMembershipPerCassandraInstance(AbstractCluster<?> cluster)
+    AbstractMap.SimpleEntry<List<? extends ElectorateMembership>, List<? 
extends ElectorateMembership>>
+    buildElectorateMembershipPerCassandraInstance(AbstractCluster<?> cluster)
     {
-        MetricRegistryFactory metricRegistryProvider = new 
MetricRegistryFactory("cassandra_sidecar",
-                                                                               
  Collections.emptyList(),
-                                                                               
  Collections.emptyList());
-
-        List<MostReplicatedKeyspaceTokenZeroElectorateMembership> result = new 
ArrayList<>();
+        List<MostReplicatedKeyspaceTokenZeroElectorateMembership> r1 = new 
ArrayList<>();
+        List<SidecarInternalTokenZeroElectorateMembership> r2 = new 
ArrayList<>();
+        AbstractMap.SimpleEntry<List<? extends ElectorateMembership>, List<? 
extends ElectorateMembership>> result
+        = new AbstractMap.SimpleEntry<>(r1, r2);
         for (IInstance instance : cluster)
         {
             List<InetSocketAddress> address = buildContactList(instance);
@@ -174,7 +191,8 @@ class 
MostReplicatedKeyspaceTokenZeroElectorateMembershipIntegrationTest
             new CQLSessionProviderImpl(address, address, 500, 
instance.config().localDatacenter(), 0, SharedExecutorNettyOptions.INSTANCE);
             InstancesMetadata instancesMetadata = 
buildInstancesMetadata(instance, sessionProvider, metricRegistryProvider);
             InstanceMetadataFetcher instanceMetadataFetcher = new 
InstanceMetadataFetcher(instancesMetadata);
-            result.add(new 
MostReplicatedKeyspaceTokenZeroElectorateMembership(instanceMetadataFetcher, 
sessionProvider, CONFIG));
+            r1.add(new 
MostReplicatedKeyspaceTokenZeroElectorateMembership(instanceMetadataFetcher, 
sessionProvider, CONFIG));
+            r2.add(new 
SidecarInternalTokenZeroElectorateMembership(instanceMetadataFetcher, CONFIG));
         }
         return result;
     }
diff --git 
a/server/src/test/integration/org/apache/cassandra/sidecar/testing/IntegrationTestModule.java
 
b/server/src/test/integration/org/apache/cassandra/sidecar/testing/IntegrationTestModule.java
index 2f0560ab..16a0438e 100644
--- 
a/server/src/test/integration/org/apache/cassandra/sidecar/testing/IntegrationTestModule.java
+++ 
b/server/src/test/integration/org/apache/cassandra/sidecar/testing/IntegrationTestModule.java
@@ -45,6 +45,7 @@ import 
org.apache.cassandra.sidecar.config.SidecarConfiguration;
 import org.apache.cassandra.sidecar.config.SslConfiguration;
 import org.apache.cassandra.sidecar.config.yaml.AccessControlConfigurationImpl;
 import org.apache.cassandra.sidecar.config.yaml.CacheConfigurationImpl;
+import 
org.apache.cassandra.sidecar.config.yaml.ClusterLeaseClaimConfigurationImpl;
 import org.apache.cassandra.sidecar.config.yaml.CoordinationConfigurationImpl;
 import org.apache.cassandra.sidecar.config.yaml.KeyStoreConfigurationImpl;
 import 
org.apache.cassandra.sidecar.config.yaml.ParameterizedClassConfigurationImpl;
@@ -204,9 +205,13 @@ public class IntegrationTestModule extends AbstractModule
     @Singleton
     public CoordinationConfiguration clusterLeaseClaimTaskConfiguration()
     {
-        return new CoordinationConfigurationImpl(new 
PeriodicTaskConfigurationImpl(true,
-                                                                               
    MillisecondBoundConfiguration.parse("1s"),
-                                                                               
    MillisecondBoundConfiguration.parse("1s")));
+        ClusterLeaseClaimConfigurationImpl configuration
+        = ClusterLeaseClaimConfigurationImpl.builder()
+                                            
.overridePeriodicTaskConfiguration(b -> b.enabled(true)
+                                                                               
      .initialDelay(MillisecondBoundConfiguration.parse("1s"))
+                                                                               
      .executeInterval(MillisecondBoundConfiguration.parse("1s")))
+                                            .build();
+        return new CoordinationConfigurationImpl(configuration);
     }
 
     @Provides
diff --git 
a/server/src/test/java/org/apache/cassandra/sidecar/config/SidecarConfigurationTest.java
 
b/server/src/test/java/org/apache/cassandra/sidecar/config/SidecarConfigurationTest.java
index 2eb1ffdf..cf75bb7d 100644
--- 
a/server/src/test/java/org/apache/cassandra/sidecar/config/SidecarConfigurationTest.java
+++ 
b/server/src/test/java/org/apache/cassandra/sidecar/config/SidecarConfigurationTest.java
@@ -228,7 +228,7 @@ class SidecarConfigurationTest
         assertThat(configuration.replicationFactor()).isEqualTo(3);
         assertThat(configuration.createReplicationStrategyString())
         .isEqualTo("{'class':'SimpleStrategy', 'replication_factor':'3'}");
-        assertThat(configuration.leaseSchemaTTL().toSeconds()).isEqualTo(120);
+        assertThat(configuration.leaseSchemaTTL().toSeconds()).isEqualTo(300L);
     }
 
     @Test
@@ -427,17 +427,49 @@ class SidecarConfigurationTest
     @Test
     void testCoordinationConfiguration() throws Exception
     {
-        Path yamlPath = yaml("config/sidecar_coordination.yaml");
-        SidecarConfiguration config = 
SidecarConfigurationImpl.readYamlConfiguration(yamlPath);
+        String yaml = "sidecar:\n" +
+                      "  coordination:\n" +
+                      "    cluster_lease_claim:\n" +
+                      "      electorate_membership_strategy: 
SidecarInternalTokenZeroElectorateMembership\n" +
+                      "      enabled: false\n" +
+                      "      initial_delay: 5s\n" +
+                      "      execute_interval: 31s\n" +
+                      "      initial_delay_random_delta: 10s";
+        SidecarConfiguration config = 
SidecarConfigurationImpl.fromYamlString(yaml);
+        ServiceConfiguration serviceConfiguration = 
config.serviceConfiguration();
+        assertThat(serviceConfiguration).isNotNull();
+
+        CoordinationConfiguration coordinationConfiguration = 
serviceConfiguration.coordinationConfiguration();
+        assertThat(coordinationConfiguration).isNotNull();
+        ClusterLeaseClaimConfiguration clusterLeaseConfig = 
coordinationConfiguration.clusterLeaseClaimConfiguration();
+        assertThat(clusterLeaseConfig.enabled()).isFalse();
+        
assertThat(clusterLeaseConfig.initialDelay().toMillis()).isEqualTo(5_000L);
+        
assertThat(clusterLeaseConfig.executeInterval().toMillis()).isEqualTo(31_000L);
+        
assertThat(clusterLeaseConfig.initialDelayRandomDelta().toMillis()).isEqualTo(10_000L);
+        assertThat(clusterLeaseConfig.randomDeltaDelayMillis()).isBetween(0L, 
10_000L);
+        
assertThat(clusterLeaseConfig.electorateMembershipStrategy()).isEqualTo("SidecarInternalTokenZeroElectorateMembership");
+    }
+
+    @Test
+    void testCoordinationDefaultElectorateMembershipStrategy() throws Exception
+    {
+        String yaml = "sidecar:\n" +
+                      "  coordination:\n" +
+                      "    cluster_lease_claim:\n" +
+                      "      enabled: false\n" +
+                      "      initial_delay: 5s\n" +
+                      "      execute_interval: 31s";
+        SidecarConfiguration config = 
SidecarConfigurationImpl.fromYamlString(yaml);
         ServiceConfiguration serviceConfiguration = 
config.serviceConfiguration();
         assertThat(serviceConfiguration).isNotNull();
 
         CoordinationConfiguration coordinationConfiguration = 
serviceConfiguration.coordinationConfiguration();
         assertThat(coordinationConfiguration).isNotNull();
-        PeriodicTaskConfiguration periodicTaskConfig = 
coordinationConfiguration.clusterLeaseClaimConfiguration();
-        assertThat(periodicTaskConfig.enabled()).isFalse();
-        
assertThat(periodicTaskConfig.initialDelay().toMillis()).isEqualTo(5_000L);
-        
assertThat(periodicTaskConfig.executeInterval().toMillis()).isEqualTo(31_000L);
+        ClusterLeaseClaimConfiguration clusterLeaseConfig = 
coordinationConfiguration.clusterLeaseClaimConfiguration();
+        assertThat(clusterLeaseConfig.enabled()).isFalse();
+        
assertThat(clusterLeaseConfig.initialDelay().toMillis()).isEqualTo(5_000L);
+        
assertThat(clusterLeaseConfig.executeInterval().toMillis()).isEqualTo(31_000L);
+        
assertThat(clusterLeaseConfig.electorateMembershipStrategy()).isEqualTo("MostReplicatedKeyspaceTokenZeroElectorateMembership");
     }
 
     void validateSingleInstanceSidecarConfiguration(SidecarConfiguration 
config)
@@ -622,10 +654,13 @@ class SidecarConfigurationTest
         // Validate default configuration
         CoordinationConfiguration coordinationConfiguration = 
serviceConfiguration.coordinationConfiguration();
         assertThat(coordinationConfiguration).isNotNull();
-        PeriodicTaskConfiguration periodicTaskConfig = 
coordinationConfiguration.clusterLeaseClaimConfiguration();
-        assertThat(periodicTaskConfig.enabled()).isTrue();
-        
assertThat(periodicTaskConfig.executeInterval().toMillis()).isEqualTo(60_000L);
-        
assertThat(periodicTaskConfig.initialDelay().toMillis()).isEqualTo(1_000L);
+        ClusterLeaseClaimConfiguration clusterLeaseConfig = 
coordinationConfiguration.clusterLeaseClaimConfiguration();
+        assertThat(clusterLeaseConfig.enabled()).isTrue();
+        
assertThat(clusterLeaseConfig.executeInterval().toMillis()).isEqualTo(100_000L);
+        
assertThat(clusterLeaseConfig.initialDelay().toMillis()).isEqualTo(1_000L);
+        
assertThat(clusterLeaseConfig.initialDelayRandomDelta().toMillis()).isEqualTo(30_000L);
+        assertThat(clusterLeaseConfig.randomDeltaDelayMillis()).isBetween(0L, 
30_000L);
+        
assertThat(clusterLeaseConfig.electorateMembershipStrategy()).isEqualTo("MostReplicatedKeyspaceTokenZeroElectorateMembership");
     }
 
     private void 
validateHealthCheckConfigurationFromYaml(PeriodicTaskConfiguration config)
diff --git 
a/server/src/test/java/org/apache/cassandra/sidecar/coordination/ClusterLeaseClaimTaskTest.java
 
b/server/src/test/java/org/apache/cassandra/sidecar/coordination/ClusterLeaseClaimTaskTest.java
index 1ea1888f..78c745d5 100644
--- 
a/server/src/test/java/org/apache/cassandra/sidecar/coordination/ClusterLeaseClaimTaskTest.java
+++ 
b/server/src/test/java/org/apache/cassandra/sidecar/coordination/ClusterLeaseClaimTaskTest.java
@@ -112,20 +112,26 @@ class ClusterLeaseClaimTaskTest
 
     @ParameterizedTest(name = "{index} => configuredInitialDelay {0} millis")
     @ValueSource(longs = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 })
-    void testInitialDelayFromConfiguration(long configuredDelayMillis)
+    void testRandomizedInitialDelayFromConfiguration(long 
configuredDelayMillis)
     {
         ServiceConfiguration mockServiceConfiguration = 
mock(ServiceConfiguration.class, RETURNS_DEEP_STUBS);
         
when(mockServiceConfiguration.coordinationConfiguration().clusterLeaseClaimConfiguration().initialDelay().quantity())
         .thenReturn(configuredDelayMillis);
         
when(mockServiceConfiguration.coordinationConfiguration().clusterLeaseClaimConfiguration().initialDelay().unit())
         .thenReturn(TimeUnit.MILLISECONDS);
+        
when(mockServiceConfiguration.coordinationConfiguration().clusterLeaseClaimConfiguration().initialDelay().toMillis())
+        .thenCallRealMethod();
         
when(mockServiceConfiguration.coordinationConfiguration().clusterLeaseClaimConfiguration().initialDelay().to(TimeUnit.MILLISECONDS))
         .thenCallRealMethod();
+        
when(mockServiceConfiguration.coordinationConfiguration().clusterLeaseClaimConfiguration().randomDeltaDelayMillis())
+        .thenCallRealMethod();
+        
when(mockServiceConfiguration.coordinationConfiguration().clusterLeaseClaimConfiguration().initialDelayRandomDelta().toMillis())
+        .thenReturn(30_000L);
         ClusterLeaseClaimTask task = new 
ClusterLeaseClaimTask(mockServiceConfiguration, 
mock(ElectorateMembership.class),
                                                                
mock(SidecarLeaseDatabaseAccessor.class), new ClusterLease(),
                                                                
mock(SidecarMetrics.class, RETURNS_DEEP_STUBS));
 
-        
assertThat(task.initialDelay().to(TimeUnit.MILLISECONDS)).isEqualTo(configuredDelayMillis);
+        
assertThat(task.initialDelay().to(TimeUnit.MILLISECONDS)).isBetween(configuredDelayMillis,
 configuredDelayMillis + 30_000L);
     }
 
     @ParameterizedTest(name = "{index} => configuredDelayMillis {0} millis")
diff --git 
a/server/src/test/java/org/apache/cassandra/sidecar/db/SidecarSchemaTest.java 
b/server/src/test/java/org/apache/cassandra/sidecar/db/SidecarSchemaTest.java
index 9b6db6f5..e0271b77 100644
--- 
a/server/src/test/java/org/apache/cassandra/sidecar/db/SidecarSchemaTest.java
+++ 
b/server/src/test/java/org/apache/cassandra/sidecar/db/SidecarSchemaTest.java
@@ -184,9 +184,9 @@ public class SidecarSchemaTest
             "WHERE job_id = ? AND bucket_id = ? AND start_token = ? AND 
end_token = ?",
 
             "INSERT INTO sidecar_internal.sidecar_lease_v1 (name,owner) " +
-            "VALUES ('cluster_lease_holder',?) IF NOT EXISTS USING TTL 120",
+            "VALUES ('cluster_lease_holder',?) IF NOT EXISTS USING TTL 300",
 
-            "UPDATE sidecar_internal.sidecar_lease_v1 USING TTL 120 SET owner 
= ? " +
+            "UPDATE sidecar_internal.sidecar_lease_v1 USING TTL 300 SET owner 
= ? " +
             "WHERE name = 'cluster_lease_holder' IF owner = ?",
 
             "SELECT * FROM sidecar_internal.role_permissions_v1",
diff --git 
a/server/src/test/java/org/apache/cassandra/sidecar/modules/ElectorateMembershipFactoryTest.java
 
b/server/src/test/java/org/apache/cassandra/sidecar/modules/ElectorateMembershipFactoryTest.java
new file mode 100644
index 00000000..46c5cfb5
--- /dev/null
+++ 
b/server/src/test/java/org/apache/cassandra/sidecar/modules/ElectorateMembershipFactoryTest.java
@@ -0,0 +1,93 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.cassandra.sidecar.modules;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.ValueSource;
+
+import org.apache.cassandra.sidecar.common.server.CQLSessionProvider;
+import org.apache.cassandra.sidecar.config.SidecarConfiguration;
+import org.apache.cassandra.sidecar.coordination.ElectorateMembership;
+import 
org.apache.cassandra.sidecar.coordination.MostReplicatedKeyspaceTokenZeroElectorateMembership;
+import 
org.apache.cassandra.sidecar.coordination.SidecarInternalTokenZeroElectorateMembership;
+import org.apache.cassandra.sidecar.exceptions.ConfigurationException;
+import org.apache.cassandra.sidecar.utils.InstanceMetadataFetcher;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
+import static org.mockito.Mockito.RETURNS_DEEP_STUBS;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+/**
+ * Unit tests for the {@link ElectorateMembershipFactory} class
+ */
+class ElectorateMembershipFactoryTest
+{
+    private ElectorateMembershipFactory factory;
+
+    @BeforeEach
+    void setup()
+    {
+        factory = new ElectorateMembershipFactory();
+    }
+
+    @ParameterizedTest(name = "{index} => strategy=\"{0}\"")
+    @ValueSource(strings = { "invalid", "", "a" })
+    void testInvalidStrategy(String strategy)
+    {
+        SidecarConfiguration config = mock(SidecarConfiguration.class, 
RETURNS_DEEP_STUBS);
+        when(config.serviceConfiguration()
+                   .coordinationConfiguration()
+                   .clusterLeaseClaimConfiguration()
+                   .electorateMembershipStrategy()).thenReturn(strategy);
+
+        assertThatExceptionOfType(ConfigurationException.class)
+        .isThrownBy(() -> factory.create(mock(InstanceMetadataFetcher.class), 
mock(CQLSessionProvider.class), config))
+        .withMessage("Invalid electorate membership strategy value '" + 
strategy + "'");
+    }
+
+    @Test
+    void testMostReplicatedKeyspaceTokenZeroElectorateMembership()
+    {
+        SidecarConfiguration config = mock(SidecarConfiguration.class, 
RETURNS_DEEP_STUBS);
+        when(config.serviceConfiguration()
+                   .coordinationConfiguration()
+                   .clusterLeaseClaimConfiguration()
+                   
.electorateMembershipStrategy()).thenReturn(MostReplicatedKeyspaceTokenZeroElectorateMembership.class.getSimpleName());
+
+        ElectorateMembership electorateMembership = 
factory.create(mock(InstanceMetadataFetcher.class), 
mock(CQLSessionProvider.class), config);
+        
assertThat(electorateMembership).isInstanceOf(MostReplicatedKeyspaceTokenZeroElectorateMembership.class);
+    }
+
+    @Test
+    void testSidecarInternalTokenZeroElectorateMembership()
+    {
+        SidecarConfiguration config = mock(SidecarConfiguration.class, 
RETURNS_DEEP_STUBS);
+        when(config.serviceConfiguration()
+                   .coordinationConfiguration()
+                   .clusterLeaseClaimConfiguration()
+                   
.electorateMembershipStrategy()).thenReturn(SidecarInternalTokenZeroElectorateMembership.class.getSimpleName());
+
+        ElectorateMembership electorateMembership = 
factory.create(mock(InstanceMetadataFetcher.class), 
mock(CQLSessionProvider.class), config);
+        
assertThat(electorateMembership).isInstanceOf(SidecarInternalTokenZeroElectorateMembership.class);
+    }
+}
diff --git a/server/src/test/resources/config/sidecar_coordination.yaml 
b/server/src/test/resources/config/sidecar_coordination.yaml
deleted file mode 100644
index 59cae9dc..00000000
--- a/server/src/test/resources/config/sidecar_coordination.yaml
+++ /dev/null
@@ -1,247 +0,0 @@
-#
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements.  See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership.  The ASF licenses this file
-# to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance
-# with the License.  You may obtain a copy of the License at
-#
-#     http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-#
-# Cassandra SideCar configuration file
-#
-cassandra_instances:
-  - id: 1
-    host: localhost1
-    port: 9042
-    storage_dir: /ccm/test/node1
-    data_dirs:
-      - ~/.ccm/test/node1/data0
-    staging_dir: ~/.ccm/test/node1/sstable-staging
-    jmx_host: 127.0.0.1
-    jmx_port: 7100
-    jmx_ssl_enabled: false
-#    jmx_role:
-#    jmx_role_password:
-  - id: 2
-    host: localhost2
-    port: 9042
-    storage_dir: /ccm/test/node2
-    data_dirs:
-      - ~/.ccm/test/node2/data0
-    staging_dir: ~/.ccm/test/node2/sstable-staging
-    jmx_host: 127.0.0.1
-    jmx_port: 7200
-    jmx_ssl_enabled: false
-#    jmx_role:
-#    jmx_role_password:
-  - id: 3
-    host: localhost3
-    port: 9042
-    storage_dir: /ccm/test/node3
-    data_dirs:
-      - ~/.ccm/test/node3/data0
-    staging_dir: ~/.ccm/test/node3/sstable-staging
-    jmx_host: 127.0.0.1
-    jmx_port: 7300
-    jmx_ssl_enabled: false
-#    jmx_role:
-#    jmx_role_password:
-
-sidecar:
-  host: 0.0.0.0
-  port: 9043
-  request_idle_timeout: 5m
-  request_timeout: 5m
-  tcp_keep_alive: false
-  accept_backlog: 1024
-  server_verticle_instances: 1
-  throttle:
-    stream_requests_per_sec: 5000
-    timeout: 10s
-  traffic_shaping:
-    inbound_global_bandwidth_bps: 0               # 0 implies unthrottled, the 
inbound bandwidth in bytes per second
-    outbound_global_bandwidth_bps: 0              # 0 implies unthrottled, the 
outbound bandwidth in bytes per second
-    peak_outbound_global_bandwidth_bps: 419430400 # the peak outbound 
bandwidth in bytes per second. The default is 400 mebibytes per second
-    max_delay_to_wait: 15s                        # 15 seconds
-    check_interval_for_stats: 1s                  # 1 second
-    inbound_global_file_bandwidth_bps: 0          # 0 implies unthrottled, the 
inbound bandwidth allocated for incoming files in bytes per second, 
upper-bounded by inbound_global_bandwidth_bps
-  sstable_upload:
-    concurrent_upload_limit: 80
-    min_free_space_percent: 10
-    # file_permissions: "rw-r--r--" # when not specified, the default file 
permissions are owner read & write, group & others read
-  allowable_time_skew: 1h
-  sstable_import:
-    execute_interval: 100ms
-    cache:
-      expire_after_access: 2h # 2 hours
-      maximum_size: 10000
-  sstable_snapshot:
-    snapshot_list_cache:
-      expire_after_access: 2h # 2 hours
-      maximum_size: 10000
-  worker_pools:
-    service:
-      name: "sidecar-worker-pool"
-      size: 20
-      max_execution_time: 1m # 1 minute
-    internal:
-      name: "sidecar-internal-worker-pool"
-      size: 20
-      max_execution_time: 15m # 15 minutes
-  jmx:
-    max_retries: 3
-    retry_delay: 200ms
-  schema:
-    is_enabled: false
-    keyspace: sidecar_internal
-    replication_strategy: SimpleStrategy
-    replication_factor: 1
-    lease_schema_ttl_sec: 120
-  coordination:
-    cluster_lease_claim:
-      enabled: false
-      initial_delay: 5s
-      execute_interval: 31s
-
-vertx:
-  filesystem_options:
-    classpath_resolving_enabled: false
-    file_caching_enabled: false
-
-#
-# Enable SSL configuration (Disabled by default)
-#
-#  ssl:
-#    enabled: true
-#    use_openssl: true
-#    handshake_timeout: 10s
-#    client_auth: NONE # valid options are NONE, REQUEST, REQUIRED
-#    accepted_protocols:
-#     - TLSv1.2
-#     - TLSv1.3
-#    cipher_suites: []
-#    keystore:
-#      type: PKCS12
-#      path: "path/to/keystore.p12"
-#      password: password
-#      check_interval: 5m
-#    truststore:
-#      path: "path/to/truststore.p12"
-#      password: password
-
-access_control:
-  # When enabled requests need to be authenticated and authorized before 
servicing.
-  enabled: false
-  # Supports setting multiple authenticators, request is authenticated if it 
is authenticated by any of the
-  # configured authenticators
-  authenticators:
-    - class_name: 
org.apache.cassandra.sidecar.acl.authentication.MutualTlsAuthenticationHandlerFactory
-      parameters:
-        # Certificate validator is used to validate details within a 
certificate, such as issuer organization,
-        # issuer country, CNs, certificate expiry etc.
-        #
-        # io.vertx.ext.auth.mtls.impl.AllowAllCertificateValidator performs no 
checks, it marks all certificates as valid.
-        # other options are, 
io.vertx.ext.auth.mtls.impl.CertificateValidatorImpl
-        certificate_validator: 
io.vertx.ext.auth.mtls.impl.AllowAllCertificateValidator
-        # CertificateIdentityExtractor is used to extract valid identities 
from certificates. These identities will be
-        # used for authorizing users.
-        #
-        # 
org.apache.cassandra.sidecar.acl.authentication.CassandraIdentityExtractor 
verifies that identity
-        # extracted from certificate is present in identity_to_role table. 
Identities in identity_to_role table in
-        # Cassandra are authenticated identities in Cassandra.
-        #
-        # other options are, 
io.vertx.ext.auth.mtls.impl.SpiffeIdentityExtractor.
-        certificate_identity_extractor: 
org.apache.cassandra.sidecar.acl.authentication.CassandraIdentityExtractor
-  # Identities that are authenticated and authorized.
-  admin_identities:
-#    - spiffe://authorized/admin/identities
-  permission_cache:
-    enabled: true
-    expire_after_access: 5m
-    maximum_size: 1000
-    warmup_retries: 5
-    warmup_retry_interval: 2s
-
-driver_parameters:
-  contact_points:
-    - "127.0.0.1:9042"
-    - "127.0.0.2:9042"
-  username: cassandra
-  password: cassandra
-  ssl:
-    enabled: false
-    keystore:
-      type: PKCS12
-      path: path/to/keystore.p12
-      password: password
-    truststore:
-      type: PKCS12
-      path: path/to/keystore.p12
-      password: password
-  num_connections: 6
-#  local_dc: datacenter1
-
-healthcheck:
-  initial_delay_millis: 0
-  poll_freq_millis: 30000
-
-metrics:
-  registry_name: cassandra_sidecar
-  vertx:
-    enabled: true
-    expose_via_jmx: false
-    jmx_domain_name: sidecar.vertx.jmx_domain
-  include:                                    # empty include list means 
include all
-    - type: "regex"                           # possible filter types are 
"regex" and "equals"
-      value: "Sidecar.*"
-    - type: "regex"
-      value: "vertx.*"
-  exclude:                                    # empty exclude list means 
exclude nothing
-#    - type: "regex"                          # possible filter types are 
"regex" and "equals"
-#      value: "vertx.eventbus.*"              # exclude all metrics starts 
with vertx.eventbus
-
-cassandra_input_validation:
-  forbidden_keyspaces:
-    - system_schema
-    - system_traces
-    - system_distributed
-    - system
-    - system_auth
-    - system_views
-    - system_virtual_schema
-    - sidecar_internal
-  allowed_chars_for_directory: "[a-zA-Z][a-zA-Z0-9_]{0,47}"
-  allowed_chars_for_quoted_name: "[a-zA-Z_0-9]{1,48}"
-  allowed_chars_for_component_name: 
"[a-zA-Z0-9_-]+(.db|.cql|.json|.crc32|TOC.txt)"
-  allowed_chars_for_restricted_component_name: "[a-zA-Z0-9_-]+(.db|TOC.txt)"
-
-blob_restore:
-  job_discovery_active_loop_delay: 5m
-  job_discovery_idle_loop_delay: 10m
-  job_discovery_recency_days: 5
-  slice_process_max_concurrency: 20
-  restore_job_tables_ttl: 90d
-  slow_task_threshold: 10m
-  slow_task_report_delay: 1m
-  ring_topology_refresh_delay: 1m
-
-s3_client:
-  concurrency: 4
-  thread_name_prefix: s3-client
-  thread_keep_alive: 1m
-  api_call_timeout: 1m # 1 minute
-  range_get_object_bytes_size: 5242880  # 5 MiB
-#  proxy_config:
-#    uri:
-#    username:
-#    password:
diff --git a/server/src/test/resources/config/sidecar_multiple_instances.yaml 
b/server/src/test/resources/config/sidecar_multiple_instances.yaml
index ff39ee56..88b17b8e 100644
--- a/server/src/test/resources/config/sidecar_multiple_instances.yaml
+++ b/server/src/test/resources/config/sidecar_multiple_instances.yaml
@@ -115,11 +115,19 @@ sidecar:
   jmx:
     max_retries: 1
     retry_delay: 1234ms
+  schema:
+    is_enabled: false
+    keyspace: sidecar_internal
+    replication_strategy: SimpleStrategy
+    replication_factor: 1
+    lease_schema_ttl: 5m
   coordination:
     cluster_lease_claim:
+      electorate_membership_strategy: 
MostReplicatedKeyspaceTokenZeroElectorateMembership
       enabled: true
       initial_delay: 1s
-      execute_interval: 60s
+      initial_delay_random_delta: 30s
+      execute_interval: 100s
 
 vertx:
   filesystem_options:
diff --git a/server/src/test/resources/config/sidecar_single_instance.yaml 
b/server/src/test/resources/config/sidecar_single_instance.yaml
index a249ffcf..84b0a009 100644
--- a/server/src/test/resources/config/sidecar_single_instance.yaml
+++ b/server/src/test/resources/config/sidecar_single_instance.yaml
@@ -63,11 +63,14 @@ sidecar:
     keyspace: sidecar_internal
     replication_strategy: SimpleStrategy
     replication_factor: 1
+    lease_schema_ttl: 5m
   coordination:
     cluster_lease_claim:
+      electorate_membership_strategy: 
MostReplicatedKeyspaceTokenZeroElectorateMembership
       enabled: true
       initial_delay: 1s
-      execute_interval: 60s
+      initial_delay_random_delta: 30s
+      execute_interval: 100s
 
 #
 # Enable SSL configuration (Disabled by default)


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscr...@cassandra.apache.org
For additional commands, e-mail: commits-h...@cassandra.apache.org

Reply via email to