Workers and claims
How independent workers agree, through Arkiv alone, that each rule fires once.
A worker is a program with its own wallet. It reads rules from Arkiv, fires the ones that come due, and writes claims, receipts and a heartbeat back. Workers never talk to each other. They coordinate through claims.
A claim is a 60-second lease
A claim is a trg.claim entity that says "I am firing this rule now". It lives 60 seconds (30 blocks)
and then expires on its own.
- Claim early. 8 blocks before a deadline, a worker writes claims for every rule coming due, in one transaction.
- Agree on a winner. It re-reads the live claims until its own are visible. The claim with the
earliest
$createdAtwins; ties (same block) go to the lowest entity key. Every worker reads the same claims and reaches the same answer. - Act with time to spare. The winner acts only while at least 18 blocks (36 seconds) of its lease remain, extending its own claim first if needed. Actions have a 30-second budget.
- Receipt. It writes the receipt while it still holds the lease.
If the winner crashes, its claim lapses after 30 blocks and another worker takes over. If it restarts while its lease is still live, it resumes the work itself.
Exactly once, at least once
In every test run (two workers racing, a crash mid-lease, 100 rules due at once) each rule fired exactly once. In the worst case (a receipt write delayed past the lease) a rule could fire twice, which is why webhooks carry a stable event ID for de-duplication.
Modes
mode | Fires |
|---|---|
any (default) | Public rules (worker = any) and rules assigned to it |
own | Only rules assigned to it |
A worker without a Telegram bot token skips Telegram rules; one that cannot open a rule's sealed chat records a failure.
One writer per wallet
Everything a worker writes goes through one queue and one transaction at a time, with group commit:
claims, receipts, extensions and its heartbeat are batched into one executeBatch, receipts first.
Parallel writes from one wallet collide on nonces, so the queue is not optional.