`ReplicatedEventSourcedActor` (#37) supports multi-master event sourcing — every replica can persist independently, vector clocks resolve concurrent writes. In most workloads that's the right shape: cross-replica reconciliation via the conflict resolver is the whole point.
But some workloads want single-writer-per-pid-at-a-time semantics — for example, when a downstream side-effect can't be replayed safely, you want exactly one replica writing while the others observe. ClusterSingleton gives this for "one actor cluster-wide" but not for "one writer per persistenceId among the replicas".
Scope:
- Optional `lease: Lease` setting on `ReplicatedEventSourcedActor`.
- On preStart: try to acquire `lease.acquire(persistenceId)`. If it fails, the actor goes into read-only / observer mode (still receives events from other replicas, but won't persist).
- Periodic `lease.renew()` keeps the lease alive.
- On lease loss: switch to observer mode, log loud, optionally trigger a configurable callback.
Use cases:
- Order-processing where a side-effect (charge card) must run exactly once across replicas.
- Heartbeat-emitting actors where N replicas would multiply the rate.
Estimate: 2-3 days.
Related: #38 (ClusterSingleton + Lease, shipped) — same Lease-based pattern, different scope.
`ReplicatedEventSourcedActor` (#37) supports multi-master event sourcing — every replica can persist independently, vector clocks resolve concurrent writes. In most workloads that's the right shape: cross-replica reconciliation via the conflict resolver is the whole point.
But some workloads want single-writer-per-pid-at-a-time semantics — for example, when a downstream side-effect can't be replayed safely, you want exactly one replica writing while the others observe. ClusterSingleton gives this for "one actor cluster-wide" but not for "one writer per persistenceId among the replicas".
Scope:
Use cases:
Estimate: 2-3 days.
Related: #38 (ClusterSingleton + Lease, shipped) — same Lease-based pattern, different scope.