Skip to content

Shard Owner Election ​

This cookbook shows how to model single-owner work distribution with a lease collection.

When This Pattern Fits ​

Use this pattern when:

  • exactly one node should actively own a key at a time
  • ownership must be renewed or it expires
  • you need fencing-aware transfer or verification
  • another node must be able to take over after expiry

Typical examples:

  • shard ownership
  • active worker selection
  • lease-based leader election per partition
  • collection type: LEASE
  • locator example: shared/worker/shard-owner
  • entity type: immutable LeaseEntity<E> record
  • persistence default: local-durable

Mental Model ​

Shard owner election flow

Lease Timeline ​

Lease lifecycle

Entity Model ​

java
public record ShardOwner(
        String entryKey,
        EntityMetadata metadata,
        LeaseState leaseState)
        implements LeaseEntity<ShardOwner> {

    public static ShardOwner blank(String entryKey) {
        return ...;
    }

    @Override
    public ShardOwner withMetadata(EntityMetadata metadata) {
        return new ShardOwner(entryKey, metadata, leaseState);
    }

    @Override
    public ShardOwner withLeaseState(LeaseState state) {
        return new ShardOwner(entryKey, metadata, state);
    }
}

Registration Pattern ​

java
DsmLeaseRegister<ShardOwner> shardOwners = runtime.leaseRegister(
    LeaseCollectionSpecBuilder.<ShardOwner>lease(
            "shared",
            "worker",
            "shard-owner")
        .schemaId("shard-owner/v1")
        .codec(new ShardOwnerCodec())
        .entityFactory(ShardOwner::blank)
        .leaseTerm(Duration.ofSeconds(10))
        .renewSkew(Duration.ofSeconds(3))
        .expiryGrace(Duration.ofMillis(500))
        .build());

Acquisition Pattern ​

java
LeaseAcquireResult<ShardOwner> acquired = shardOwners.acquire(
        "shard-17",
        LeaseAcquireOptions.defaults())
    .join();

Renewal Pattern ​

java
LeaseRenewResult<ShardOwner> renewed = shardOwners.renew(
        "shard-17",
        LeaseRenewOptions.defaults())
    .join();

Handoff Pattern ​

In a handoff, worker-a transfers shard-17 to worker-b, worker-b becomes the active owner, and downstream systems must stop trusting the old fencing token.

Design Rules ​

  • use one lease key per owned work item
  • keep renewal scheduling comfortably inside the renew-skew window
  • treat fencing tokens as part of the correctness contract for downstream side effects
  • do not use lease state as a generic metadata bag

Common Mistakes ​

Renewing Too Late ​

If renewal is scheduled too close to expiry, transient pauses can cause avoidable ownership churn.

Ignoring Fencing ​

Lease ownership is not just "latest writer wins". Downstream processing should respect the current lease lineage and fencing decision.

Using A Lease For Mergeable Metrics ​

If multiple nodes should contribute to a shared value, use a CRDT instead.

Spring Boot Shape ​

yaml
dsm:
  collections:
    - bean-name: shardOwnersCollection
      tenant-id: shared
      application-id: worker
      collection-id: shard-owner
      schema-id: shard-owner/v1
      type: LEASE
      consistency-tier: LEASE
      codec-bean: shardOwnerCodec
      lease:
        mode: AUTONOMOUS
        term: 10s
        renew-skew: 3s
        expiry-grace: 500ms
        entity-factory-bean: shardOwnerEntityFactory