pgbus 0.14.0 → 0.14.1

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 66fe070813c414410d4b55f2b9c9f1dfcacd70236f97d22f8e037ec7a2d906c4
4
- data.tar.gz: 285e8851e43a02384734c0dfda2ae240ea4450554b5c8dca478e351b04a57528
3
+ metadata.gz: c7a7416041503b893fcd514bb1a81509d6ca3b1b6dbd31b800237b782ecad5e2
4
+ data.tar.gz: 831aa16289605abb51cd5e6ab9cdaa195497a3cbd58e68afe896813746fe4fb9
5
5
  SHA512:
6
- metadata.gz: 160efab6bf57a74ab7d190b127b7e0f64426fc17877407a87c0f70a3ba328bea8e0dfa6c44e2477263e746b16a23544843a044e1eb88c285147a6e31e129f404
7
- data.tar.gz: 7dc944582757565e3d0c8339661e533745f750731da645f2aaf6693673083b31b470f1b92265e880278b7b5720a593cc266eb9d3a11aaf554a527780f7cd481b
6
+ metadata.gz: b0734dc2d6f529c0560290a31d418165e2e2bba4b3ac175b379e9418596c304f0534adef23a390cb60ef3f8d6294b2bd2589016c9de638a3c49ada7112d1af46
7
+ data.tar.gz: 610918036f7585086d6bd2c2bd71df8cd8c3035f1e47919e47853f37bc76ce218487faaa106d71327c03c7ac080eac83eb974be83f3f16995a2b6ced71bfa145
data/CHANGELOG.md CHANGED
@@ -2,6 +2,8 @@
2
2
 
3
3
  ### Fixed
4
4
 
5
+ - **The 0.14.0 purge/drop guard no longer crashes on Rails 8.0/8.1 — pool ownership is resolved version-tolerantly (issue #411).** `Pgbus::BusRecord.disconnect_all_pools!` (added in #410 for the #409 wedge) identified its own pools via `pool.connection_class` — an API that exists on Rails 7.1/7.2 but was replaced in Rails 8.0 by `ConnectionPool#connection_descriptor` (a `ConnectionDescriptor` whose `#name` is the owning class name; 8.x `PoolConfig` has no `connection_class` either, so the obvious fallback route doesn't exist). Since the guard is prepended onto every purge/drop path, the `NoMethodError` aborted **every** `db:test:purge` / `db:prepare` on current stable Rails, forcing consumers to cap at `< 0.14`. Ownership is now resolved against whichever API the running Rails exposes — `connection_descriptor&.name == name` on 8.0+ (a nil descriptor, e.g. a null pool, never matches), `connection_class == self` on 7.x — with identical semantics: only `connects_to`-created BusRecord pools are disconnected, `ActiveRecord::Base`'s pool is never touched. The reason CI missed this: the spec stubbed `connection_class` on plain RSpec doubles, which happily fake methods the running Rails doesn't define. The spec now also exercises verifying doubles (`instance_double`) against the real `ConnectionPool`, so both existing matrix legs (7.1 and latest 8.x) fail on any future drift in the ownership API. Refs #411.
6
+
5
7
  - **Boot-time BusRecord connections no longer wedge `db:test:purge` — pgbus disconnects its own pools before every database purge/drop (issue #409).** With pgbus on a dedicated database (`config.connects_to`), any boot-time touch of a pgbus model left an idle session on that database for the life of the process. Rails' purge/drop only disconnects the connection it establishes for the target db_config — it knows nothing about gem-owned pools — so the rake process's own idle session blocked its own `DROP DATABASE`: a hang without a `statement_timeout`, a fast `ActiveRecord::QueryCanceled` with one, and either way `db:test:prepare` / `maintain_test_schema!` permanently broken on that machine (every retry re-boots, re-opens the connection, and re-blocks; terminating sessions externally can't help). Three changes: **(1)** `Pgbus::DatabaseTasksGuard` is prepended onto `ActiveRecord::Tasks::DatabaseTasks` at boot, so every route to a purge/drop — `db:test:purge` / `db:purge` / `db:drop` and their per-database variants, `maintain_test_schema!`'s in-process purge, parallel-testing's `TestDatabases` — first runs `Pgbus::BusRecord.disconnect_all_pools!` (all roles; a no-op on primary-database installs, `ActiveRecord::Base`'s pool is never touched). **(2)** The task-aware guard the event-bus registry already used internally is now public as **`Pgbus.database_task?`** — true while the process runs a `db:*` / `assets:*`-family rake task — so apps can skip their own boot-time warm-ups in the contexts where a database may legitimately not exist. **(3)** `pgbus:tune_autovacuum` (enhanced onto `db:schema:load`) no longer holds a permanent connection lease from `BusRecord.connection`: it checks out via `connection_pool.with_connection` and disconnects the pool afterward, leaving no idle session behind inside longer rake chains. Refs #409.
6
8
 
7
9
  - **Concurrent queue creation no longer kills the loser with `PG::UniqueViolation` on `pg_class` (issue #404).** The sibling of the #403 trigger race, one DDL step earlier: `CREATE TABLE IF NOT EXISTS` is not race-safe — two backends creating a not-yet-existing queue both pass the existence check (READ COMMITTED; neither sees the other's uncommitted catalog rows), both insert into `pg_class`, and the loser raises `unique_violation` on `pg_class_relname_nsp_index` instead of the friendly `duplicate_table`. All the dedup guards (`@queues_created`, `Stream#@ensured`, `synchronized`) are process-local, so with lazily-created per-record durable stream queues two processes first-touching the same brand-new stream hit `pgmq.create` simultaneously — and via `send_message`'s `ensure_queue` the same window applies to plain job queues on cold post-deploy herds (production: AppSignal incident #963, an unrescued `PG::UniqueViolation` out of an unrelated `after_commit`). Three DDL steps now rescue the duplicate as success, mirroring the #397/#403 shape: **(1)** `create_queue_table` — `pgmq.create` is a single statement and therefore atomic, so when the loser unblocks the winner has committed the whole queue; the loser re-checks `pgmq.meta` and returns, retrying `pgmq.create` once when the re-check can't confirm (e.g. a leftover physical table without a meta row) with a second failure propagating (the retry's own error — the original duplicate is preserved deeper in its cause chain via Ruby's implicit `$!` chaining); **(2)** `create_fifo_index_if_needed` under group_mode — the duplicate proves the index exists; **(3)** the stream archive `msg_id` index in `ensure_stream_queue` — a raw `CREATE INDEX IF NOT EXISTS` with the same catalog race, where the loser now proceeds to register and memoize the stream instead of dropping the first broadcast. Duplicate detection reuses `DUPLICATE_INSTALL_ERROR_CLASSES`, matched directly (raw `conn.exec` paths) or as the `cause` of pgmq-ruby's `ConnectionError` wrapper. No locking added, no happy-path cost. Refs #404.
@@ -24,8 +24,22 @@ module Pgbus
24
24
  # the next checkout after a disconnect reconnects transparently.
25
25
  def self.disconnect_all_pools!
26
26
  connection_handler.connection_pool_list(:all).each do |pool|
27
- pool.disconnect! if pool.connection_class == self
27
+ pool.disconnect! if owns_pool?(pool)
28
28
  end
29
29
  end
30
+
31
+ # Rails 8.0 replaced ConnectionPool#connection_class with
32
+ # #connection_descriptor — a ConnectionDescriptor whose #name is the
33
+ # owning class name (issue #411). Pools `connects_to` creates register
34
+ # under the class name, so the name comparison is equivalent to the
35
+ # class-identity check on 7.x. A nil descriptor (null pool) never matches.
36
+ def self.owns_pool?(pool)
37
+ if pool.respond_to?(:connection_descriptor)
38
+ pool.connection_descriptor&.name == name
39
+ else
40
+ pool.connection_class == self
41
+ end
42
+ end
43
+ private_class_method :owns_pool?
30
44
  end
31
45
  end
data/lib/pgbus/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Pgbus
4
- VERSION = "0.14.0"
4
+ VERSION = "0.14.1"
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pgbus
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.14.0
4
+ version: 0.14.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mikael Henriksson