Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/NikolayS/PgQue/llms.txt

Use this file to discover all available pages before exploring further.

PgQue ticks on a configurable cadence. The default is 100 ms (10 checks/sec), but the true WAL cost depends on how many ticks actually materialize — idle queues back off automatically and produce negligible overhead.

How tick frequency works

pgque.start() schedules one 1-second pg_cron slot that calls pgque.ticker_loop(). The procedure then invokes pgque.ticker() every tick_period_ms milliseconds and commits between iterations. So sub-second ticking is real — not limited by pg_cron’s 1-second minimum schedule.
The 100 ms default is the check cadence, not a guarantee of 10 materialized ticks per second. If no events have arrived since the last tick, ticker() returns NULL — no tick row is written. PgQue backs off idle queues toward ticker_idle_period (default 1 minute).

Choosing a cadence

tick_period_msCheck rateMedian e2e waitUse case
10001 check/sec~500 msSmall projects, WAL-constrained systems, pgqd-compatible cadence
100 (default)10 checks/sec~50 msLower latency without high churn
5020 checks/sec~25 msLatency-sensitive apps (check WAL budget first)
10100 checks/sec~5 msSpecialized workloads — benchmark first
11000 checks/secsub-ms averageExperimental/extreme — benchmark WAL, NOTIFY, metadata churn
Tune at runtime — no restart or rescheduling needed:
select pgque.set_tick_period_ms(1000);  -- 1 check/sec (low WAL)
select pgque.set_tick_period_ms(100);   -- 10 checks/sec (default)
select pgque.set_tick_period_ms(50);    -- 20 checks/sec
Valid values: exact divisors of 1000 in the 1–1000 ms range.

WAL budget for continuously active queues

Every materialized tick writes PgQue metadata. A simple PG18 measurement isolated ~280 bytes of WAL per materialized tick per queue.
Materialized tick rateFormulaEstimate
1 tick/sec continuously280 B × 86,400~24 MiB/day per queue
10 ticks/sec continuously280 B × 10 × 86,400~240 MiB/day per queue
100 ticks/sec continuously280 B × 100 × 86,400~2.4 GiB/day per queue
These estimates apply only to queues that materialize ticks continuously. An idle queue that backs off to ticker_idle_period (1 minute) produces a fraction of this overhead. Do not multiply the “10 ticks/sec” estimate by idle queues.
Factors that affect the real number:
  • Full-page imagesfull_page_writes = on (the default) logs full page images after checkpoints, which can exceed the steady-state estimate
  • Number of active queues — overhead scales with active queues, not total queues
  • Scheduler loggingcron.job_run_details WAL is separate; PgQue’s sub-second loop does not multiply cron log rows (still one slot per second)

Why idle queues back off

With no producer writes, pgque.ticker() consults per-queue settings before materializing a tick:
  • ticker_max_lag — max wall time between ticks while there is activity
  • ticker_max_count — force a tick after N events
  • ticker_idle_period — upper bound on idle ticking (default 1 minute)
A quiet queue naturally trends toward occasional idle ticks rather than 10/sec. Calling ticker() every 100 ms is cheap when it returns NULL.

Practical recommendations

Start with the default (100 ms) for most workloads. It delivers ~50 ms median end-to-end latency with manageable WAL overhead on active queues.
  • Use 1000 ms for small projects, low-throughput queues, WAL-constrained environments, or anywhere logical replication lag matters more than sub-100 ms delivery
  • Monitor WAL generation, dead tuples on PgQue metadata tables, and replica lag before going below 50 ms
  • For many queues in one database, estimate active queues separately; idle queues are nearly free
  • If using pg_cron, schedule a log purge to avoid unbounded growth of cron.job_run_details:
select cron.schedule(
  'pgque_purge_cron_log',
  '0 * * * *',
  $$
  delete from cron.job_run_details d
  using cron.job j
  where d.jobid = j.jobid
    and j.jobname in (
      'pgque_ticker', 'pgque_retry_events',
      'pgque_maint', 'pgque_rotate_step2',
      'pgque_purge_cron_log'
    )
    and d.end_time < now() - interval '1 day'
  $$
);

Build docs developers (and LLMs) love