The nightly report must be built once, but every replica of the service runs the same scheduler. This is leader election, or a singleton job.
A lock with a lifetime: the worker that gets it builds the report, and the others skip. The report is committed with .guard(lock): the transaction commits only while the lock is still this worker’s. The day in the transactionId is a second fence.
const lock = queen.lock('nightly-report', { ttl: '30s' })
if (!(await lock.acquire({ wait: '1s' }))) return 'skipped' // another worker has it
try {
const report = { day: '2026-10-24', bookings: 412 }
const result = await queen.transaction()
.guard(lock) // commits only while the lock is ours
.queue('daily-reports').push([{ transactionId: `report-${report.day}`, data: report }])
.commit()
if (result.success === false) return 'lost the lock'
return 'done'
} finally {
await lock.release()
}lock = queen.lock("nightly-report", ttl_seconds=30)
if not await lock.acquire(wait=1): # another worker has it
return "skipped"
try:
report = {"day": "2026-10-24", "bookings": 412}
result = await (
queen.transaction()
.guard(lock) # commits only while the lock is ours
.queue("daily-reports")
.push([{"transactionId": f"report-{report['day']}", "data": report}])
.commit()
)
if not result:
return "lost the lock"
return "done"
finally:
await lock.release()lock := client.Lock("nightly-report", 30*time.Second)
wait, cancel := context.WithTimeout(ctx, time.Second) // wait at most 1 s for it
defer cancel()
if err := lock.Acquire(wait); errors.Is(err, context.DeadlineExceeded) {
return "skipped", nil // another worker has it
} else if err != nil {
return "", err
}
defer func() { _, _ = lock.Release(ctx) }() // if this fails, the lock expires with its ttl
day := "2026-10-24"
report := map[string]interface{}{"day": day, "bookings": 412}
result, err := client.Transaction().
Guard(lock). // commits only while the lock is ours
Queue("daily-reports").
Push(queen.PushItem{TransactionID: "report-" + day, Payload: report}).
Commit(ctx)
if err != nil {
return "", err
}
if result.IsKVPrecondition() {
return "lost the lock", nil
}
return "done", nillet lock = queen.lock("nightly-report", Duration::from_secs(30));
if !lock.acquire_within(Duration::from_secs(1)).await? {
return Ok("skipped"); // another worker has it
}
let day = "2026-10-24";
let committed = queen
.transaction()
.guard(&lock) // commits only while the lock is ours
.push_item(TxnPushItem {
queue: "daily-reports".into(),
partition: None,
payload: json!({ "day": day, "bookings": 412 }),
transaction_id: Some(format!("report-{day}")),
trace_id: None,
})?
.commit()
.await;
lock.release().await?; // whatever happened, give the lock back
if !committed?.success {
return Ok("lost the lock");
}
Ok("done")$lock = $queen->lock('nightly-report', ['ttlSeconds' => 30]);
if (!$lock->acquire(1.0)) { // waits up to 1 s for it
return 'skipped'; // another worker has it
}
try {
$report = ['day' => '2026-10-24', 'bookings' => 412];
$result = $queen->transaction()
->guard($lock) // commits only while the lock is ours
->queue('daily-reports')
->push([['transactionId' => "report-{$report['day']}", 'data' => $report]])
->commit();
if ($result['success'] === false) {
return 'lost the lock';
}
return 'done';
} finally {
$lock->release();
}queen::Lock lock = client.lock("nightly-report", 30);
if (!lock.acquire(1000)) return "skipped"; // another worker has it
json result;
try {
json report = {{"day", "2026-10-24"}, {"bookings", 412}};
std::string id = "report-" + report["day"].get<std::string>();
result = client.transaction()
.guard(lock) // commits only while the lock is ours
.queue("daily-reports").push({{{"transactionId", id}, {"data", report}}})
.commit();
} catch (...) {
lock.release();
throw;
}
lock.release();
return result.value("success", false) ? "done" : "lost the lock";Three workers started at once: one built the report and two skipped. There was one report.
One thing to know: in JavaScript, Python, Go and Rust the lock renews itself in the background while the worker holds it. For long work in JavaScript, pass lock.signal to what the work waits on, so it stops when the lock is lost. For “at most three at a time”, queen.semaphore(name, 3) works the same way.
Built from: KV, locks and timers, Transactions.