Give every task one temporary owner.
Name the work. Acquire it before side effects. Renew while it runs. Release when it finishes. If the worker disappears, the lease expires and the task becomes available again.
Election chooses a coordinator. A lock chooses a task owner.
| Your question | Use | Typical work |
|---|---|---|
| Who coordinates this group right now? | /elections | Schedulers, controllers, reconcilers, dispatchers |
| Who owns this exact item right now? | /locks/:name | Jobs, issues, deploys, migrations, customer tasks |
Claim before you change anything.
Use a stable name that every worker can derive from the work itself. One caller receives acquired, a lease ID, and a fencing token. Others receive held and leave the task alone.
curl -s -X POST \
https://your-octostore.internal/locks/invoice-1842/acquire \
-H "Authorization: Bearer $OCTOSTORE_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"ttl_seconds":120,
"metadata":"worker=billing-7 trace=2f91"
}'
The lease is the recovery plan.
A lock is advisory, not magic. Keep downstream operations idempotent and carry the fencing token into systems that can reject a stale owner.
Coordinate a process, not your whole product.
Sessions tie many ephemeral locks to one worker heartbeat and release them together when that worker disappears.
Metadata makes ownership understandable with a runner ID, trace, task URL, branch, or runbook hint.
Watches and webhooks let operators and reconcilers react to acquisition, renewal, release, and expiry.
Hierarchical names keep ownership legible across repos, tenants, queues, and work types.
One binary. One database file. Your boundary.
OctoStore runs as a Rust binary backed by SQLite in WAL mode. Start with static bearer tokens. Add GitHub OAuth only if humans need it. Put TLS and network policy in the reverse proxy you already operate.
curl -fsSL \
https://raw.githubusercontent.com/octostore/octostore.io/main/install.sh \
| sh
STATIC_TOKENS='ops:change-me' \
DATABASE_URL='./octostore.db' \
octostore