pgbus 0.7.6 → 0.7.8

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: a28025e2b7af463cb6ff57d12e516d461b9b968ed7bb4eb4568be18d77ff2678
4
- data.tar.gz: fd39f5774df158b0cf06e85a6ef52f0114d649008f56b4736a782ce895baae0b
3
+ metadata.gz: 48e02fc16de64a9ccec20b8b0d917e154e17dc2082c1e3933b80da1bdc2f0c2a
4
+ data.tar.gz: 811db2dfcb4c4271296d9125754af3865b117ebc8b45d3194bc4314cc43ffaba
5
5
  SHA512:
6
- metadata.gz: 19ced25de78f93ccbf307e2bdd72a5dbc46050657c6e394bc9e6a16d8665fa19bc2a29cebf2fcbda8c31eb07e07d94545322eec80c5d61915ddd6bfc924de105
7
- data.tar.gz: 9d8e2a9255ce011edf6bc2647fbd4d604db65b8fb2470c17735149599072f2824e510db4e97c4d241cdd4d6a9fef2ff7c23638738cd40de581ee56a07b783f6b
6
+ metadata.gz: 2b41cd760d469af41c4e0ef0d9bfaffd3cb17ff81b38dbeb250605d78c737708f54ee43519fe25afeda83a5e15177a14e89e48d27471ae39ad5c79420d791e21
7
+ data.tar.gz: 50f209ed7b74e18c1bf927ca73fe80286c9a4333642af4f32e579bd6f9e40158007c07a39dfa6a3fc2082fd9ad1663f3e9b109ebd7021485f931a615ad9baabb
data/CHANGELOG.md CHANGED
@@ -15,6 +15,7 @@
15
15
 
16
16
  ### Fixed
17
17
 
18
+ - **EventBus handler invocations now run inside `Rails.application.executor` (or `.reloader` in dev).** `Pgbus::EventBus::Handler#process` previously ran outside any Rails executor wrapper, so `claim_idempotency?`'s `ProcessedEvent.insert` (and any `handle` body that touches AR) leased a connection that was never returned to the pool. With a small AR pool (Rails dev default with `RAILS_MAX_THREADS=3` is 6 connections), a handful of consumed events leaked the entire pool. The next request that triggers `clear_reloadable_connections!` (any reloadable change in dev) hung in `with_exclusively_acquired_all_connections`, surfacing as a confusing `Rack::Timeout` with a trace ending in `MonitorMixin#wait_for_cond`. Mirrors the executor-wrap pattern already used by `Pgbus::ActiveJob::Executor#execute_job`. No-op when Rails isn't loaded.
18
19
  - **Defensive retry on stale pooled pgmq connections in the enqueue path.** `Pgbus::Client#send_message`, `#send_batch`, and `#publish_to_topic` now retry once when `@pgmq.produce*` raises `PGMQ::Errors::ConnectionError` with a message indicating the pooled `PG::Connection` was killed beneath pgmq-ruby — typically by PgBouncer hitting `server_idle_timeout` / `client_idle_timeout`, an admin disconnect, or a TCP RST. Observed in production as `PQsocket() can't get socket descriptor` on the first produce following an idle window. pgmq-ruby's `auto_reconnect` recovers on the *next* pool checkout, so a single retry is sufficient; non-stale errors (pool timeout, misconfiguration, unreachable database) still propagate unchanged. Upstream pgmq-ruby fix for the underlying misclassification is in-flight at mensfeld/pgmq-ruby#94.
19
20
 
20
21
  ## [0.5.1] - 2026-04-08
@@ -107,12 +107,22 @@ module Pgbus
107
107
 
108
108
  def execute_job(job)
109
109
  if defined?(Rails) && Rails.respond_to?(:application) && Rails.application
110
- Rails.application.executor.wrap { job.perform_now }
110
+ wrapper = reloading? ? Rails.application.reloader : Rails.application.executor
111
+ wrapper.wrap { job.perform_now }
111
112
  else
112
113
  job.perform_now
113
114
  end
114
115
  end
115
116
 
117
+ def reloading?
118
+ app_config = Rails.application.config
119
+ if app_config.respond_to?(:enable_reloading)
120
+ app_config.enable_reloading
121
+ else
122
+ !app_config.cache_classes
123
+ end
124
+ end
125
+
116
126
  def monotonic_now
117
127
  ::Process.clock_gettime(::Process::CLOCK_MONOTONIC)
118
128
  end
@@ -18,6 +18,16 @@ module Pgbus
18
18
  end
19
19
 
20
20
  def process(message)
21
+ with_rails_executor { process!(message) }
22
+ end
23
+
24
+ def handle(event)
25
+ raise NotImplementedError, "#{self.class.name} must implement #handle(event)"
26
+ end
27
+
28
+ private
29
+
30
+ def process!(message)
21
31
  raw = JSON.parse(message.message)
22
32
  event = build_event(raw)
23
33
 
@@ -28,11 +38,30 @@ module Pgbus
28
38
  :handled
29
39
  end
30
40
 
31
- def handle(event)
32
- raise NotImplementedError, "#{self.class.name} must implement #handle(event)"
41
+ # Mirrors Pgbus::ActiveJob::Executor#execute_job: wrap the handler
42
+ # invocation in Rails.application.executor (or the reloader in dev)
43
+ # so AR connections leased by `claim_idempotency?` and `handle` are
44
+ # released back to the pool when this method returns. Without the
45
+ # wrap, every consumed event leaks one AR connection on the consumer
46
+ # thread — in dev that wedges `clear_reloadable_connections!`,
47
+ # producing a confusing Rack::Timeout in `MonitorMixin#wait_for_cond`.
48
+ #
49
+ # No-op when Rails isn't loaded (test harnesses, gem-only consumers).
50
+ def with_rails_executor(&)
51
+ return yield unless defined?(Rails) && Rails.respond_to?(:application) && Rails.application
52
+
53
+ wrapper = reloading? ? Rails.application.reloader : Rails.application.executor
54
+ wrapper.wrap(&)
33
55
  end
34
56
 
35
- private
57
+ def reloading?
58
+ app_config = Rails.application.config
59
+ if app_config.respond_to?(:enable_reloading)
60
+ app_config.enable_reloading
61
+ else
62
+ !app_config.cache_classes
63
+ end
64
+ end
36
65
 
37
66
  def build_event(raw)
38
67
  payload = raw["payload"]
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.7.6"
4
+ VERSION = "0.7.8"
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.7.6
4
+ version: 0.7.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mikael Henriksson