Skip to content

docs: three-latencies explanation#68

Merged
NikolayS merged 6 commits intomainfrom
docs/three-latencies
Apr 30, 2026
Merged

docs: three-latencies explanation#68
NikolayS merged 6 commits intomainfrom
docs/three-latencies

Conversation

@NikolayS
Copy link
Copy Markdown
Owner

Summary

Addresses recurring confusion (including a HN thread today: https://news.ycombinator.com/threads?id=samokhvalov) about the apparent contradiction between PgQue's sub-ms consumer-path latency and the ~1-second end-to-end delivery bound.

Names the three distinct latencies in any event queue and explains PgQue's trade-off explicitly:

  1. Producer latency — INSERT. Sub-ms.
  2. Subscriber latencynext_batch returning an already-built batch. Sub-ms.
  3. End-to-end delivery time — bounded by tick cadence (default 1 s via pg_cron), not by load. This is the design property that polling queues lack.

Changes

  • README.md: new "Three latencies" subsection between "Latency trade-off" and "Comparison" — one paragraph + 3-bullet list + link to the concept doc.
  • docs/pgq-concepts.md: detailed version appended to the existing concept doc — per-latency physics with preliminary bench numbers, tick-frequency trade-off table (1 s / 250 ms / 100 ms / sub-100 ms), comparison to pgmq's poll-on-demand model including the MVCC/bloat failure mode, when-to-pick guidance, provenance link to the HN thread.

Uses the real config knob names from sql/pgque.sql:

  • queue_ticker_max_lag (default 3 seconds) — safety cap
  • queue_ticker_idle_period (default 1 minute) — idle decelerator
  • queue_ticker_max_count (default 500) — batch-size cap
  • Tick cadence itself is the pg_cron schedule set in pgque.start() (default 1 second)

No SQL files modified. No invented features.

Test plan

  • Author review of framing, numbers, and voice/tone match with existing README sections
  • Confirm the HN thread URL is the one you want as the provenance link (or swap for a deeper-link to the specific comment once the thread stabilizes)
  • Sanity-check that "~86k ev/s PL/pgSQL insert" and "~2.4M ev/s consumer read" numbers cited in the concept doc match what you want to cite (pulled from docs/benchmarks.md)
  • Decide whether to promote this to a top-level docs/three-latencies.md with a redirect from the concept doc, or keep it as a section of pgq-concepts.md (current choice)

Draft — author review before merge.

@NikolayS NikolayS force-pushed the docs/three-latencies branch from fafc9e1 to 9a28fc2 Compare April 18, 2026 23:36
@NikolayS
Copy link
Copy Markdown
Owner Author

Force-pushed with two fixes from second review round:

1. Trimmed both sections.

  • README: ~13 lines → 9 lines (1 short intro sentence + 3-bullet list; the link carries the depth).
  • Concept doc: ~142 lines → 85 lines. Per-latency physics collapsed into a 4-column table; tick trade-off compressed; "when to pick" reduced from bullets to 2 sentences.

2. Corrected the 'e2e is floored at ~1 s' implicit claim. Previous wording risked reading as "PgQue cannot do sub-ms e2e." It can — the 1-second default is a pg_cron schedule, not a design floor. Both sections now explicitly say e2e is tunable, not floored, and the concept doc adds a dedicated subsection covering three techniques:

  • Staggered pg_cron jobs (N jobs offset via shared lock, effective ~10 ms or ~1 ms)
  • In-tick pg_sleep loop (single cron callout, internal sub-second cadence)
  • Native sub-second pg_cron (future)

Plus the metadata-table bloat caveat with pointer to #61 and PR #62.

Framing attribution — added Hannu Krosing (ex-Skype, original PgQ context) alongside the HN thread in the Provenance paragraph.

One thing I did NOT touch that you may want to revisit: the existing "Latency trade-off" section above "Three latencies" still says "If your top priority is single-digit-millisecond dispatch, PgQue is the wrong tool." That's now inconsistent with the "tunable, not floored" framing in the new section. Happy to soften it in a follow-up if you want — kept this PR scoped to the new section only.

@NikolayS NikolayS force-pushed the docs/three-latencies branch 2 times, most recently from 20ece4d to e43dd57 Compare April 18, 2026 23:50
@NikolayS
Copy link
Copy Markdown
Owner Author

Two cleanups:

  1. Generalized comparison language — no longer naming a specific alternative queue system. The section now reads "poll-on-demand systems" / "designs that rely on SKIP LOCKED with visibility timeouts" / "pick a poll-on-demand system if..." instead of calling out one project.
  2. Removed ### Provenance section — concept doc stands on its own.

@NikolayS NikolayS force-pushed the docs/three-latencies branch from e43dd57 to 18a0263 Compare April 18, 2026 23:51
@NikolayS
Copy link
Copy Markdown
Owner Author

Three docs cleanups:

  1. Generalized comparison — no named alternative queue systems.
  2. Removed ### Provenance section.
  3. Removed all issue/PR references — docs are self-contained, not tracker-coupled.

@NikolayS NikolayS force-pushed the docs/three-latencies branch from 18a0263 to defdc4d Compare April 18, 2026 23:58
@NikolayS
Copy link
Copy Markdown
Owner Author

Terminology fix: "poll-on-demand" → "UPDATE/DELETE" (the canonical framing — those systems' distinguishing trait is UPDATE/DELETE-based consumption, which creates dead tuples).

Name the three distinct latencies in any Postgres queue and explain why
PgQue's batch-ticker model makes #1 and #2 sub-ms while bounding #3 by
the tick cadence (not by load). Addresses recurring confusion about the
apparent contradiction between sub-ms consumer-path latency and the ~1 s
end-to-end delivery bound.

- README.md: brief paragraph + 3-bullet list, new "Three latencies"
  subsection between "Latency trade-off" and "Comparison".
- docs/pgq-concepts.md: detailed version with per-latency physics,
  tick-frequency trade-off table, comparison to pgmq's poll-on-demand
  model, when-to-pick guidance, provenance link.

Uses actual pgque.sql column names: queue_ticker_max_lag (3s),
queue_ticker_idle_period (1min idle-decelerator), queue_ticker_max_count
(500). The 1-second cadence comes from the pg_cron schedule set by
pgque.start(), not from queue_ticker_idle_period.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@NikolayS NikolayS force-pushed the docs/three-latencies branch from defdc4d to bf560ae Compare April 30, 2026 09:22
@NikolayS
Copy link
Copy Markdown
Owner Author

REV review — PR #68 docs: three-latencies explanation

Verdict: LGTM with two minor notes (no blockers). Independent reviewer — not approving/merging.

Confidence: High. Docs-only, tightly scoped, factual claims cross-checked against sql/pgque.sql, docs/reference.md, docs/benchmarks.md.

Counts

Blockers 0
Major 0
Minor 2
Nits 2

5-perspective summary

Security: N/A. No suspicious links. Provenance link is news.ycombinator.com/threads?id=samokhvalov — author's own HN handle, fine.

Bug hunter: Function names and config knobs verified against the v0.1 install:

  • pgque.send, pgque.insert_event, pgque.next_batch, pgque.get_batch_events, pgque.set_queue_config() — all match docs/reference.md.
  • queue_ticker_max_lag (default 3 seconds), queue_ticker_max_count (default 500), queue_ticker_idle_period (default 1 minute) — all match sql/pgque.sql:110-112 exactly.
  • Bench numbers ~86k ev/s and ~2.4M ev/s match docs/benchmarks.md:45,48 (85,836 ev/s and ~2.4M ev/s).
  • Math sanity: 1 s / 100 = 10 ms, 1 s / 1000 = 1 ms — staggered table consistent.
  • No SQL/Python code blocks in the new doc, so no syntax to break.

Test analyzer: N/A (docs-only).

Guidelines (CLAUDE.md):

  • Lowercase SQL, snake_case, schema-qualified pgque.X — compliant throughout.
  • Conventional Commits: docs: promote three-latencies to dedicated page — compliant.
  • Binary units: only MiB/s appears (transitively, via reference to bench doc); no inline storage sizes in new prose to violate the rule.
  • README structure: 5-line tease (1 intro + 3-bullet list + link) does not duplicate the dedicated page — passes the tease-not-duplicate test.
  • docs/README.md index updated.
  • docs/pgq-concepts.md no longer duplicates the prose; replaced with a clean cross-reference. Good.

Docs:

Anti-leak: grep -iE \"gitlab|sahmed|artifact[_-]?registry|@AR|wi[ -]?#?7[67]|round[ -]?8|R8\" on the diff — clean.

Rebase integrity (force-with-lease check): Branch has two commits (1206929 initial → bf560ae promote). The rebased tip diff against main shows the full consolidated state: 46-line standalone doc with all 3 sections + tables + provenance, ToC entry, and the cross-reference stub in pgq-concepts.md. No content scrambling or dropped sections.

CI: All green (claude-review, client-smoke, test 14-18, verify).

Minor

  1. Stale PR body. The PR description still references the older inlined-into-pgq-concepts.md structure ("~142 lines", "detailed version appended", "keep it as a section of pgq-concepts.md (current choice)"), which no longer matches the branch. The current branch is the trimmed standalone-page version. Consider refreshing the description before un-drafting so reviewers and future readers see what actually shipped.

  2. Self-flagged inconsistency between sections. The author's own comment notes that the upstream ## Latency trade-off section still says "If your top priority is single-digit-millisecond dispatch, PgQue is the wrong tool", which contradicts the new "tunable, not floored" framing. Out of scope here, but worth a follow-up PR (a one-line softening to something like "…the default config is the wrong tool — sub-ms e2e is achievable, see Three latencies" would close the loop).

Nits

  1. "≈ tick period + consumer poll interval" in the row-3 table cell is correct but introduces a poll-interval term that isn't elaborated until the "Load behavior" section several paragraphs later. A reader scanning only the table may briefly wonder where the consumer poll comes from. Optional: parenthetical "(see below)" or move to plain "≈ tick period" in the table and explain the consumer-poll addition in body text.

  2. Guidance table phrasing. Row 1 says pgqd-compatible — not wrong, but pgqd is unexplained at first encounter and may be unfamiliar to readers arriving from the README tease. Consider "matches PgQ's pgqd default" or linking to where pgqd is introduced.

@NikolayS NikolayS marked this pull request as ready for review April 30, 2026 09:39
NikolayS and others added 4 commits April 30, 2026 02:42
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@NikolayS NikolayS merged commit 63da117 into main Apr 30, 2026
8 checks passed
@NikolayS NikolayS deleted the docs/three-latencies branch April 30, 2026 09:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant