Do You Need This Book?¶
pgrelay.schedule is a small companion utility: a PostgreSQL type that
answers one question — "when should this next run?" — for recurring
schedules like "weekdays at 04:30 and 17:00," "the 2nd Tuesday of the month,"
or "every third week on Monday and Wednesday."
Who needs this book
Anyone storing a recurring schedule in a table column — a scheduled
report, a maintenance job, a notification cadence — for pg_relay itself or
for an application that also uses pg_relay. If you only need one-off or
interval-based scheduling (p_run_at, p_expire_at on pgrelay.notify()),
you don't need this book — that's already covered by the
Sending Events chapter of the User
Guide.
What it is, and why it exists¶
pg_relay itself only ever answers "run this action when this event arrives."
It has no concept of recurrence — and deliberately so, because recurrence
logic (day-of-month clamping, nth-weekday-of-the-month arithmetic,
every-N-weeks anchoring) is a different, self-contained problem with its own
edge cases. Several pg_relay-related applications — a notifier, a scheduled
maintenance job, your own code — kept needing that same piece of logic. Rather
than have each one invent its own, pgrelay.schedule gives them one shared,
thoroughly tested definition of "recurring schedule" to build on.
It is not part of the pg_relay extension. pg_relay's own SQL and the
Processor binary never reference it — installing or skipping it changes
nothing about how pg_relay itself behaves. It lives in the pgrelay schema
because it's conceptually part of the pg_relay ecosystem, but — like other
companion utilities in this repository — it ships and installs separately,
after the extension, as an optional addition.
How it fits with pg_relay's queue¶
This is the one thing worth being precise about: pgrelay.schedule only ever
computes when. It never enqueues anything, and it never calls
pgrelay.notify() itself. If you want pg_relay's Processor to actually
dispatch scheduled work, your own code is responsible for calling
pgrelay.notify() once a schedule says it's due — typically right after
advancing a "next run" watermark column. The
Watermark Pattern chapter shows the complete,
concrete pattern, including exactly where that call goes.
Your table (e.g. myapp.job)
s pgrelay.schedule -- "when should this recur?"
next_run_at timestamptz -- computed by pgrelay.next_run(s, ...)
│
│ your own code checks: next_run_at <= now() ?
▼
pgrelay.notify('your_channel', ...) -- THIS is what actually queues work
│
▼
pgrelay.queue → the Processor dispatches it, exactly like any other event
The five modes, at a glance¶
A schedule is one composite value with seven fields; which fields are populated tells you the mode — there's no separate "kind" flag to keep in sync.
| Mode | Fields | Example |
|---|---|---|
| Every matching weekday | dow |
weekdays at 04:30, 17:00 |
| Nth weekday of the month | dow + nth |
2nd Tuesday |
| Every N weeks | dow + week_interval (+ anchor) |
fortnightly on Tuesday |
| Days of the month | dom |
3rd, 5th, 22nd |
| Independent per-day times | day_times |
Mon 05:00; Tue 17:30 and 20:00; Wed 12:00 |
You never build one of these by hand — a set of constructor functions
(pgrelay.weekdays(), pgrelay.nth_dow(), pgrelay.fortnightly(),
pgrelay.on_day_times(), and so on) build and validate a schedule for you.
Every evaluation function also has a pgrelay.schedule[] array overload, for
combining several schedules — including different modes — into one answer.
See Installation to get started, or jump straight to
the API Reference if you already know what you're
building.
Continue to Installation.