Atlas 0.4.0
Released 2026-10-14 · v0.4.0 on GitHub · install with "atlas": "github:AndreyDAraya/atlas#v0.4.0"
Scale out: any number of instances share one database, each consumer (capability or edge subscriber) is delivered by one live instance at a time with automatic failover, and an instance can run API-only. No breaking change: 0.3.0 code keeps working unchanged.
- Consumer leases. A worker loop delivers a consumer only while its instance holds that consumer’s lease; the others stand by and take it over when the owner stops (it releases its leases) or when its lease expires (a dead or unreachable instance), continuing from the cursor. Edge subscribers (push, email, webhooks) no longer run in every instance, so a fact’s side effect is no longer performed once per instance; capability consumers stop wasting work on cursor conflicts.
start({ leaseMs, renewMs })(defaults 30000 / 10000;renewMsmust be shorter,startthrows otherwise). (3347d0c) createRuntime({ instance })andruntime.instance: the lease owner id, a random UUID by default. (3347d0c)start({ workers: false }): an API-only instance runs no consumer loop and no timer loop; dispatch, queries andawait/Atlas-Awaitkeep working against the instances that run workers (an await polls the cursors in the store). (3347d0c)Store.lease?(consumer, owner, ttlMs)andStore.unlease?(consumer, owner), optional: the memory and Postgres stores implement them, the contract suite intest/store-contract.tscovers them. A custom store without them runs every consumer in every instance started with workers, as in 0.3.0. (3347d0c)- Postgres: table
atlas_leases (consumer, owner, expires_at), created bymigrate()(CREATE TABLE IF NOT EXISTS, nothing rewritten); a lease is acquired or renewed with one conditional upsert on the database clock. (3347d0c) - Trace:
warningwith codelease-lostwhen an instance loses a consumer, and afailed(lease)event when a renewal throws. (3347d0c)
Changed
Section titled “Changed”- An edge subscriber’s cursor advances only after its instance renews the lease following the handler; when the lease was lost meanwhile the cursor stays and the new owner delivers the fact again. The remaining at-least-once case is a handler that outlives its lease (a process frozen longer than
leaseMs): dedupe byfact.idstays the contract. (3347d0c) stop()releases the instance’s leases after its loops finish. (3347d0c)
Upgrade
Section titled “Upgrade”Run migrate() on boot as before (it adds atlas_leases). Nothing else changes for one instance. For several: deploy N identical instances, or API instances with start({ workers: false }) plus one or more worker instances; do not call drain() next to running workers (it ignores leases).
From CHANGELOG.md. All versions: Releases.