Cluster cron: one leader, one tick

Redis-backed leader election visualised. createLeader elects exactly one worker across the cluster; configureCron({ leader }) gates every cron tick on the lease so a 1Hz live.cron fires once per second cluster-wide instead of once per worker.

This instance
...
Lease key
...
Leader status
follower
Current cron leader
...

Recent ticks (newest first)

cap 30

Waiting for the first cron tick...

Instances seen in the tick log

Waiting...

Only the current leader writes ticks, so replicas that correctly stay silent never appear here. However many replicas a deploy runs, this list shows the leader, you, and any past leaders - it is not a roster of every instance.

The wiring

import { createLeader } from 'svelte-adapter-uws-extensions/redis/leader'
import { live, configureCron } from 'svelte-realtime/server'

const leader = createLeader(redis)
configureCron({ leader: () => leader.isLeader() })

live.cron('* * * * * *', topic, async (ctx) => {
  // fires once per second on the elected leader, cluster-wide
})

That is the whole surface: one lease, one gate, and every live.cron in the app becomes a cluster singleton. This page's tick handler is registered exactly this way.

See the takeover

Single-instance dev shows one steady leader (this worker is always elected). To watch a real cluster transition, start a second prod server on a different port pointing at the same Redis:

npm run build
DATABASE_URL=postgres://postgres:postgres@localhost:5434/stickynotes \
  REDIS_URL=redis://localhost:6380 \
  PORT=3021 HOST=127.0.0.1 \
  node build/index.js

Open both http://127.0.0.1:3020/demos/cluster-cron and http://127.0.0.1:3021/demos/cluster-cron. The recent-tick log on both pages should show the SAME instanceId (the elected leader). Stop one server with Ctrl-C; within ten seconds (renewMs) the surviving sibling acquires the lease and the log on the live page flips to the new instanceId.

The /metrics endpoint exposes leader_acquired_total, leader_renewals_total, leader_lost_total, and svelte_realtime_cron_total{status}. Scrape both servers during the takeover window and the counters tell the same story the page shows.

For durable work on the same lease, see the durable jobs demo.