Leader Job Safety Lab
한국어
Leader Job Safety Lab · Visual Companion

Only the newest worker result reaches PostgreSQL after an expired worker resumes

Leader election only selects who may attempt the work. Redis must issue an ordering token and PostgreSQL must decide whether a delayed mutation is still current.

6operational scenarios
2SAFE / UNSAFE paths
41 → 42fencing tokens during takeover

01 · Problem framing

Successful leader election does not guarantee a safe database mutation

Lease expiry does not stop the old worker thread. After a GC pause, network partition, or long I/O, the old worker can resume and write after the takeover.

Coordination

Leader lease only

It reduces concurrent workers but cannot reject a resumed stale worker.

Resource identity

Lock by job name

Two differently named jobs can still mutate the same business resource.

Outcome recovery

Blind external retry

A new request can duplicate an earlier request whose result is unknown.

Brainstorming: separate the guarantees before selecting mechanisms

Mutual exclusionRedis leader and resource leasesReduce concurrent execution at one moment.
FailoverLease expiry and reacquisitionAllow a new worker to take over.
Stale-write rejectionFencing token + PostgreSQLReject an older generation at commit.
Replay safetyOperationId + idempotencyLook up and retry the same external operation.
Durable completionExposed transaction + outboxCommit business state and follow-up work together.

02 · Solution design

The design separates Redis ordering from PostgreSQL commit decisions

No single component provides all guarantees. Coordination, durable mutation, and external outcome recovery remain separate.

Rejected

Reuse the leader owner token

The owner token is an opaque identifier with no ordering semantics.

Rejected

Let Redis make the final commit decision

Redis lease state can diverge from PostgreSQL business state.

Rejected

Create a new request ID after timeout

Both the unknown first request and the retry may be applied.

Selected

Monotonic fencing token

Every takeover receives a higher generation.

Selected

PostgreSQL conditional update

Mutate only when `incomingFence > lastAcceptedFence`.

Selected

Outbox and original OperationId lookup

Query the same request instead of guessing the result.

03 · Architecture

Redis coordinates execution order and PostgreSQL decides whether to commit

No single component provides all guarantees. Coordination, durable mutation, and external outcome recovery remain separate.

Leader Job Safety Lab components and data flow No single component provides all guarantees. Coordination, durable mutation, and external outcome recovery remain separate. API Coordination Database External effect Caller Operator or scheduler JobSafetyController Scenario API · authorization Request JobRunCoordinator Execution order and leases FencedJobExecutionService Recheck current state and token Run Resource lease · token Redis 8 Coordination state store Leader lease Resource lease + fencing token Leader lease Resource lease · token PostgreSQL 18 + Exposed Final mutation decision Single transaction Outbox Receipt and reconciliation Conditional mutation OutboxEffectWorker Process committed requests External system Idempotent apply · outcome query Claim outbox · record result Stable OperationId · outcome query
APIAPI layer

Scenario selection · SAFE/UNSAFE isolation · authorization

CoordinationCoordination layer

Leader lease · resource lease · fencing-token allocation

PostgreSQLDatabase layer

Current-state recheck · conditional mutation · checkpoint/execution/outbox

Outbox / ProviderExternal-effect layer

Provider call · receipt · reconciliation

04 · Interactive flow

Select a scenario and inspect where the safeguard changes the outcome

Switch the same scenario between SAFE and UNSAFE to find the exact step where the final state diverges.

05 · Source mapping

Concrete classes and tests prove each safeguard

The visible steps are reconstructed from the actual services and deterministic scenario implementation.

Tests that verify the implemented behavior

  • LeaseOverrunScenarioTestReject token 41 and preserve the token-42 result
  • FencedMutationPostgresIntegrationTestReject a stale conditional mutation in PostgreSQL
  • JobSafetyEndToEndIntegrationTestCommit business state, checkpoint, execution, and outbox atomically
  • NonFenceableEffectScenarioTestAvoid duplicate effects with a stable OperationId and reconciliation
  • UnsafeJobSafetyControllerConditionTestIsolate the UNSAFE API behind both profile and property

06 · Run the example

Start the related services and verify the SAFE result first

The example uses JDK 25, a PostgreSQL 18-compatible server, and a Redis 8-compatible server. Run the UNSAFE API only as an isolated comparison.

07 · Boundaries

Problems addressed by the example and remaining limits

Addressed

Delayed database mutation

PostgreSQL rejects a conditional mutation carrying an old fencing token.

Addressed

Configuration changes during execution

The transaction reloads tenant, region, version, and namespace state.

Addressed

Unknown external result

The worker queries the original OperationId and records a receipt.

Limit

Provider has no idempotency key or query API

Exactly-once external effects cannot be guaranteed; manual review or compensation is required.

Limit

Redis counter history is lost

Preserve the counter in backups or advance the namespace epoch.

Limit

Schema migration

The example uses SchemaUtils at startup; production needs Flyway or Liquibase.