Documentation
¶
Overview ¶
Package claims keeps the claims and the leases of a scheduler.Scheduler in PostgreSQL tables, so that an app running several instances runs each minute boundary of a recurring job on one of them (NewBunStore), and runs at most one run of a keyed job id at a time across them (NewBunLeaser). It works on PostgreSQL only.
The claims table has one row per job id, so it does not grow with time and needs no cleanup. A claim is one statement: an upsert that takes the row only when its stored tick is older than the claimed one and its job is not busy. "Now" and the busy deadline are computed by the database, so instances whose clocks disagree still agree on whether a claim is busy, and a tick more than a minute ahead of the database clock is refused with an error.
Index ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func CreateLeaseTable ¶ added in v1.36.0
CreateLeaseTable creates the table of NewBunLeaser when it does not exist. Every instance can call it at startup: like CreateTable, it holds a transaction-level advisory lock while it creates the table. The role needs CREATE on the schema even when the table exists.
func CreateTable ¶
CreateTable creates the table of NewBunStore when it does not exist. Every instance can call it at startup: it holds a transaction-level advisory lock while it creates the table, since concurrent CREATE TABLE IF NOT EXISTS statements can fail on PostgreSQL's catalog. The role needs CREATE on the schema even when the table exists.
func NewBunLeaser ¶ added in v1.36.0
NewBunLeaser returns a scheduler.Leaser backed by one PostgreSQL table with the columns job_id, owner, held_until and superseded. Call CreateLeaseTable with the same table at startup to create it, and pass the leaser to scheduler.WithLeaser on every instance.
Each of Acquire, Renew and Release is one statement in its own implicit transaction, and reads the time from the database's now(), so it works through a pooler in transaction mode, and instances whose clocks disagree agree on whether a lease is live. Release also deletes the rows whose lease lapsed more than an hour ago, left by instances that stopped without releasing for ids not used since.
The statements are written for the default READ COMMITTED isolation only. Under a database or role default of REPEATABLE READ or SERIALIZABLE, Acquire, Renew and Release can all fail with a serialization error when acquires race the holder: a contended Acquire fails instead of being refused, a failed Renew fails the instance's whole batch, and a failed Release leaves the id blocked until the lease lapses. Two runs of an id still never hold it together.
The job id is the table's primary key, so it must fit in a btree index entry, about 2.7 KB after PostgreSQL's compression, and must not contain a NUL byte, which PostgreSQL's text refuses. Every Acquire of an id that breaks either limit fails.
func NewBunStore ¶
NewBunStore returns a scheduler.Claimer backed by one PostgreSQL table with the columns job_id, tick and busy_until. Call CreateTable with the same table at startup to create it, and pass the store to scheduler.WithClaimer on every instance.
For one job id it grants a tick to exactly one claim, and refuses a tick older than or equal to the last one claimed, so an instance that asks late cannot run a tick again. While a claim is busy, from the claim until it is released or its lease expires, it refuses later ticks too. A tick more than a minute ahead of the database clock is an ez.EINVALID error and is not stored.
Types ¶
This section is empty.