pgbus 0.18.0 → 0.18.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 +4 -0
- data/app/controllers/pgbus/application_controller.rb +2 -2
- data/lib/pgbus/process/worker.rb +5 -0
- 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: 83064d02cef8b5b1e2da6a8fb229d3968a93b59e34d7072babe9a7968f9100dd
|
|
4
|
+
data.tar.gz: 7a7095fee01a7e8c9f68f1284dd4b3e849bb1e50d12455b45830b2e96d854cc9
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: f4112de787c0eda83491b5b8bc4217c7a98111f4cbdd7304de601accc2795a08af5f5c192e09951a7ce2fc289f5f48950bea619540c200c41464f203a8a7d2b6
|
|
7
|
+
data.tar.gz: 8e28ba86d1ccbe8e323dd5dc6168f9466c791fa5d93b286a312a2b929885c5db43e42092136bb6035ec57b2adabb3f3b1e002e509d057a24a9bec0b23ba0aaef
|
data/CHANGELOG.md
CHANGED
|
@@ -56,6 +56,8 @@
|
|
|
56
56
|
|
|
57
57
|
### Fixed
|
|
58
58
|
|
|
59
|
+
- **A draining worker no longer strands its read-ahead claims.** The worker loop checked `can_process?` once to decide whether to return buffered claims, then read the lifecycle again to decide whether to exit. A drain (`graceful_shutdown`) or stop (`immediate_shutdown`) from another thread that landed between the two reads let the loop exit with the buffer still full (a pause does not exit the loop, so its claims go back on the next step), so those messages stayed invisible until their visibility timeout instead of going straight back to the queue (`vt: 0`). The worker now returns whatever is still buffered after the loop, however it exits. This was the intermittent `worker_read_ahead_spec.rb:217` failure (about 1 run in 20). Refs #486.
|
|
60
|
+
|
|
59
61
|
- **`pgbus:connected` now fires only once the connection is registered and its presence join has run.** `StreamApp` wrote the frame at hijack time, before the streamer's dispatcher had handled the connect, so a page that acted on its connection id as soon as it heard the event — `Pgbus.stream(x).presence.set_state(connection_id:)` from an action, for instance — found no row (`set_state` returned nil) and had to retry. The dispatcher now writes the frame at the end of the connect, after the archive replay, `registry.register` and the presence join attempt (a stream without presence, or a member resolver that returns nil, has no seat to join; a join that raises is logged and the frame still follows), through the connection's mutex-serialised writer (`Connection#write_connected` / `FalconConnection#write_connected`). The event name, its `connectionId` payload and the element's `connection-id` attribute are unchanged; listeners hear it after any replayed frames instead of before them, and a connection that dies during the replay never gets one. A repeated disconnect for an already-unregistered connection no longer records a second `disconnect` stream stat. Closes #521.
|
|
60
62
|
|
|
61
63
|
- **A closed tab leaves its presence seat at once, not on the next heartbeat.** The server never reads a hijacked SSE socket after the request, so a client that went away was noticed only when a heartbeat write failed: up to `streams_heartbeat_interval` later (15 s by default), and often a beat later still, because the first write after the client's FIN succeeds. Every viewer of a presence roster kept the closed tab for that long. A new `PeerCloseWatcher` thread per streamer waits on every live hijacked socket with `IO.select` and probes a readable one with a non-blocking read: EOF or a reset marks the connection dead, closes it and posts the same `DisconnectMessage` the heartbeat posts, so the seat leaves (and `streams_presence_on_change` fires once) within milliseconds on Puma and on Falcon's default hijack path; a connection closed within its first `streams_peer_close_interval` after opening is noticed within that interval. A TLS client that vanishes without close_notify (OpenSSL's or Puma MiniSSL's SSL error on read) counts as closed, the probe skips a socket while a write holds its mutex, and `#stop` wakes the select through a self-pipe so shutdown does not wait out the interval. The client sends nothing after its request, so a readable socket means a close; stray bytes are read and discarded. Falcon's experimental streaming-body path has no socket and keeps the heartbeat. New setting `streams_peer_close_interval` (1.0 s by default): how long a newly opened connection waits to join the watched set; `nil` turns the watcher off. Closes #519.
|
|
@@ -253,6 +255,8 @@
|
|
|
253
255
|
|
|
254
256
|
### Fixed
|
|
255
257
|
|
|
258
|
+
- **Dashboard views keep every engine helper when `base_controller_class` is a host controller (issue #528).** `Pgbus::ApplicationController` named only `ApplicationHelper` and `ButtonHelper`. Rails runs `helper :all` only when a controller's superclass is `ActionController::Base`, so a custom base never loaded the rest. The home page renders `processes/_status` from the dashboard controller, which does not own `ProcessesHelper`, and raised `undefined method 'pgbus_process_status'` as soon as a process row rendered. The controller now calls `helper :all` itself, the same call Rails makes for the default base, so every helper under `app/helpers/pgbus/` is available on every dashboard view. A host base controller's own helpers stay in the chain. Refs #528.
|
|
259
|
+
|
|
256
260
|
- **`ensures_uniqueness` / `limits_concurrency` declared on a base class now reach every subclass — previously the declaration was silently inert for them (issue #357).** Both macros stored their config in a class-level ivar (`@pgbus_uniqueness` / `@pgbus_concurrency`) and every lookup read `active_job.class.pgbus_uniqueness` without walking ancestors — class-level ivars are not inherited in Ruby, so `class RecurringBase < ApplicationJob; ensures_uniqueness strategy: :until_executed; end` gave subclasses NO uniqueness key, no scheduler overlap protection, and no #333 guard, with no warning that the natural reading of the code was false. The readers now fall back to the nearest ancestor's declaration (a class's own declaration still beats an inherited one). Coupled fix, required to make inheritance safe rather than harmful: no default key proc is stored anymore — the old `key || ->(*) { name }` captured the DECLARING class, so an inheritance fix alone would have collapsed every subclass into ONE shared key (the base class's name), and with `on_conflict: :discard` sibling jobs would silently discard each other's enqueues — strictly worse than inert. The class-name default is now resolved from the ENQUEUED job's class at all three call sites (`Uniqueness.resolve_key`, `Concurrency.resolve_key`, and the recurring scheduler's `resolve_uniqueness_key`), and `config[:key]` is `nil` when no explicit `key:` was given. Consumer note: concrete-class declarations resolve to exactly the same keys as before, but a base-class declaration that was silently inert now ACTIVATES per-subclass uniqueness/concurrency on upgrade — audit any base-class declarations (the macro finally does what it says). In the scheduler path the no-key default is additionally qualified with the recurring task's `args:` (`SyncJob:["site_a"]`) so two tasks pointing at the same job class with different arguments don't share one lock — the scheduler's analogue of the #333 raise-at-enqueue guard, which a scheduler loop can't use — and a failure to resolve ANY uniqueness key — default or user-supplied key proc — now fails closed (skips the tick, logs, and reaches `error_reporters`) instead of degrading to nil and enqueuing WITHOUT a lock, which silently disabled the very protection the proc configured. Both macros also now reject a non-nil, non-callable `key:` (e.g. `key: false`) at definition time with the documented ArgumentError — previously `false` slipped the truthiness guard and surfaced as a `NoMethodError` at enqueue (uniqueness) or silently acted as the class-name default (concurrency). Measured (benchmark-ips, enqueue-path budget per docs/performance.md): the shared `Support.call_key_proc` dispatch is ~17% faster than the old inline dispatch (136ns vs 160ns/op), the class-name default is 3.7× faster than the old stored-proc call (23ns vs 86ns/op), and the inherited-config ancestor walk adds ~15ns/op. Refs #357, #333.
|
|
257
261
|
- **The Ruby-Timeout read fallback no longer leaves a wedged `CONNECTION_OK` connection in the pgmq pool to re-hang the next read (issue #354).** On the one path where libpq can't bound a hung socket (dedicated connection on non-Linux hosts or libpq < 12), the last-resort `Timeout.timeout` interrupts the read via `Thread#raise` — and libpq may leave the pooled `PG::Connection` reporting `CONNECTION_OK` while it will in fact re-hang on reuse, invisible to pgmq-ruby's checkout health check (it isn't `CONNECTION_BAD`). This was a documented KNOWN LIMITATION waiting on a public pool-reload upstream (cf. mensfeld/pgmq-ruby#94); pgmq-ruby 0.7.1 shipped it, so the fallback now raises an internal `ReadTimeoutError` subclass and reloads the job pool before re-raising — the poisoned connection (already checked back in by `connection_pool`'s ensure) is dropped and the pool rebuilds lazily. A clean server-side `statement_timeout` cancel still never triggers a reload (the connection is healthy), and a reload failure is logged without masking the timeout. Requires pgmq-ruby >= 0.7.1 (dependency bumped to `~> 0.7.1`). Refs #354.
|
|
258
262
|
- **`connection_guc_mode = :session` no longer kills every SSE stream and NOTIFY wakeup with `PG::Error: invalid connection option "variables"` (issue #352).** In `:session` mode, `forward_connection_variables` deliberately leaves the database.yml `variables:` hash on the connection options for the *caller* to strip and apply via post-connect `SET` (a transaction-mode pooler rejects the libpq `options` startup param — the reason `:session` mode exists). `Pgbus::Client#wrap_session_gucs` honors that contract on both pgmq pools, but the two dedicated raw-connect paths — the streamer's `build_raw_pg_connection` and the worker `NotifyListener` — passed the hash straight to `PG.connect`, which rejects the non-libpq `:variables` key. Result: the first stream request per process raised, `StreamApp` rescued it into a 500 (so **every** `/pgbus/streams/…` request failed from then on), and NOTIFY-gated wakeups died with workers silently falling back to polling. Both paths now connect through the new `Pgbus::DedicatedConnection.connect`, which strips `:variables` and applies each GUC via post-connect `SET` — dedicated connections *keep* the operator's GUCs (`statement_timeout`, `timezone`, …), matching the pooled paths, and the mechanism works on both a direct port and a session-mode pooler. A guard spec confines raw `PG.connect` call sites to `Client` and `DedicatedConnection`, so the next dedicated-connection path can't silently reintroduce the bypass. Refs #352.
|
|
@@ -16,8 +16,8 @@ module Pgbus
|
|
|
16
16
|
|
|
17
17
|
layout "pgbus/application"
|
|
18
18
|
|
|
19
|
-
helper
|
|
20
|
-
helper
|
|
19
|
+
# Rails calls `helper :all` only when the superclass is ActionController::Base.
|
|
20
|
+
helper :all
|
|
21
21
|
|
|
22
22
|
# Make `pgbus` route proxy available in views (e.g. pgbus.root_path).
|
|
23
23
|
# With isolate_namespace, the non-prefixed helpers (root_path) work inside
|
data/lib/pgbus/process/worker.rb
CHANGED
|
@@ -210,6 +210,11 @@ module Pgbus
|
|
|
210
210
|
@wake_signal.wait(timeout: config.polling_interval) if @lifecycle.draining? || @lifecycle.paused?
|
|
211
211
|
end
|
|
212
212
|
|
|
213
|
+
# The lifecycle can change on another thread between the
|
|
214
|
+
# return_claims check and the breaks above, so a loop that exits with
|
|
215
|
+
# the state it never returned claims for would strand them until their
|
|
216
|
+
# visibility timeout. Nothing buffered outlives the loop.
|
|
217
|
+
return_claims
|
|
213
218
|
shutdown
|
|
214
219
|
end
|
|
215
220
|
|
data/lib/pgbus/version.rb
CHANGED