bluetape4k Leader
1 → N slots 한국어

Visual companion · Release 0.4.0 · Redis Lettuce

One lock.
One valid leader.

Follow a blocking LeaderElector call from contention to token ownership, lease TTL, protected work, extension, expiry, and token-checked release.

Deterministic lease timeline

Logical ticks explain ordering; they do not model Redis latency.

Ready at tick 0.
Candidates
node-aidle
node-bidle
node-cidle
Redis · conceptual record
invoice-close
TTL —
lockNameinvoice-close
owner
token
expires
Protected action
Waiting for leader

Only a candidate with the current token may enter this boundary.

logical tick 0 waitTime 2 minLeaseTime 1 autoExtend false

Latest ownership events

Tick Candidate Operation Token TTL Outcome

Step 01 · Mental model

A token proves current ownership

The Redis drawing is conceptual: lockName → { owner, token, TTL }. It explains the contract without promising a particular serialized key layout.

Atomic acquire

A missing lock becomes owned by one successful candidate.

Opaque token

Release and extension must present the token that currently owns the lock.

Lease TTL

Ownership disappears after leaseTime unless it is validly extended.

Scoped action

The library runs the action only after acquisition succeeds.

Normal contention does not throw.

A contender that reaches its wait deadline is skipped and the protected action is not called.

Step 02 · Settings

Four times answer four different questions

Change action duration and leaseTime above; scenario presets control the other values.

waitTime

How long a contender may keep trying before it skips. This simulation uses 2 ticks.

leaseTime

How long the current token remains valid after acquire or extension.

minLeaseTime

How long a successful lock remains held even when the action finishes early. It cannot exceed leaseTime.

Action duration

How long business work continues. It may be shorter or longer than the lease.

autoExtend is single-leader support.

The extension preset renews the lease periodically while the elected action remains active.

Step 03 · Direct API

Choose null convenience or an explicit result

val value = elector.runIfLeader("invoice-close") {
    closeInvoices()
}
// elected: action value
// contention: null
when (val result =
    elector.runIfLeaderResult("invoice-close") { closeInvoices() }) {
    is LeaderRunResult.Elected -> showCompleted(result.value)
    LeaderRunResult.Skipped -> showSkipped()
    is LeaderRunResult.ActionFailed -> showFailure(result.cause)
}
LeaderRunResult.Elected

The lock was acquired and the action returned, even when its value is null.

LeaderRunResult.Skipped

The lock was not acquired during normal contention.

LeaderRunResult.ActionFailed

Acquisition succeeded, but the protected action failed.

Acquisition failure

Backend or configuration failures are not relabeled as normal contention.

Step 04 · Spring Boot

The annotation guards the same boundary

@LeaderElection(
    name = "invoice-close",
    waitTime = "PT0.5S",
    leaseTime = "PT10S",
    minLeaseTime = "PT1S",
    autoExtend = true,
)
fun closeInvoices(): CloseSummary? = service.closeInvoices()
AspectJ compile-time weaving

Do not add @EnableAspectJAutoProxy. Kotlin methods do not need to be open, while private methods are not intercepted. A dynamic name must be valid SpEL such as "'invoice-' + #tenantId".

This companion animates the synchronous boundary. The release also supports suspend values, Mono, Flux, and Kotlin Flow. Long streams require autoExtend = true; use streamBounded = true only when completion is guaranteed inside the lease.

Step 05 · Failure and recovery

Expiry can create overlapping business work

Run “Expiry + takeover.” The first action becomes stale after its token expires, while a later candidate acquires a new token and begins valid work.

A lease is not a fencing token for external side effects.

A stale process may still execute code after expiry. Its old token cannot release the successor's lock, but leader election alone cannot undo an external write. Make actions idempotent and use a domain-appropriate fencing or claim mechanism when stale writes must be rejected.

In the extension scenario, the valid owner renews before expiry. In every scenario, release is token-checked: an old owner cannot delete a newer owner's lock.

Release evidence

Pinned to 0.4.0

Claims and links below target release commit 17ab7f8.