pgbus 0.14.2 → 0.15.0
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 +7 -0
- data/README.md +33 -0
- data/Rakefile +6 -1
- data/app/helpers/pgbus/application_helper.rb +7 -0
- data/app/views/pgbus/dead_letter/show.html.erb +17 -0
- data/app/views/pgbus/events/_pending_table.html.erb +21 -0
- data/app/views/pgbus/jobs/show.html.erb +17 -0
- data/config/locales/da.yml +3 -0
- data/config/locales/de.yml +3 -0
- data/config/locales/en.yml +3 -0
- data/config/locales/es.yml +3 -0
- data/config/locales/fi.yml +3 -0
- data/config/locales/fr.yml +3 -0
- data/config/locales/it.yml +3 -0
- data/config/locales/ja.yml +3 -0
- data/config/locales/nb.yml +3 -0
- data/config/locales/nl.yml +3 -0
- data/config/locales/pt.yml +3 -0
- data/config/locales/sv.yml +3 -0
- data/lib/pgbus/active_job/adapter.rb +5 -1
- data/lib/pgbus/active_job/current_attributes.rb +52 -0
- data/lib/pgbus/client/fair_read.rb +187 -0
- data/lib/pgbus/client.rb +30 -3
- data/lib/pgbus/configuration.rb +57 -0
- data/lib/pgbus/current_attributes.rb +156 -0
- data/lib/pgbus/engine.rb +1 -0
- data/lib/pgbus/event.rb +7 -2
- data/lib/pgbus/event_bus/handler.rb +12 -2
- data/lib/pgbus/event_bus/publisher.rb +37 -2
- data/lib/pgbus/event_bus/subscriber.rb +4 -0
- data/lib/pgbus/fair_share.rb +110 -0
- data/lib/pgbus/outbox.rb +8 -1
- data/lib/pgbus/process/consumer.rb +38 -1
- data/lib/pgbus/process/worker.rb +41 -0
- data/lib/pgbus/testing.rb +2 -1
- data/lib/pgbus/version.rb +1 -1
- data/lib/pgbus/web/job_context.rb +80 -0
- data/lib/pgbus.rb +2 -0
- metadata +6 -1
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Pgbus
|
|
4
|
+
# Fair share scheduling across tenants (issue #426).
|
|
5
|
+
#
|
|
6
|
+
# At enqueue time the configured callable (`config.fair_share`) resolves a
|
|
7
|
+
# key — typically a tenant id — and an optional weight for the job. Both
|
|
8
|
+
# ride inside the job payload hash (same pattern as Concurrency::METADATA_KEY
|
|
9
|
+
# and Batch::METADATA_KEY), so they survive every path that re-sends a
|
|
10
|
+
# payload: blocked-execution promotion, DLQ retry, dashboard retry, bulk
|
|
11
|
+
# enqueue. On the read side Client#read_batch_fair interleaves across keys
|
|
12
|
+
# proportionally to weight (see Client::FairRead).
|
|
13
|
+
#
|
|
14
|
+
# Events (issue #427) use the same keys and the same read primitive: the
|
|
15
|
+
# configured `config.event_fair_share` callable receives the Pgbus::Event at
|
|
16
|
+
# publish time and the key rides in the event *envelope* (a sibling of
|
|
17
|
+
# event_id / payload / published_at — never inside the user payload), so the
|
|
18
|
+
# same `message->>'pgbus_fair_key'` expression, index and read SQL serve both
|
|
19
|
+
# jobs and events, and the outbox (which stores the envelope) carries it.
|
|
20
|
+
module FairShare
|
|
21
|
+
METADATA_KEY = "pgbus_fair_key"
|
|
22
|
+
WEIGHT_KEY = "pgbus_fair_weight"
|
|
23
|
+
DEFAULT_WEIGHT = 1
|
|
24
|
+
|
|
25
|
+
class << self
|
|
26
|
+
def enabled?(config = Pgbus.configuration)
|
|
27
|
+
!config.fair_share.nil?
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def event_enabled?(config = Pgbus.configuration)
|
|
31
|
+
!config.event_fair_share.nil?
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# Returns the payload with fair-share metadata merged in, or the payload
|
|
35
|
+
# itself (same object) when fair share is off or the job is unkeyed.
|
|
36
|
+
# Exceptions raised by the callable propagate — a key resolver that
|
|
37
|
+
# cannot run is a programmer error, not something to swallow at enqueue.
|
|
38
|
+
def inject_metadata(active_job, payload_hash, config = Pgbus.configuration)
|
|
39
|
+
return payload_hash unless enabled?(config)
|
|
40
|
+
|
|
41
|
+
tag(payload_hash, resolve(active_job, config))
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
# Event twin of inject_metadata: returns the event envelope (the hash
|
|
45
|
+
# Publisher.build_event_data produced) with fair-share metadata merged
|
|
46
|
+
# in, or the envelope itself (same object) when event fair share is off
|
|
47
|
+
# or the callable declines to key the event.
|
|
48
|
+
def inject_event_metadata(event, event_data, config = Pgbus.configuration)
|
|
49
|
+
return event_data unless event_enabled?(config)
|
|
50
|
+
|
|
51
|
+
tag(event_data, resolve_event(event, config))
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# [key, weight] for the job, or nil when the callable declines to key it.
|
|
55
|
+
def resolve(active_job, config = Pgbus.configuration)
|
|
56
|
+
normalize(config.fair_share.call(active_job))
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
# [key, weight] for the event, or nil when the callable declines.
|
|
60
|
+
def resolve_event(event, config = Pgbus.configuration)
|
|
61
|
+
normalize(config.event_fair_share.call(event))
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def extract_key(payload)
|
|
65
|
+
payload[METADATA_KEY]
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def extract_weight(payload)
|
|
69
|
+
payload[WEIGHT_KEY] || DEFAULT_WEIGHT
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
private
|
|
73
|
+
|
|
74
|
+
def tag(hash, resolved)
|
|
75
|
+
return hash unless resolved
|
|
76
|
+
|
|
77
|
+
key, weight = resolved
|
|
78
|
+
tagged = hash.merge(METADATA_KEY => key)
|
|
79
|
+
tagged[WEIGHT_KEY] = weight unless weight == DEFAULT_WEIGHT
|
|
80
|
+
tagged
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def normalize(result)
|
|
84
|
+
return nil if result.nil?
|
|
85
|
+
|
|
86
|
+
raw_key, raw_weight = result.is_a?(Array) ? result : [result, nil]
|
|
87
|
+
[normalize_key(raw_key), normalize_weight(raw_weight)]
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def normalize_key(raw)
|
|
91
|
+
key = case raw
|
|
92
|
+
when String, Symbol, Integer then raw.to_s
|
|
93
|
+
else
|
|
94
|
+
raise ArgumentError,
|
|
95
|
+
"fair_share key must be a String, Symbol, or Integer (got #{raw.class})"
|
|
96
|
+
end
|
|
97
|
+
raise ArgumentError, "fair_share key must not be empty" if key.empty?
|
|
98
|
+
|
|
99
|
+
key
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
def normalize_weight(raw)
|
|
103
|
+
return DEFAULT_WEIGHT if raw.nil?
|
|
104
|
+
return raw if raw.is_a?(Numeric) && raw.positive?
|
|
105
|
+
|
|
106
|
+
raise ArgumentError, "fair_share weight must be a positive Numeric (got #{raw.inspect})"
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
end
|
data/lib/pgbus/outbox.rb
CHANGED
|
@@ -18,7 +18,14 @@ module Pgbus
|
|
|
18
18
|
|
|
19
19
|
def publish_event(routing_key, payload, headers: nil)
|
|
20
20
|
Instrumentation.instrument("pgbus.outbox.publish", routing_key: routing_key, kind: :event) do
|
|
21
|
-
|
|
21
|
+
# routing_key: in the envelope so the consumer can dispatch the relayed
|
|
22
|
+
# event to handlers — pgmq.send_topic matches queues at relay time but
|
|
23
|
+
# stamps nothing on the message, and Consumer#handle_message reads the
|
|
24
|
+
# routing key from the envelope (fixed alongside issue #431; previously
|
|
25
|
+
# relayed outbox events matched zero handlers and were archived unrun).
|
|
26
|
+
event_data = EventBus::Publisher.build_event_data(payload, routing_key: routing_key)
|
|
27
|
+
event_data = EventBus::Publisher.tag_fair_share(event_data, payload, routing_key: routing_key, headers: headers)
|
|
28
|
+
event_data = EventBus::Publisher.tag_current(event_data)
|
|
22
29
|
OutboxEntry.create!(
|
|
23
30
|
routing_key: routing_key,
|
|
24
31
|
payload: event_data,
|
|
@@ -116,6 +116,7 @@ module Pgbus
|
|
|
116
116
|
setup_signals
|
|
117
117
|
start_heartbeat
|
|
118
118
|
setup_subscriptions
|
|
119
|
+
ensure_fair_indexes
|
|
119
120
|
start_wake_source
|
|
120
121
|
Pgbus.logger.info do
|
|
121
122
|
"[Pgbus] Consumer started: topics=#{topics.join(",")} threads=#{threads} " \
|
|
@@ -188,7 +189,9 @@ module Pgbus
|
|
|
188
189
|
active_queues = @queue_names.reject { |q| @circuit_breaker.paused?(q) }
|
|
189
190
|
return [] if active_queues.empty?
|
|
190
191
|
|
|
191
|
-
if
|
|
192
|
+
if fair_share_enabled?
|
|
193
|
+
fetch_fair(active_queues, qty)
|
|
194
|
+
elsif active_queues.size == 1
|
|
192
195
|
queue = active_queues.first
|
|
193
196
|
(Pgbus.client.read_batch(queue, qty: qty) || []).map { |m| [queue, m] }
|
|
194
197
|
else
|
|
@@ -282,6 +285,40 @@ module Pgbus
|
|
|
282
285
|
end
|
|
283
286
|
end
|
|
284
287
|
|
|
288
|
+
# Fair share for consumers (issue #427): one weighted-interleave read per
|
|
289
|
+
# subscriber queue, in list order with the remaining capacity — strict
|
|
290
|
+
# order across queues, fair across tenants WITHIN each queue. Same loop
|
|
291
|
+
# shape as Worker#fetch_fair; the consumer has no priority levels or
|
|
292
|
+
# group mode, so this is the whole fair branch.
|
|
293
|
+
def fetch_fair(active_queues, qty)
|
|
294
|
+
remaining = qty
|
|
295
|
+
results = []
|
|
296
|
+
|
|
297
|
+
active_queues.each do |queue|
|
|
298
|
+
break if remaining <= 0
|
|
299
|
+
|
|
300
|
+
messages = Pgbus.client.read_batch_fair(queue, qty: remaining) || []
|
|
301
|
+
messages.each { |m| results << [queue, m] }
|
|
302
|
+
remaining -= messages.size
|
|
303
|
+
end
|
|
304
|
+
|
|
305
|
+
results
|
|
306
|
+
end
|
|
307
|
+
|
|
308
|
+
def fair_share_enabled?
|
|
309
|
+
FairShare.event_enabled?(config)
|
|
310
|
+
end
|
|
311
|
+
|
|
312
|
+
# Build the fair index on every subscriber queue this consumer reads
|
|
313
|
+
# (idempotent, memoized in the client, CONCURRENTLY so a populated queue
|
|
314
|
+
# is never write-locked). Subscriber queues created later get theirs from
|
|
315
|
+
# Subscriber#setup!.
|
|
316
|
+
def ensure_fair_indexes
|
|
317
|
+
return unless fair_share_enabled?
|
|
318
|
+
|
|
319
|
+
@queue_names.each { |q| Pgbus.client.ensure_fair_index(q) }
|
|
320
|
+
end
|
|
321
|
+
|
|
285
322
|
# Signal the loop to exit cleanly once a recycle limit is hit. The clean
|
|
286
323
|
# exit gets an immediate supervisor restart (supervisor.rb:305-307), so a
|
|
287
324
|
# fresh fork replaces this one before its memory grows unbounded — the
|
data/lib/pgbus/process/worker.rb
CHANGED
|
@@ -54,6 +54,11 @@ module Pgbus
|
|
|
54
54
|
raise ArgumentError,
|
|
55
55
|
"Invalid group_mode: #{@group_mode.inspect}. Must be nil, :fifo, or :round_robin"
|
|
56
56
|
end
|
|
57
|
+
if FairShare.enabled?(config) && (@group_mode || config.group_mode)
|
|
58
|
+
raise Pgbus::ConfigurationError,
|
|
59
|
+
"fair_share and group_mode are mutually exclusive — this worker has group_mode " \
|
|
60
|
+
"#{(@group_mode || config.group_mode).inspect} while config.fair_share is set"
|
|
61
|
+
end
|
|
57
62
|
@single_active_consumer = single_active_consumer
|
|
58
63
|
@consumer_priority = consumer_priority
|
|
59
64
|
@lifecycle = Lifecycle.new
|
|
@@ -165,6 +170,7 @@ module Pgbus
|
|
|
165
170
|
setup_signals
|
|
166
171
|
start_heartbeat
|
|
167
172
|
resolve_wildcard_queues
|
|
173
|
+
ensure_fair_indexes
|
|
168
174
|
start_wake_source
|
|
169
175
|
@lifecycle.transition_to!(:running)
|
|
170
176
|
Pgbus.logger.info do
|
|
@@ -284,6 +290,8 @@ module Pgbus
|
|
|
284
290
|
fetch_prioritized(active_queues, qty)
|
|
285
291
|
elsif @group_mode
|
|
286
292
|
fetch_grouped(active_queues, qty)
|
|
293
|
+
elsif fair_share_enabled?
|
|
294
|
+
fetch_fair(active_queues, qty)
|
|
287
295
|
elsif active_queues.size == 1
|
|
288
296
|
queue = active_queues.first
|
|
289
297
|
messages = Pgbus.client.read_batch(queue, qty: qty) || []
|
|
@@ -391,6 +399,38 @@ module Pgbus
|
|
|
391
399
|
results
|
|
392
400
|
end
|
|
393
401
|
|
|
402
|
+
# Fair share (issue #426): one weighted-interleave read per queue, in
|
|
403
|
+
# list order with the remaining capacity — strict priority ACROSS queues
|
|
404
|
+
# (the capsule DSL contract), fair WITHIN each queue. Same loop shape as
|
|
405
|
+
# fetch_prioritized; under priority_levels the client composes both.
|
|
406
|
+
def fetch_fair(active_queues, qty)
|
|
407
|
+
remaining = qty
|
|
408
|
+
results = []
|
|
409
|
+
|
|
410
|
+
active_queues.each do |queue|
|
|
411
|
+
break if remaining <= 0
|
|
412
|
+
|
|
413
|
+
messages = Pgbus.client.read_batch_fair(queue, qty: remaining) || []
|
|
414
|
+
messages.each { |m| results << [queue, m] }
|
|
415
|
+
remaining -= messages.size
|
|
416
|
+
end
|
|
417
|
+
|
|
418
|
+
results
|
|
419
|
+
end
|
|
420
|
+
|
|
421
|
+
def fair_share_enabled?
|
|
422
|
+
FairShare.enabled?(config)
|
|
423
|
+
end
|
|
424
|
+
|
|
425
|
+
# Build the fair index on every queue this worker serves (idempotent,
|
|
426
|
+
# memoized in the client, CONCURRENTLY so a populated queue is never
|
|
427
|
+
# write-locked). Queues created later get theirs at creation time.
|
|
428
|
+
def ensure_fair_indexes
|
|
429
|
+
return unless fair_share_enabled?
|
|
430
|
+
|
|
431
|
+
queues.each { |q| Pgbus.client.ensure_fair_index(q) }
|
|
432
|
+
end
|
|
433
|
+
|
|
394
434
|
def priority_enabled?
|
|
395
435
|
config.priority_levels && config.priority_levels > 1
|
|
396
436
|
end
|
|
@@ -448,6 +488,7 @@ module Pgbus
|
|
|
448
488
|
return if @last_wildcard_resolve && (monotonic_now - @last_wildcard_resolve) < WILDCARD_REFRESH_INTERVAL
|
|
449
489
|
|
|
450
490
|
resolve_wildcard_queues
|
|
491
|
+
ensure_fair_indexes
|
|
451
492
|
end
|
|
452
493
|
|
|
453
494
|
# When a "relation does not exist" error occurs, the queue was deleted.
|
data/lib/pgbus/testing.rb
CHANGED
|
@@ -54,7 +54,8 @@ module Pgbus
|
|
|
54
54
|
break unless event
|
|
55
55
|
|
|
56
56
|
Pgbus::EventBus::Registry.instance.handlers_for(event.routing_key).each do |subscriber|
|
|
57
|
-
|
|
57
|
+
# Restore the publisher's Current (issue #431) like the consumer does.
|
|
58
|
+
Pgbus::CurrentAttributes.restore(event.context) { subscriber.handler_class.new.handle(event) }
|
|
58
59
|
end
|
|
59
60
|
|
|
60
61
|
@mutex.synchronize { @events.shift }
|
data/lib/pgbus/version.rb
CHANGED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "json"
|
|
4
|
+
|
|
5
|
+
module Pgbus
|
|
6
|
+
module Web
|
|
7
|
+
# Presents the Current attributes persisted in a job payload
|
|
8
|
+
# (Pgbus::CurrentAttributes::METADATA_KEY) for the dashboard's Context
|
|
9
|
+
# card: { "Current" => { "tenant" => "gid://app/Tenant/42", ... } }.
|
|
10
|
+
#
|
|
11
|
+
# Pure presentation: ActiveJob argument encodings are unwrapped to display
|
|
12
|
+
# strings (a GlobalID shows its gid, a serialized Symbol/Time its value) —
|
|
13
|
+
# nothing is constantized or located. Callers pass the payload through
|
|
14
|
+
# PayloadFilter first (ApplicationHelper#pgbus_parse_message does), so
|
|
15
|
+
# sensitive values arrive already redacted.
|
|
16
|
+
module JobContext
|
|
17
|
+
AJ_GLOBALID = "_aj_globalid"
|
|
18
|
+
AJ_SERIALIZED = "_aj_serialized"
|
|
19
|
+
AJ_META_PREFIX = "_aj_"
|
|
20
|
+
|
|
21
|
+
module_function
|
|
22
|
+
|
|
23
|
+
def from_payload(payload)
|
|
24
|
+
data = parse(payload)
|
|
25
|
+
stored = data && data[Pgbus::CurrentAttributes::METADATA_KEY]
|
|
26
|
+
return nil unless stored.is_a?(Hash) && stored.any?
|
|
27
|
+
|
|
28
|
+
stored.to_h do |klass_name, attrs|
|
|
29
|
+
[klass_name.to_s, present_attrs(attrs)]
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def present_attrs(attrs)
|
|
34
|
+
return {} unless attrs.is_a?(Hash)
|
|
35
|
+
|
|
36
|
+
attrs.each_with_object({}) do |(name, value), out|
|
|
37
|
+
next if name.to_s.start_with?(AJ_META_PREFIX)
|
|
38
|
+
|
|
39
|
+
out[name.to_s] = display(value)
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# String form of a value for the card. Hashes/arrays that are ActiveJob
|
|
44
|
+
# encodings collapse to their payload; anything else renders as JSON
|
|
45
|
+
# (stable across Ruby versions — Hash#inspect changed in 3.4).
|
|
46
|
+
def display(value)
|
|
47
|
+
unwrapped = unwrap(value)
|
|
48
|
+
unwrapped.is_a?(String) ? unwrapped : JSON.generate(unwrapped)
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def unwrap(value)
|
|
52
|
+
case value
|
|
53
|
+
when Hash
|
|
54
|
+
return value[AJ_GLOBALID] if value.key?(AJ_GLOBALID)
|
|
55
|
+
return unwrap(value["value"]) if value.key?(AJ_SERIALIZED) && value.key?("value")
|
|
56
|
+
|
|
57
|
+
value.each_with_object({}) do |(k, v), out|
|
|
58
|
+
next if k.to_s.start_with?(AJ_META_PREFIX)
|
|
59
|
+
|
|
60
|
+
out[k] = unwrap(v)
|
|
61
|
+
end
|
|
62
|
+
when Array
|
|
63
|
+
value.map { |v| unwrap(v) }
|
|
64
|
+
else
|
|
65
|
+
value
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def parse(payload)
|
|
70
|
+
case payload
|
|
71
|
+
when Hash then payload
|
|
72
|
+
when String then JSON.parse(payload)
|
|
73
|
+
end
|
|
74
|
+
rescue JSON::ParserError
|
|
75
|
+
nil
|
|
76
|
+
end
|
|
77
|
+
private_class_method :parse
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
end
|
data/lib/pgbus.rb
CHANGED
|
@@ -49,6 +49,8 @@ module Pgbus
|
|
|
49
49
|
# comes back with a msg_id count that doesn't match the number of jobs sent —
|
|
50
50
|
# a data-integrity signal that some jobs may not have been persisted.
|
|
51
51
|
class EnqueueError < Error; end
|
|
52
|
+
# A Current attribute could not be serialized for job persistence (issue #430).
|
|
53
|
+
class CurrentAttributesError < Error; end
|
|
52
54
|
|
|
53
55
|
# Raised by the execution pools when work can't be accepted: the pool is
|
|
54
56
|
# shutting down, or it's momentarily at capacity. Consumer-reachable during
|
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.
|
|
4
|
+
version: 0.15.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Mikael Henriksson
|
|
@@ -257,6 +257,7 @@ files:
|
|
|
257
257
|
- lib/pgbus.rb
|
|
258
258
|
- lib/pgbus/active_job/adapter.rb
|
|
259
259
|
- lib/pgbus/active_job/batch_id.rb
|
|
260
|
+
- lib/pgbus/active_job/current_attributes.rb
|
|
260
261
|
- lib/pgbus/active_job/executor.rb
|
|
261
262
|
- lib/pgbus/autovacuum_tuning.rb
|
|
262
263
|
- lib/pgbus/batch.rb
|
|
@@ -269,6 +270,7 @@ files:
|
|
|
269
270
|
- lib/pgbus/client.rb
|
|
270
271
|
- lib/pgbus/client/connection_health.rb
|
|
271
272
|
- lib/pgbus/client/ensure_stream_queue.rb
|
|
273
|
+
- lib/pgbus/client/fair_read.rb
|
|
272
274
|
- lib/pgbus/client/notify_stream.rb
|
|
273
275
|
- lib/pgbus/client/read_after.rb
|
|
274
276
|
- lib/pgbus/client/resizable_pool.rb
|
|
@@ -277,6 +279,7 @@ files:
|
|
|
277
279
|
- lib/pgbus/concurrency/semaphore.rb
|
|
278
280
|
- lib/pgbus/configuration.rb
|
|
279
281
|
- lib/pgbus/configuration/capsule_dsl.rb
|
|
282
|
+
- lib/pgbus/current_attributes.rb
|
|
280
283
|
- lib/pgbus/database_tasks_guard.rb
|
|
281
284
|
- lib/pgbus/dedicated_connection.rb
|
|
282
285
|
- lib/pgbus/dedup_cache.rb
|
|
@@ -292,6 +295,7 @@ files:
|
|
|
292
295
|
- lib/pgbus/execution_pools/async_pool.rb
|
|
293
296
|
- lib/pgbus/execution_pools/thread_pool.rb
|
|
294
297
|
- lib/pgbus/failed_event_recorder.rb
|
|
298
|
+
- lib/pgbus/fair_share.rb
|
|
295
299
|
- lib/pgbus/generators/database_target_detector.rb
|
|
296
300
|
- lib/pgbus/generators/migration_detector.rb
|
|
297
301
|
- lib/pgbus/health_probe.rb
|
|
@@ -394,6 +398,7 @@ files:
|
|
|
394
398
|
- lib/pgbus/web/data_source.rb
|
|
395
399
|
- lib/pgbus/web/health_app.rb
|
|
396
400
|
- lib/pgbus/web/health_server.rb
|
|
401
|
+
- lib/pgbus/web/job_context.rb
|
|
397
402
|
- lib/pgbus/web/metrics_serializer.rb
|
|
398
403
|
- lib/pgbus/web/payload_filter.rb
|
|
399
404
|
- lib/pgbus/web/stream_app.rb
|