pgbus 0.12.1 → 0.12.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +1 -0
- data/lib/pgbus/client/ensure_stream_queue.rb +38 -10
- data/lib/pgbus/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 3393ad40ec489306eff74a6504c6694aa27747e5e0d2ce533ba4b7d7e989fe93
|
|
4
|
+
data.tar.gz: b1e7244a064bfa8fe1776a5eaa9dd7317682e098bf98133759eadc0c6402e4c8
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 440cfbc362912153a1cfb694033e667b32559a965b5b2b8c99214d11bc06a09d717127e8616a49dc59858f6a8048619a0d4a0267398f5cccf78019ca2f0dedf3
|
|
7
|
+
data.tar.gz: 45163ef47567b3ff8be5e4c415311f6619d11a4712ecbc970aafe7e949cc09ebd75632727ebf6b7817c124cfbb9dec0cf3c9d29c41061d37704048c9522d6851
|
data/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
### Fixed
|
|
4
4
|
|
|
5
|
+
- **`ensure_stream_queue` recovers when a process-local `@queues_created` memo is stale after another process drops the physical queue.** Stream queues are created lazily and memoized per process. The dispatcher orphan stream sweep (and dashboard / manual `drop_queue`) only clears the *local* process memo when it drops an empty or aged stream queue. Peer processes — typically long-lived web workers that already published or subscribed once — keep the memo, skip `pgmq.create` on the next durable broadcast, and fail in `pgmq.enable_notify_insert` with `Queue "…" does not exist. Create it first using pgmq.create()`. That exception often surfaces from an `after_commit` Turbo/stream broadcast and turns a successful write into a 500. On that specific missing-queue `PGMQ::Errors::ConnectionError`, `ensure_stream_queue` now forgets the local queue + archive-index memo and retries create/notify once. Unrelated connection errors still raise immediately. Happy path: no extra round-trips (recovery is error-path only).
|
|
5
6
|
- **`streams_pool_database_url` / `streams_pool_host` / `streams_pool_port` — route the streams PGMQ pool independently of the streamer's LISTEN connection (issue #358).** 0.12.0 started building the dedicated streams pool from `streams_connection_options` (correct for a separate streams database), but that method is also how pooler-bypass installs pin the LISTEN connection to the **direct** Postgres port (`streams_port = 5432`, the documented "workers go through PgBouncer, streamer goes direct" pattern) — so upgrading silently moved up to `streams_pool_size` connections **per process** onto the direct port, whose `max_connections` ceiling on managed Postgres is typically low. A modest fleet exhausts it (`FATAL: remaining connection slots are reserved for roles with the SUPERUSER attribute`): `StreamApp` then 500s every SSE connect and durable broadcasts fail at publish, intermittently, because the pools are lazy. Only LISTEN actually needs the direct port (it dies at transaction-pool COMMIT boundaries); the pool's broadcast INSERTs and replay reads are plain pooler-safe SQL. The new `streams_pool_*` triple routes the POOL independently — applied to the base options exactly like the `streams_*` and `worker_notify_*` groups: set `streams_pool_port` back to the pooled port and only the LISTEN pins remain direct. Default `nil` = follows `streams_connection_options`, byte-identical to 0.12.0, so separate-streams-DB installs are unchanged. Refs #358.
|
|
6
7
|
- **The health verdict no longer reads durable stream queues as a wedged fleet (issue #359).** The Process-liveness signal (`pgbus doctor`, `pgbus_health`, the MCP health tool) treats *visible messages with `read_ct=0` while workers are alive* as the silent-worker-wedge signature — but durable stream delivery is a non-consuming peek, so **every** stream queue matches it permanently by design. On a streams-heavy install the verdict screamed STALLED listing hundreds of healthy stream queues, burying real wedges in noise. `HealthAnalyzer` now excludes queues registered in the `pgbus_stream_queues` registry from the operational set (exactly like DLQs) — out of the STALLED/DEGRADED reasons and the backlog totals — via a new `Web::DataSource#stream_queue_names` (loaded fresh per verdict; degrades to an empty set on pre-registry installs). Same bug class as #308/#309, same registry cure. Refs #359.
|
|
7
8
|
- **The `upgrade_pgmq` migration no longer silently kills NOTIFY-gated wakeups fleet-wide (issue #360).** The generated migration drops every pgmq function **with CASCADE** — which also drops the `trigger_notify_queue_insert_listeners` trigger from every existing queue table (it depends on the dropped `pgmq.notify_queue_listeners()`), and `install_sql` re-created the functions but never the per-queue triggers. Result: after every PGMQ schema upgrade, NOTIFY wakeups (#174) silently died and workers fell back to `polling_interval` polling — nothing errored; latency degraded and DB poll load rose. Trigger re-install only happened in `ensure_single_queue` (per-process memoized), so on the common deploy ordering where the job supervisor boots *before* migrations run, the supervisor installed triggers at boot and the migration wiped them minutes later — with nothing left to re-install them until a full process restart. New `PgmqSchema.reinstall_notify_triggers_sql` replays `pgmq.enable_notify_insert` for every row in `pgmq.notify_insert_throttle` (a table, preserved by the upgrade, recording exactly which queues had notify and at what throttle; the function is idempotent), and the migration template runs it after `install_sql` — restoring every trigger at its original interval. No-op on vendored versions without the notify feature. **Already ran an upgrade migration?** Run `Pgbus::PgmqSchema.reinstall_notify_triggers_sql` once (e.g. from a console: `ActiveRecord::Base.connection.execute(...)`) or restart the fleet; `pgbus doctor`'s LISTEN/NOTIFY check confirms the repair. Refs #360.
|
|
@@ -29,16 +29,7 @@ module Pgbus
|
|
|
29
29
|
# raise on the missing bare table. Streams never use priority
|
|
30
30
|
# sub-queues (issue #310).
|
|
31
31
|
ensure_pgmq_schema
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
# PGMQ's default NOTIFY throttle is 250ms — meant to coalesce
|
|
35
|
-
# high-frequency worker queue inserts. Streams are latency-
|
|
36
|
-
# sensitive and need every broadcast to fire a NOTIFY, even
|
|
37
|
-
# when several are batched within a single millisecond.
|
|
38
|
-
# Override the throttle to 0 specifically for stream queues.
|
|
39
|
-
# Use the idempotent path to avoid deadlocks when multiple
|
|
40
|
-
# processes race to set up the same stream queue.
|
|
41
|
-
synchronized { enable_notify_if_needed(full_name, 0) }
|
|
32
|
+
ensure_stream_queue_tables(full_name, stream_name)
|
|
42
33
|
end
|
|
43
34
|
|
|
44
35
|
# CREATE INDEX IF NOT EXISTS is idempotent in Postgres but still
|
|
@@ -68,6 +59,43 @@ module Pgbus
|
|
|
68
59
|
|
|
69
60
|
@stream_indexes_created[stream_name] = true
|
|
70
61
|
end
|
|
62
|
+
|
|
63
|
+
private
|
|
64
|
+
|
|
65
|
+
# Creates the bare stream queue + forces NOTIFY throttle 0. Retries once
|
|
66
|
+
# when a process-local `@queues_created` memo is stale relative to the
|
|
67
|
+
# database: another process can drop the physical queue (orphan stream
|
|
68
|
+
# sweep, dashboard drop, manual `drop_queue`) without invalidating every
|
|
69
|
+
# peer process's memo. The memoized path then skips `pgmq.create` and
|
|
70
|
+
# `enable_notify_insert` raises "Queue does not exist".
|
|
71
|
+
def ensure_stream_queue_tables(full_name, stream_name)
|
|
72
|
+
ensure_single_queue(full_name)
|
|
73
|
+
|
|
74
|
+
# PGMQ's default NOTIFY throttle is 250ms — meant to coalesce
|
|
75
|
+
# high-frequency worker queue inserts. Streams are latency-
|
|
76
|
+
# sensitive and need every broadcast to fire a NOTIFY, even
|
|
77
|
+
# when several are batched within a single millisecond.
|
|
78
|
+
# Override the throttle to 0 specifically for stream queues.
|
|
79
|
+
# Use the idempotent path to avoid deadlocks when multiple
|
|
80
|
+
# processes race to set up the same stream queue.
|
|
81
|
+
synchronized { enable_notify_if_needed(full_name, 0) }
|
|
82
|
+
rescue PGMQ::Errors::ConnectionError => e
|
|
83
|
+
raise unless missing_pgmq_queue_error?(e)
|
|
84
|
+
|
|
85
|
+
forget_stream_queue_memo!(full_name, stream_name)
|
|
86
|
+
ensure_single_queue(full_name)
|
|
87
|
+
synchronized { enable_notify_if_needed(full_name, 0) }
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def forget_stream_queue_memo!(full_name, stream_name)
|
|
91
|
+
@queues_created.delete(full_name)
|
|
92
|
+
@stream_indexes_created.delete(stream_name)
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
def missing_pgmq_queue_error?(error)
|
|
96
|
+
message = error.message.to_s
|
|
97
|
+
message.include?("does not exist") && message.include?("pgmq.create")
|
|
98
|
+
end
|
|
71
99
|
end
|
|
72
100
|
end
|
|
73
101
|
end
|
data/lib/pgbus/version.rb
CHANGED