postburner 1.0.0.pre.6 → 1.0.0.pre.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 +4 -4
- data/README.md +88 -5
- data/lib/postburner/active_job/adapter.rb +21 -1
- data/lib/postburner/configuration.rb +78 -58
- data/lib/postburner/runner.rb +2 -1
- data/lib/postburner/version.rb +1 -1
- data/lib/postburner/workers/base.rb +5 -10
- data/lib/postburner/workers/worker.rb +80 -163
- data/lib/postburner.rb +19 -0
- 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: 38a691a9f1e5d99c0d6f19cbe7c4c605bd1e570787d1cb7c8b5ee862b3efa84c
|
|
4
|
+
data.tar.gz: 962f60d03662ee7dc119503f190d5f6376cd7be35a14b52c140d75141a837b0c
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: e4a3bdd33be9342b9e521ef806baff7e27375891f73487daba929aefc9abf1ac888dd037bf764b46c839b8f904e9b766558f1705d2eebbab612a9b27d1562577
|
|
7
|
+
data.tar.gz: 69e36547fbc73cab99f8d9991a62825019f4d201e041fdf7cfb508fd885c0ce3dc6b6801f6e1897fe4037877b0649718b7089566b42a68d5e622302797a4c3ac
|
data/README.md
CHANGED
|
@@ -127,6 +127,13 @@ beanstalkd -l 127.0.0.1 -p 11300 # Start beanstalkd
|
|
|
127
127
|
bundle exec rails generate postburner:install
|
|
128
128
|
bundle exec rails db:migrate
|
|
129
129
|
|
|
130
|
+
# application.rb
|
|
131
|
+
config.active_job.queue_adapter = :postburner
|
|
132
|
+
# Note: Postburner auto-prefixes queue names with "postburner.{env}." similar to:
|
|
133
|
+
#config.active_job.queue_name_prefix = Postburner.tube_prefix(Rails.env) # i.e. "postburner.#{Rails.env}"
|
|
134
|
+
config.action_mailer.deliver_later_queue_name = 'mailers' # gets prefixed by config.active_job.queue_name_prefix
|
|
135
|
+
|
|
136
|
+
|
|
130
137
|
bundle exec postburner # start with bin/postburner
|
|
131
138
|
bundle exec rake postburner:work # or with rake task
|
|
132
139
|
```
|
|
@@ -1084,6 +1091,42 @@ production: # <- environment config, i.e. defaults
|
|
|
1084
1091
|
- mailers
|
|
1085
1092
|
```
|
|
1086
1093
|
|
|
1094
|
+
### Queue Names
|
|
1095
|
+
|
|
1096
|
+
Postburner automatically prefixes all queue names with `postburner.{env}.` to create Beanstalkd tube names. This namespacing prevents collisions when multiple applications share the same Beanstalkd server.
|
|
1097
|
+
|
|
1098
|
+
**The same base queue name is used everywhere:**
|
|
1099
|
+
|
|
1100
|
+
| Context | Syntax | Beanstalkd Tube |
|
|
1101
|
+
|---------|--------|-----------------|
|
|
1102
|
+
| ActiveJob | `queue_as :mailers` | `postburner.production.mailers` |
|
|
1103
|
+
| Postburner::Job | `queue 'mailers'` | `postburner.production.mailers` |
|
|
1104
|
+
| postburner.yml | `queues: [mailers]` | `postburner.production.mailers` |
|
|
1105
|
+
|
|
1106
|
+
**Example:**
|
|
1107
|
+
|
|
1108
|
+
```ruby
|
|
1109
|
+
# app/jobs/welcome_email_job.rb
|
|
1110
|
+
class WelcomeEmailJob < ApplicationJob
|
|
1111
|
+
queue_as :mailers # Uses base name 'mailers'
|
|
1112
|
+
end
|
|
1113
|
+
```
|
|
1114
|
+
|
|
1115
|
+
```yaml
|
|
1116
|
+
# config/postburner.yml
|
|
1117
|
+
production:
|
|
1118
|
+
workers:
|
|
1119
|
+
email_worker:
|
|
1120
|
+
queues:
|
|
1121
|
+
- mailers # Same base name 'mailers'
|
|
1122
|
+
```
|
|
1123
|
+
|
|
1124
|
+
Both refer to the Beanstalkd tube `postburner.production.mailers`.
|
|
1125
|
+
|
|
1126
|
+
**Naming convention:** Use underscores for multi-word queue names (e.g., `background_jobs`, `high_priority`). Avoid hyphens as they can cause issues with some Beanstalkd client libraries.
|
|
1127
|
+
|
|
1128
|
+
**Important:** No need to set `config.active_job.queue_name_prefix` - Postburner handles prefixing automatically, when jobs are enqueued with postburner.
|
|
1129
|
+
|
|
1087
1130
|
### Queue Configuration Methods
|
|
1088
1131
|
|
|
1089
1132
|
For `Postburner::Job` subclasses (and backwards compatibility):
|
|
@@ -1333,7 +1376,25 @@ job.attempts # Array of attempt timestamps
|
|
|
1333
1376
|
|
|
1334
1377
|
## Beanstalkd Integration
|
|
1335
1378
|
|
|
1336
|
-
|
|
1379
|
+
Postburner uses [Beaneater](https://github.com/beanstalkd/beaneater) as the Ruby client for Beanstalkd. You can access the underlying Beaneater connection directly for advanced operations.
|
|
1380
|
+
|
|
1381
|
+
### Connection Methods
|
|
1382
|
+
|
|
1383
|
+
```ruby
|
|
1384
|
+
# Get a cached Beaneater connection (returns Beaneater instance)
|
|
1385
|
+
conn = Postburner.connection
|
|
1386
|
+
conn.tubes.to_a # List all tubes
|
|
1387
|
+
conn.stats # Server statistics
|
|
1388
|
+
|
|
1389
|
+
# Block form - yields connection, recommended for one-off operations
|
|
1390
|
+
Postburner.connected do |conn|
|
|
1391
|
+
conn.tubes.to_a # List all tubes
|
|
1392
|
+
conn.tubes['postburner.production.critical'].stats
|
|
1393
|
+
conn.tubes['postburner.production.critical'].kick(10) # Kick 10 buried jobs
|
|
1394
|
+
end
|
|
1395
|
+
```
|
|
1396
|
+
|
|
1397
|
+
### Job-Level Access
|
|
1337
1398
|
|
|
1338
1399
|
```ruby
|
|
1339
1400
|
# Get Beanstalkd job ID
|
|
@@ -1342,12 +1403,25 @@ job.bkid # => 12345
|
|
|
1342
1403
|
# Access Beaneater job object
|
|
1343
1404
|
job.bk.stats
|
|
1344
1405
|
# => {"id"=>12345, "tube"=>"critical", "state"=>"ready", ...}
|
|
1406
|
+
```
|
|
1345
1407
|
|
|
1346
|
-
|
|
1408
|
+
### Beaneater API
|
|
1409
|
+
|
|
1410
|
+
The connection object is a standard Beaneater instance. See the [Beaneater documentation](https://github.com/beanstalkd/beaneater) for full API details:
|
|
1411
|
+
|
|
1412
|
+
```ruby
|
|
1347
1413
|
Postburner.connected do |conn|
|
|
1348
|
-
|
|
1349
|
-
conn.tubes
|
|
1350
|
-
conn.tubes['
|
|
1414
|
+
# Tubes
|
|
1415
|
+
conn.tubes.to_a # List all tube names
|
|
1416
|
+
conn.tubes['my-tube'].stats # Tube statistics
|
|
1417
|
+
conn.tubes['my-tube'].peek(:ready) # Peek at next ready job
|
|
1418
|
+
conn.tubes['my-tube'].kick(10) # Kick 10 buried jobs
|
|
1419
|
+
|
|
1420
|
+
# Server
|
|
1421
|
+
conn.stats # Server statistics
|
|
1422
|
+
|
|
1423
|
+
# Jobs
|
|
1424
|
+
conn.jobs.find(12345) # Find job by ID
|
|
1351
1425
|
end
|
|
1352
1426
|
```
|
|
1353
1427
|
|
|
@@ -1557,6 +1631,15 @@ There is a CLAUDE.md file for guidance when using Claude Code. Please use it or
|
|
|
1557
1631
|
|
|
1558
1632
|
We encourage AI tools, but do not vibe, as the code must look like it was written by a human. Code that contains AI agent idioms will be rejected. Code that doesn't follow the project conventions will be rejected.
|
|
1559
1633
|
|
|
1634
|
+
|
|
1635
|
+
### Testing
|
|
1636
|
+
|
|
1637
|
+
```bash
|
|
1638
|
+
bundle install
|
|
1639
|
+
bundle exec rails test # must have beanstalkd on 11300 by default
|
|
1640
|
+
bundle exec rails app:postburner:work # if you want to run the worker
|
|
1641
|
+
```
|
|
1642
|
+
|
|
1560
1643
|
## License
|
|
1561
1644
|
|
|
1562
1645
|
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
|
@@ -8,6 +8,24 @@ module ActiveJob
|
|
|
8
8
|
# - **Default mode**: Fast execution via Beanstalkd only
|
|
9
9
|
# - **Tracked mode** (opt-in): Full PostgreSQL audit trail
|
|
10
10
|
#
|
|
11
|
+
# ## Queue Name Prefixing
|
|
12
|
+
#
|
|
13
|
+
# Postburner automatically prefixes all queue names with `postburner.{env}.`
|
|
14
|
+
# to create Beanstalkd tube names. This means:
|
|
15
|
+
#
|
|
16
|
+
# - `queue_as :default` → tube `postburner.production.default`
|
|
17
|
+
# - `queue_as :mailers` → tube `postburner.production.mailers`
|
|
18
|
+
#
|
|
19
|
+
# The same base queue names are used across:
|
|
20
|
+
# - ActiveJob: `queue_as :default`
|
|
21
|
+
# - Postburner::Job: `queue 'default'`
|
|
22
|
+
# - config/postburner.yml: `queues: [default]`
|
|
23
|
+
#
|
|
24
|
+
# All refer to the same Beanstalkd tube after prefixing.
|
|
25
|
+
#
|
|
26
|
+
# @note Do NOT set `config.active_job.queue_name_prefix` - Postburner
|
|
27
|
+
# handles prefixing automatically via {#expand_tube_name}.
|
|
28
|
+
#
|
|
11
29
|
# ## Usage
|
|
12
30
|
#
|
|
13
31
|
# @example Configure in Rails
|
|
@@ -16,6 +34,8 @@ module ActiveJob
|
|
|
16
34
|
#
|
|
17
35
|
# @example Default job (fast)
|
|
18
36
|
# class SendEmail < ApplicationJob
|
|
37
|
+
# queue_as :mailers # → postburner.production.mailers
|
|
38
|
+
#
|
|
19
39
|
# def perform(user_id)
|
|
20
40
|
# # No PostgreSQL overhead, executes quickly
|
|
21
41
|
# end
|
|
@@ -24,7 +44,7 @@ module ActiveJob
|
|
|
24
44
|
# @example Tracked job (opt-in for audit trail)
|
|
25
45
|
# class ProcessPayment < ApplicationJob
|
|
26
46
|
# include Postburner::Tracked
|
|
27
|
-
#
|
|
47
|
+
# queue_as :critical # → postburner.production.critical
|
|
28
48
|
#
|
|
29
49
|
# def perform(payment_id)
|
|
30
50
|
# log "Processing payment..."
|
|
@@ -10,37 +10,48 @@ module Postburner
|
|
|
10
10
|
# @example Programmatic configuration
|
|
11
11
|
# Postburner.configure do |config|
|
|
12
12
|
# config.beanstalk_url = 'beanstalk://localhost:11300'
|
|
13
|
-
# config.worker_type = :threads_on_fork
|
|
14
13
|
# config.logger = Rails.logger
|
|
14
|
+
# config.worker_config = { name: 'default', queues: ['default'], forks: 2, threads: 10 }
|
|
15
15
|
# end
|
|
16
16
|
#
|
|
17
17
|
# @example Loading from YAML
|
|
18
|
-
# config = Postburner::Configuration.load_yaml('config/postburner.yml', 'production')
|
|
18
|
+
# config = Postburner::Configuration.load_yaml('config/postburner.yml', 'production', 'imports')
|
|
19
19
|
#
|
|
20
20
|
class Configuration
|
|
21
|
-
|
|
21
|
+
# Global settings
|
|
22
|
+
attr_accessor :beanstalk_url, :logger, :default_queue, :default_priority, :default_ttr
|
|
23
|
+
|
|
24
|
+
# Worker-specific settings (loaded for a single worker)
|
|
25
|
+
attr_accessor :worker_config
|
|
22
26
|
|
|
23
27
|
# @param options [Hash] Configuration options
|
|
24
28
|
# @option options [String] :beanstalk_url Beanstalkd URL (default: ENV['BEANSTALK_URL'] or localhost)
|
|
25
29
|
# @option options [Logger] :logger Logger instance (default: Rails.logger)
|
|
26
|
-
# @option options [Hash] :queues Queue configurations
|
|
27
30
|
# @option options [String] :default_queue Default queue name (default: 'default')
|
|
28
31
|
# @option options [Integer] :default_priority Default job priority (default: 65536, lower = higher priority)
|
|
29
32
|
# @option options [Integer] :default_ttr Default time-to-run in seconds (default: 300)
|
|
30
|
-
# @option options [
|
|
31
|
-
#
|
|
32
|
-
#
|
|
33
|
+
# @option options [Hash] :worker_config Worker configuration hash with keys:
|
|
34
|
+
# - :name [String] Worker name
|
|
35
|
+
# - :queues [Array<String>] Queue/tube names to process
|
|
36
|
+
# - :forks [Integer] Number of forked processes (0 = single process mode)
|
|
37
|
+
# - :threads [Integer] Number of threads per fork
|
|
38
|
+
# - :gc_limit [Integer, nil] Jobs to process before restart (nil = unlimited)
|
|
39
|
+
# - :timeout [Integer] Reserve command timeout in seconds (1-10, default: 3)
|
|
33
40
|
#
|
|
34
41
|
def initialize(options = {})
|
|
35
42
|
@beanstalk_url = options[:beanstalk_url] || ENV['BEANSTALK_URL'] || 'beanstalk://localhost:11300'
|
|
36
43
|
@logger = options[:logger] || (defined?(Rails) ? Rails.logger : Logger.new(STDOUT))
|
|
37
|
-
@queues = options[:queues] || { 'default' => {} }
|
|
38
44
|
@default_queue = options[:default_queue] || 'default'
|
|
39
45
|
@default_priority = options[:default_priority] || 65536
|
|
40
46
|
@default_ttr = options[:default_ttr] || 300
|
|
41
|
-
@
|
|
42
|
-
|
|
43
|
-
|
|
47
|
+
@worker_config = options[:worker_config] || {
|
|
48
|
+
name: 'default',
|
|
49
|
+
queues: ['default'],
|
|
50
|
+
forks: 0,
|
|
51
|
+
threads: 1,
|
|
52
|
+
gc_limit: nil,
|
|
53
|
+
timeout: 3
|
|
54
|
+
}
|
|
44
55
|
end
|
|
45
56
|
|
|
46
57
|
# Loads configuration from a YAML file.
|
|
@@ -68,30 +79,31 @@ module Postburner
|
|
|
68
79
|
# beanstalk_url: beanstalk://localhost:11300
|
|
69
80
|
# default_priority: 131072 # change default priority from 65536 to 131072
|
|
70
81
|
#
|
|
71
|
-
# production: # <- environment config, i.e. defaults
|
|
82
|
+
# production: # <- environment config, i.e. defaults
|
|
72
83
|
# <<: *default
|
|
73
84
|
# default_forks: 2
|
|
74
85
|
# default_threads: 10
|
|
75
86
|
# default_gc_limit: 5000
|
|
76
87
|
# default_ttr: 300
|
|
77
|
-
# workers: # <- worker
|
|
78
|
-
# imports: # <- worker
|
|
88
|
+
# workers: # <- worker configs
|
|
89
|
+
# imports: # <- worker name
|
|
90
|
+
# timeout: 3 # Reserve timeout in seconds (1-10, default: 3)
|
|
91
|
+
# # Lower values enable faster graceful shutdowns
|
|
79
92
|
# forks: 4 # Overrides default_forks
|
|
80
93
|
# threads: 1 # Overrides default_threads
|
|
81
94
|
# gc_limit: 500 # Overrides default_gc_limit
|
|
82
|
-
# # ttr: 60 # Use default from production, i.e. 300 because not set
|
|
83
95
|
# queues:
|
|
84
96
|
# - imports
|
|
85
97
|
# - data_processing
|
|
86
98
|
#
|
|
87
99
|
def self.load_yaml(path, env = 'development', worker_name = nil)
|
|
88
100
|
yaml = YAML.load_file(path, aliases: true)
|
|
89
|
-
#
|
|
90
|
-
|
|
101
|
+
# env_config = top-level environment config (development:, production:, etc.)
|
|
102
|
+
env_config = yaml[env.to_s] || yaml[env.to_sym]
|
|
91
103
|
|
|
92
|
-
raise ArgumentError, "Environment '#{env}' not found in #{path}" unless
|
|
104
|
+
raise ArgumentError, "Environment '#{env}' not found in #{path}" unless env_config
|
|
93
105
|
|
|
94
|
-
workers =
|
|
106
|
+
workers = env_config['workers']
|
|
95
107
|
raise ArgumentError, "No 'workers:' section found in #{path} for environment '#{env}'" unless workers
|
|
96
108
|
|
|
97
109
|
# Auto-select single worker or validate worker_name
|
|
@@ -114,55 +126,39 @@ module Postburner
|
|
|
114
126
|
end
|
|
115
127
|
end
|
|
116
128
|
|
|
117
|
-
#
|
|
118
|
-
|
|
129
|
+
# worker_yaml = specific worker configuration from YAML (workers: imports:)
|
|
130
|
+
worker_yaml = workers[worker_name]
|
|
119
131
|
|
|
120
|
-
#
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
132
|
+
# Build worker_config hash - worker-level overrides env-level defaults
|
|
133
|
+
worker_config = {
|
|
134
|
+
name: worker_name,
|
|
135
|
+
queues: worker_yaml['queues'] || ['default'],
|
|
136
|
+
forks: worker_yaml['forks'] || env_config['default_forks'] || 0,
|
|
137
|
+
threads: worker_yaml['threads'] || env_config['default_threads'] || 1,
|
|
138
|
+
gc_limit: worker_yaml['gc_limit'] || env_config['default_gc_limit'],
|
|
139
|
+
timeout: worker_yaml['timeout'] || 3
|
|
140
|
+
}
|
|
126
141
|
|
|
127
|
-
# Cascade: worker-level overrides env-level defaults
|
|
128
|
-
# Worker uses: forks, threads, gc_limit, ttr, priority (NO default_ prefix)
|
|
129
|
-
# Env uses: default_forks, default_threads, etc. (WITH default_ prefix)
|
|
130
142
|
options = {
|
|
131
|
-
beanstalk_url:
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
default_threads: worker_config['threads'] || env_defaults['default_threads'],
|
|
137
|
-
default_forks: worker_config['forks'] || env_defaults['default_forks'],
|
|
138
|
-
default_gc_limit: worker_config['gc_limit'] || env_defaults['default_gc_limit']
|
|
143
|
+
beanstalk_url: env_config['beanstalk_url'],
|
|
144
|
+
default_queue: env_config['default_queue'],
|
|
145
|
+
default_priority: env_config['default_priority'],
|
|
146
|
+
default_ttr: env_config['default_ttr'],
|
|
147
|
+
worker_config: worker_config
|
|
139
148
|
}
|
|
140
149
|
|
|
141
150
|
new(options)
|
|
142
151
|
end
|
|
143
152
|
|
|
144
|
-
# Returns
|
|
145
|
-
#
|
|
146
|
-
# @param queue_name [String, Symbol] Name of the queue
|
|
147
|
-
#
|
|
148
|
-
# @return [Hash] Queue configuration with threads, gc_limit, etc.
|
|
149
|
-
#
|
|
150
|
-
# @example
|
|
151
|
-
# config.queue_config('critical') # => { threads: 1, gc_limit: 100 }
|
|
152
|
-
#
|
|
153
|
-
def queue_config(queue_name)
|
|
154
|
-
@queues[queue_name.to_s] || @queues[queue_name.to_sym] || {}
|
|
155
|
-
end
|
|
156
|
-
|
|
157
|
-
# Returns array of all configured queue names.
|
|
153
|
+
# Returns array of queue names from worker config.
|
|
158
154
|
#
|
|
159
155
|
# @return [Array<String>] Queue names
|
|
160
156
|
#
|
|
161
157
|
# @example
|
|
162
|
-
# config.queue_names # => ['
|
|
158
|
+
# config.queue_names # => ['imports', 'data_processing']
|
|
163
159
|
#
|
|
164
160
|
def queue_names
|
|
165
|
-
@queues.
|
|
161
|
+
@worker_config[:queues].map(&:to_s)
|
|
166
162
|
end
|
|
167
163
|
|
|
168
164
|
# Expands queue name to full tube name with environment prefix.
|
|
@@ -189,12 +185,35 @@ module Postburner
|
|
|
189
185
|
env ||= defined?(Rails) ? Rails.env : nil
|
|
190
186
|
queue_name ||= @default_queue
|
|
191
187
|
[
|
|
192
|
-
|
|
193
|
-
env,
|
|
188
|
+
tube_prefix(env),
|
|
194
189
|
queue_name,
|
|
195
190
|
].compact.join('.')
|
|
196
191
|
end
|
|
197
192
|
|
|
193
|
+
# Returns the Beanstalkd tube name prefix for the given environment.
|
|
194
|
+
#
|
|
195
|
+
# Postburner automatically prefixes all queue names with this value.
|
|
196
|
+
# The ActiveJob adapter expands queue names using this prefix, so
|
|
197
|
+
# `queue_as :default` becomes `postburner.production.default` in production.
|
|
198
|
+
#
|
|
199
|
+
# @param env [String, Symbol, nil] Environment name (defaults to Rails.env or nil)
|
|
200
|
+
#
|
|
201
|
+
# @return [String] Tube prefix (e.g., "postburner.production")
|
|
202
|
+
#
|
|
203
|
+
# @example
|
|
204
|
+
# config.tube_prefix('production') # => "postburner.production"
|
|
205
|
+
# config.tube_prefix # => "postburner.test" (in test env)
|
|
206
|
+
#
|
|
207
|
+
# @note Do not set ActiveJob's `queue_name_prefix` - Postburner handles
|
|
208
|
+
# queue name expansion automatically via the adapter.
|
|
209
|
+
#
|
|
210
|
+
def tube_prefix(env = nil)
|
|
211
|
+
env ||= defined?(Rails) ? Rails.env : nil
|
|
212
|
+
[
|
|
213
|
+
'postburner',
|
|
214
|
+
env,
|
|
215
|
+
].compact.join('.')
|
|
216
|
+
end
|
|
198
217
|
|
|
199
218
|
# Returns array of expanded tube names with environment prefix.
|
|
200
219
|
#
|
|
@@ -203,7 +222,8 @@ module Postburner
|
|
|
203
222
|
# @return [Array<String>] Array of expanded tube names
|
|
204
223
|
#
|
|
205
224
|
# @example
|
|
206
|
-
# config.expanded_tube_names('production') # => ['postburner.production.
|
|
225
|
+
# config.expanded_tube_names('production') # => ['postburner.production.imports', 'postburner.production.data_processing']
|
|
226
|
+
#
|
|
207
227
|
def expanded_tube_names(env = nil)
|
|
208
228
|
queue_names.map { |q| expand_tube_name(q, env) }
|
|
209
229
|
end
|
|
@@ -227,7 +247,7 @@ module Postburner
|
|
|
227
247
|
# @example
|
|
228
248
|
# Postburner.configure do |config|
|
|
229
249
|
# config.beanstalk_url = 'beanstalk://localhost:11300'
|
|
230
|
-
# config.
|
|
250
|
+
# config.worker_config = { name: 'default', queues: ['default'], forks: 2, threads: 10 }
|
|
231
251
|
# end
|
|
232
252
|
#
|
|
233
253
|
def self.configure
|
data/lib/postburner/runner.rb
CHANGED
|
@@ -87,7 +87,8 @@ module Postburner
|
|
|
87
87
|
config.logger.info "[Postburner] Environment: #{options[:env]}"
|
|
88
88
|
config.logger.info "[Postburner] Worker: #{options[:worker] || '(auto-selected)'}" if options[:worker] || options[:queues].nil?
|
|
89
89
|
config.logger.info "[Postburner] Queues: #{config.queue_names.join(', ')}"
|
|
90
|
-
|
|
90
|
+
wc = config.worker_config
|
|
91
|
+
config.logger.info "[Postburner] Worker config: forks=#{wc[:forks]}, threads=#{wc[:threads]}, gc_limit=#{wc[:gc_limit] || 'none'}, timeout=#{wc[:timeout]}s"
|
|
91
92
|
end
|
|
92
93
|
|
|
93
94
|
# Returns root directory for config file resolution.
|
data/lib/postburner/version.rb
CHANGED
|
@@ -189,21 +189,16 @@ module Postburner
|
|
|
189
189
|
[2 ** retry_count, 3600].min
|
|
190
190
|
end
|
|
191
191
|
|
|
192
|
-
# Watches
|
|
192
|
+
# Watches all configured queues in Beanstalkd.
|
|
193
193
|
#
|
|
194
194
|
# @param connection [Postburner::Connection] Beanstalkd connection
|
|
195
|
-
# @param queue_name [String, nil] Optional specific queue name to watch (watches all if nil)
|
|
196
195
|
#
|
|
197
196
|
# @return [void]
|
|
198
197
|
#
|
|
199
|
-
def watch_queues(connection,
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
else
|
|
204
|
-
tube_names = config.expanded_tube_names
|
|
205
|
-
connection.beanstalk.tubes.watch!(*tube_names)
|
|
206
|
-
end
|
|
198
|
+
def watch_queues(connection, queue_names=nil)
|
|
199
|
+
tube_names = queue_names.map { |q| config.expand_tube_name(q) }
|
|
200
|
+
tube_names = config.expanded_tube_names if tube_names.empty?
|
|
201
|
+
connection.beanstalk.tubes.watch!(*tube_names)
|
|
207
202
|
end
|
|
208
203
|
end
|
|
209
204
|
end
|
|
@@ -4,7 +4,7 @@ require 'concurrent'
|
|
|
4
4
|
|
|
5
5
|
module Postburner
|
|
6
6
|
module Workers
|
|
7
|
-
# Puma-style worker with configurable forks and threads
|
|
7
|
+
# Puma-style worker with configurable forks and threads.
|
|
8
8
|
#
|
|
9
9
|
# This is the universal Postburner worker that scales from development
|
|
10
10
|
# to production using forks and threads configuration. Just like Puma:
|
|
@@ -16,27 +16,18 @@ module Postburner
|
|
|
16
16
|
# ### Single Process Mode (forks: 0)
|
|
17
17
|
# ```
|
|
18
18
|
# Main Process
|
|
19
|
-
#
|
|
20
|
-
# ├─ Queue 'critical' Thread Pool (1 thread)
|
|
21
|
-
# └─ Queue 'mailers' Thread Pool (5 threads)
|
|
19
|
+
# └─ Thread Pool (N threads watching all queues)
|
|
22
20
|
# ```
|
|
23
21
|
#
|
|
24
22
|
# ### Multi-Process Mode (forks: 1+)
|
|
25
23
|
# ```
|
|
26
24
|
# Parent Process
|
|
27
|
-
# ├─ Fork 0
|
|
28
|
-
# │ └─ Thread
|
|
29
|
-
# ├─ Fork
|
|
30
|
-
# │
|
|
31
|
-
#
|
|
32
|
-
#
|
|
33
|
-
# ├─ Fork 2 (queue: default)
|
|
34
|
-
# │ └─ Thread 1-10
|
|
35
|
-
# ├─ Fork 3 (queue: default)
|
|
36
|
-
# │ └─ Thread 1-10
|
|
37
|
-
# │ └─ Total: 40 concurrent jobs for 'default' (4 forks × 10 threads)
|
|
38
|
-
# └─ Fork 0 (queue: mailers)
|
|
39
|
-
# └─ Thread 1-5
|
|
25
|
+
# ├─ Fork 0
|
|
26
|
+
# │ └─ Thread Pool (N threads watching all queues)
|
|
27
|
+
# ├─ Fork 1
|
|
28
|
+
# │ └─ Thread Pool (N threads watching all queues)
|
|
29
|
+
# └─ Fork 2
|
|
30
|
+
# └─ Thread Pool (N threads watching all queues)
|
|
40
31
|
# ```
|
|
41
32
|
#
|
|
42
33
|
# ## Scaling Strategy
|
|
@@ -60,38 +51,25 @@ module Postburner
|
|
|
60
51
|
# forks: 4
|
|
61
52
|
# threads: 10
|
|
62
53
|
# ```
|
|
63
|
-
# 4 processes × 10 threads = 40 concurrent jobs
|
|
54
|
+
# 4 processes × 10 threads = 40 concurrent jobs
|
|
64
55
|
#
|
|
65
56
|
# ## Configuration
|
|
66
57
|
#
|
|
67
58
|
# @example Development (single-threaded)
|
|
68
|
-
# development:
|
|
69
|
-
#
|
|
70
|
-
# default_threads: 1
|
|
71
|
-
# workers: # <- worker config, i.e. overrides
|
|
59
|
+
# development:
|
|
60
|
+
# workers:
|
|
72
61
|
# default:
|
|
62
|
+
# forks: 0
|
|
63
|
+
# threads: 1
|
|
73
64
|
# queues:
|
|
74
65
|
# - default
|
|
75
66
|
# - mailers
|
|
76
67
|
#
|
|
77
|
-
# @example
|
|
78
|
-
#
|
|
79
|
-
# default_forks: 0
|
|
80
|
-
# default_threads: 10
|
|
81
|
-
# default_gc_limit: 5000
|
|
82
|
-
# workers: # <- worker config, i.e. overrides
|
|
83
|
-
# default:
|
|
84
|
-
# queues:
|
|
85
|
-
# - critical
|
|
86
|
-
# - default
|
|
87
|
-
# - mailers
|
|
88
|
-
#
|
|
89
|
-
# @example Production (Puma-style: forks × threads with worker overrides)
|
|
90
|
-
# production: # <- environment config, i.e. defaults
|
|
68
|
+
# @example Production (Puma-style: forks × threads)
|
|
69
|
+
# production:
|
|
91
70
|
# default_forks: 2
|
|
92
71
|
# default_threads: 10
|
|
93
|
-
#
|
|
94
|
-
# workers: # <- worker config, i.e. overrides
|
|
72
|
+
# workers:
|
|
95
73
|
# default:
|
|
96
74
|
# forks: 4 # Overrides default_forks
|
|
97
75
|
# threads: 10 # Overrides default_threads
|
|
@@ -109,12 +87,13 @@ module Postburner
|
|
|
109
87
|
# @return [void]
|
|
110
88
|
#
|
|
111
89
|
def start
|
|
112
|
-
logger.info "[Postburner::Worker] Starting..."
|
|
90
|
+
logger.info "[Postburner::Worker] Starting worker '#{worker_config[:name]}'..."
|
|
113
91
|
logger.info "[Postburner::Worker] Queues: #{config.queue_names.join(', ')}"
|
|
92
|
+
logger.info "[Postburner::Worker] Config: #{worker_config[:forks]} forks, #{worker_config[:threads]} threads, gc_limit: #{worker_config[:gc_limit] || 'unlimited'}, timeout: #{worker_config[:timeout]}s"
|
|
114
93
|
logger.info "[Postburner] #{config.beanstalk_url} watching tubes: #{config.expanded_tube_names.join(', ')}"
|
|
115
94
|
|
|
116
95
|
# Detect mode based on fork configuration
|
|
117
|
-
if
|
|
96
|
+
if worker_config[:forks] > 0
|
|
118
97
|
start_forked_mode
|
|
119
98
|
else
|
|
120
99
|
start_single_process_mode
|
|
@@ -123,21 +102,17 @@ module Postburner
|
|
|
123
102
|
|
|
124
103
|
private
|
|
125
104
|
|
|
126
|
-
#
|
|
105
|
+
# Returns the worker configuration hash.
|
|
127
106
|
#
|
|
128
|
-
# @return [
|
|
107
|
+
# @return [Hash] Worker config with :name, :queues, :forks, :threads, :gc_limit, :timeout
|
|
129
108
|
#
|
|
130
|
-
def
|
|
131
|
-
config.
|
|
132
|
-
queue_config = config.queue_config(queue_name)
|
|
133
|
-
fork_count = queue_config['forks'] || queue_config[:forks] || config.default_forks
|
|
134
|
-
fork_count > 0
|
|
135
|
-
end
|
|
109
|
+
def worker_config
|
|
110
|
+
config.worker_config
|
|
136
111
|
end
|
|
137
112
|
|
|
138
113
|
# Starts worker in single-process mode (forks: 0).
|
|
139
114
|
#
|
|
140
|
-
# Creates thread
|
|
115
|
+
# Creates a thread pool that watches all configured queues.
|
|
141
116
|
# Suitable for development and moderate concurrency needs.
|
|
142
117
|
#
|
|
143
118
|
# @return [void]
|
|
@@ -147,12 +122,17 @@ module Postburner
|
|
|
147
122
|
|
|
148
123
|
# Track total jobs processed across all threads
|
|
149
124
|
@jobs_processed = Concurrent::AtomicFixnum.new(0)
|
|
150
|
-
@gc_limit =
|
|
125
|
+
@gc_limit = worker_config[:gc_limit]
|
|
126
|
+
|
|
127
|
+
# Create thread pool
|
|
128
|
+
thread_count = worker_config[:threads]
|
|
129
|
+
@pool = Concurrent::FixedThreadPool.new(thread_count)
|
|
151
130
|
|
|
152
|
-
#
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
131
|
+
# Spawn worker threads
|
|
132
|
+
thread_count.times do
|
|
133
|
+
@pool.post do
|
|
134
|
+
process_jobs
|
|
135
|
+
end
|
|
156
136
|
end
|
|
157
137
|
|
|
158
138
|
# Monitor for shutdown or GC limit
|
|
@@ -160,9 +140,10 @@ module Postburner
|
|
|
160
140
|
sleep 0.5
|
|
161
141
|
end
|
|
162
142
|
|
|
163
|
-
# Shutdown
|
|
143
|
+
# Shutdown pool gracefully
|
|
164
144
|
logger.info "[Postburner::Worker] Shutting down..."
|
|
165
|
-
|
|
145
|
+
@pool.shutdown
|
|
146
|
+
@pool.wait_for_termination(30)
|
|
166
147
|
|
|
167
148
|
if @gc_limit && @jobs_processed.value >= @gc_limit
|
|
168
149
|
logger.info "[Postburner::Worker] Reached GC limit (#{@jobs_processed.value} jobs), exiting for restart..."
|
|
@@ -172,49 +153,24 @@ module Postburner
|
|
|
172
153
|
end
|
|
173
154
|
end
|
|
174
155
|
|
|
175
|
-
#
|
|
176
|
-
#
|
|
177
|
-
# @param queue_name [String] Name of the queue to process
|
|
178
|
-
#
|
|
179
|
-
# @return [void]
|
|
180
|
-
#
|
|
181
|
-
def spawn_queue_threads(queue_name)
|
|
182
|
-
queue_config = config.queue_config(queue_name)
|
|
183
|
-
thread_count = queue_config['threads'] || queue_config[:threads] || config.default_threads
|
|
184
|
-
|
|
185
|
-
logger.info "[Postburner::Worker] Queue '#{queue_name}': #{thread_count} threads"
|
|
186
|
-
|
|
187
|
-
# Create thread pool
|
|
188
|
-
pool = Concurrent::FixedThreadPool.new(thread_count)
|
|
189
|
-
@pools[queue_name] = pool
|
|
190
|
-
|
|
191
|
-
# Spawn worker threads
|
|
192
|
-
thread_count.times do
|
|
193
|
-
pool.post do
|
|
194
|
-
process_jobs_in_single_process(queue_name)
|
|
195
|
-
end
|
|
196
|
-
end
|
|
197
|
-
end
|
|
198
|
-
|
|
199
|
-
# Processes jobs in a single thread (single-process mode).
|
|
156
|
+
# Processes jobs in a single thread.
|
|
200
157
|
#
|
|
201
158
|
# Each thread has its own Beanstalkd connection and reserves jobs
|
|
202
|
-
# from
|
|
203
|
-
#
|
|
204
|
-
# @param queue_name [String] Name of the queue to process
|
|
159
|
+
# from all configured queues.
|
|
205
160
|
#
|
|
206
161
|
# @return [void]
|
|
207
162
|
#
|
|
208
|
-
def
|
|
163
|
+
def process_jobs
|
|
209
164
|
connection = Postburner::Connection.new
|
|
165
|
+
timeout = worker_config[:timeout]
|
|
210
166
|
|
|
211
|
-
# Watch
|
|
212
|
-
watch_queues(connection,
|
|
167
|
+
# Watch all configured queues
|
|
168
|
+
watch_queues(connection, config.queue_names)
|
|
213
169
|
|
|
214
170
|
until shutdown? || (@gc_limit && @jobs_processed.value >= @gc_limit)
|
|
215
171
|
begin
|
|
216
|
-
# Reserve with
|
|
217
|
-
job = connection.beanstalk.tubes.reserve(timeout:
|
|
172
|
+
# Reserve with configured timeout
|
|
173
|
+
job = connection.beanstalk.tubes.reserve(timeout: timeout)
|
|
218
174
|
|
|
219
175
|
if job
|
|
220
176
|
logger.debug "[Postburner::Worker] Thread #{Thread.current.object_id} reserved job #{job.id}"
|
|
@@ -238,34 +194,22 @@ module Postburner
|
|
|
238
194
|
connection&.close rescue nil
|
|
239
195
|
end
|
|
240
196
|
|
|
241
|
-
# Gracefully shuts down all thread pools (single-process mode).
|
|
242
|
-
#
|
|
243
|
-
# @return [void]
|
|
244
|
-
#
|
|
245
|
-
def shutdown_pools
|
|
246
|
-
@pools.each do |queue_name, pool|
|
|
247
|
-
pool.shutdown
|
|
248
|
-
pool.wait_for_termination(30)
|
|
249
|
-
logger.info "[Postburner::Worker] Queue '#{queue_name}' shutdown complete"
|
|
250
|
-
end
|
|
251
|
-
end
|
|
252
|
-
|
|
253
197
|
# Starts worker in forked mode (forks: 1+).
|
|
254
198
|
#
|
|
255
|
-
# Forks multiple child processes
|
|
256
|
-
#
|
|
199
|
+
# Forks multiple child processes, each running a thread pool.
|
|
200
|
+
# Parent process monitors children and restarts them when they exit.
|
|
257
201
|
#
|
|
258
202
|
# @return [void]
|
|
259
203
|
#
|
|
260
204
|
def start_forked_mode
|
|
261
|
-
logger.info "[Postburner::Worker] Mode: Multi-process (forks
|
|
205
|
+
logger.info "[Postburner::Worker] Mode: Multi-process (#{worker_config[:forks]} forks)"
|
|
262
206
|
|
|
263
|
-
# Track children: { pid =>
|
|
207
|
+
# Track children: { pid => fork_num }
|
|
264
208
|
@children = {}
|
|
265
209
|
|
|
266
|
-
# Spawn configured number of forks
|
|
267
|
-
|
|
268
|
-
|
|
210
|
+
# Spawn configured number of forks
|
|
211
|
+
worker_config[:forks].times do |fork_num|
|
|
212
|
+
spawn_fork(fork_num)
|
|
269
213
|
end
|
|
270
214
|
|
|
271
215
|
# Parent process monitors children
|
|
@@ -274,18 +218,16 @@ module Postburner
|
|
|
274
218
|
pid, status = Process.wait2(-1, Process::WNOHANG)
|
|
275
219
|
|
|
276
220
|
if pid
|
|
277
|
-
|
|
221
|
+
fork_num = @children.delete(pid)
|
|
278
222
|
exit_code = status.exitstatus
|
|
279
|
-
queue_name = child_info[:queue]
|
|
280
|
-
fork_num = child_info[:fork_num]
|
|
281
223
|
|
|
282
224
|
if exit_code == 99
|
|
283
225
|
# GC restart - this is normal
|
|
284
|
-
logger.info "[Postburner::Worker]
|
|
285
|
-
|
|
226
|
+
logger.info "[Postburner::Worker] Fork #{fork_num} reached GC limit, restarting..."
|
|
227
|
+
spawn_fork(fork_num) unless shutdown?
|
|
286
228
|
else
|
|
287
|
-
logger.error "[Postburner::Worker]
|
|
288
|
-
|
|
229
|
+
logger.error "[Postburner::Worker] Fork #{fork_num} exited unexpectedly (code: #{exit_code})"
|
|
230
|
+
spawn_fork(fork_num) unless shutdown?
|
|
289
231
|
end
|
|
290
232
|
end
|
|
291
233
|
|
|
@@ -305,61 +247,36 @@ module Postburner
|
|
|
305
247
|
logger.info "[Postburner::Worker] Shutdown complete"
|
|
306
248
|
end
|
|
307
249
|
|
|
308
|
-
# Spawns
|
|
309
|
-
#
|
|
310
|
-
# @param queue_name [String] Name of the queue to process
|
|
311
|
-
#
|
|
312
|
-
# @return [void]
|
|
313
|
-
#
|
|
314
|
-
def spawn_queue_workers(queue_name)
|
|
315
|
-
queue_config = config.queue_config(queue_name)
|
|
316
|
-
fork_count = queue_config['forks'] || queue_config[:forks] || config.default_forks
|
|
317
|
-
thread_count = queue_config['threads'] || queue_config[:threads] || config.default_threads
|
|
318
|
-
|
|
319
|
-
# Skip if this queue has 0 forks (shouldn't happen in forked mode, but be defensive)
|
|
320
|
-
return if fork_count == 0
|
|
321
|
-
|
|
322
|
-
total_concurrency = fork_count * thread_count
|
|
323
|
-
logger.info "[Postburner::Worker] Queue '#{queue_name}': #{fork_count} forks × #{thread_count} threads = #{total_concurrency} total concurrency"
|
|
324
|
-
|
|
325
|
-
fork_count.times do |fork_num|
|
|
326
|
-
spawn_queue_worker(queue_name, fork_num)
|
|
327
|
-
end
|
|
328
|
-
end
|
|
329
|
-
|
|
330
|
-
# Spawns a single forked worker process for a specific queue.
|
|
250
|
+
# Spawns a single forked worker process.
|
|
331
251
|
#
|
|
332
|
-
# @param queue_name [String] Name of the queue to process
|
|
333
252
|
# @param fork_num [Integer] Fork number (0-indexed)
|
|
334
253
|
#
|
|
335
254
|
# @return [void]
|
|
336
255
|
#
|
|
337
|
-
def
|
|
256
|
+
def spawn_fork(fork_num)
|
|
338
257
|
pid = fork do
|
|
339
258
|
# Child process
|
|
340
|
-
|
|
259
|
+
run_fork(fork_num)
|
|
341
260
|
end
|
|
342
261
|
|
|
343
|
-
@children[pid] =
|
|
344
|
-
logger.info "[Postburner::Worker] Spawned
|
|
262
|
+
@children[pid] = fork_num
|
|
263
|
+
logger.info "[Postburner::Worker] Spawned fork #{fork_num} (pid: #{pid})"
|
|
345
264
|
end
|
|
346
265
|
|
|
347
|
-
# Runs the thread pool worker
|
|
266
|
+
# Runs the thread pool worker in a forked process.
|
|
348
267
|
#
|
|
349
268
|
# This runs in the child process. Creates a thread pool and processes
|
|
350
269
|
# jobs until GC limit is reached or shutdown is requested.
|
|
351
270
|
#
|
|
352
|
-
# @param queue_name [String] Name of the queue to process
|
|
353
271
|
# @param fork_num [Integer] Fork number (for logging)
|
|
354
272
|
#
|
|
355
273
|
# @return [void]
|
|
356
274
|
#
|
|
357
|
-
def
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
gc_limit = queue_config['gc_limit'] || queue_config[:gc_limit] || config.default_gc_limit
|
|
275
|
+
def run_fork(fork_num)
|
|
276
|
+
thread_count = worker_config[:threads]
|
|
277
|
+
gc_limit = worker_config[:gc_limit]
|
|
361
278
|
|
|
362
|
-
logger.info "[Postburner::Worker]
|
|
279
|
+
logger.info "[Postburner::Worker] Fork #{fork_num}: #{thread_count} threads, GC limit #{gc_limit || 'unlimited'}"
|
|
363
280
|
|
|
364
281
|
# Track jobs processed in this fork
|
|
365
282
|
jobs_processed = Concurrent::AtomicFixnum.new(0)
|
|
@@ -370,7 +287,7 @@ module Postburner
|
|
|
370
287
|
# Each thread needs its own Beanstalkd connection
|
|
371
288
|
thread_count.times do
|
|
372
289
|
pool.post do
|
|
373
|
-
process_jobs_in_fork(
|
|
290
|
+
process_jobs_in_fork(fork_num, jobs_processed, gc_limit)
|
|
374
291
|
end
|
|
375
292
|
end
|
|
376
293
|
|
|
@@ -384,43 +301,43 @@ module Postburner
|
|
|
384
301
|
pool.wait_for_termination(30)
|
|
385
302
|
|
|
386
303
|
if gc_limit && jobs_processed.value >= gc_limit
|
|
387
|
-
logger.info "[Postburner::Worker]
|
|
304
|
+
logger.info "[Postburner::Worker] Fork #{fork_num} reached GC limit (#{jobs_processed.value} jobs), exiting for restart..."
|
|
388
305
|
exit 99 # Special exit code for GC restart
|
|
389
306
|
else
|
|
390
|
-
logger.info "[Postburner::Worker]
|
|
307
|
+
logger.info "[Postburner::Worker] Fork #{fork_num} shutting down gracefully..."
|
|
391
308
|
exit 0
|
|
392
309
|
end
|
|
393
310
|
rescue => e
|
|
394
|
-
logger.error "[Postburner::Worker]
|
|
311
|
+
logger.error "[Postburner::Worker] Fork #{fork_num} error: #{e.message}"
|
|
395
312
|
logger.error e.backtrace.join("\n")
|
|
396
313
|
exit 1
|
|
397
314
|
end
|
|
398
315
|
|
|
399
|
-
# Processes jobs in a single thread within a fork
|
|
316
|
+
# Processes jobs in a single thread within a fork.
|
|
400
317
|
#
|
|
401
318
|
# Each thread has its own Beanstalkd connection and reserves jobs
|
|
402
|
-
# from
|
|
319
|
+
# from all configured queues.
|
|
403
320
|
#
|
|
404
|
-
# @param queue_name [String] Name of the queue to process
|
|
405
321
|
# @param fork_num [Integer] Fork number (for logging)
|
|
406
322
|
# @param jobs_processed [Concurrent::AtomicFixnum] Shared counter of jobs processed
|
|
407
323
|
# @param gc_limit [Integer, nil] Maximum jobs before triggering GC restart (nil = unlimited)
|
|
408
324
|
#
|
|
409
325
|
# @return [void]
|
|
410
326
|
#
|
|
411
|
-
def process_jobs_in_fork(
|
|
327
|
+
def process_jobs_in_fork(fork_num, jobs_processed, gc_limit)
|
|
412
328
|
connection = Postburner::Connection.new
|
|
329
|
+
timeout = worker_config[:timeout]
|
|
413
330
|
|
|
414
|
-
# Watch
|
|
415
|
-
watch_queues(connection,
|
|
331
|
+
# Watch all configured queues
|
|
332
|
+
watch_queues(connection, config.queue_names)
|
|
416
333
|
|
|
417
334
|
until shutdown? || (gc_limit && jobs_processed.value >= gc_limit)
|
|
418
335
|
begin
|
|
419
|
-
# Reserve with
|
|
420
|
-
job = connection.beanstalk.tubes.reserve(timeout:
|
|
336
|
+
# Reserve with configured timeout
|
|
337
|
+
job = connection.beanstalk.tubes.reserve(timeout: timeout)
|
|
421
338
|
|
|
422
339
|
if job
|
|
423
|
-
logger.debug "[Postburner::Worker]
|
|
340
|
+
logger.debug "[Postburner::Worker] Fork #{fork_num} thread #{Thread.current.object_id} reserved job #{job.id}"
|
|
424
341
|
execute_job(job)
|
|
425
342
|
jobs_processed.increment
|
|
426
343
|
end
|
data/lib/postburner.rb
CHANGED
|
@@ -448,6 +448,25 @@ module Postburner
|
|
|
448
448
|
@__watched_tubes ||= watched_tube_names.map { |tube_name| connection.tubes[tube_name] }
|
|
449
449
|
end
|
|
450
450
|
|
|
451
|
+
# Returns the Beanstalkd tube name prefix for the given environment.
|
|
452
|
+
#
|
|
453
|
+
# Delegates to {Configuration#tube_prefix}. Postburner automatically
|
|
454
|
+
# prefixes all queue names with this value.
|
|
455
|
+
#
|
|
456
|
+
# @param env [String, Symbol, nil] Environment name (defaults to Rails.env or nil)
|
|
457
|
+
#
|
|
458
|
+
# @return [String] Tube prefix (e.g., "postburner.production")
|
|
459
|
+
#
|
|
460
|
+
# @example
|
|
461
|
+
# Postburner.tube_prefix('production') # => "postburner.production"
|
|
462
|
+
# Postburner.tube_prefix # => "postburner.test" (in test env)
|
|
463
|
+
#
|
|
464
|
+
# @see Configuration#tube_prefix
|
|
465
|
+
#
|
|
466
|
+
def self.tube_prefix(env = nil)
|
|
467
|
+
configuration.tube_prefix(env)
|
|
468
|
+
end
|
|
469
|
+
|
|
451
470
|
# Returns detailed statistics about Beanstalkd tubes.
|
|
452
471
|
#
|
|
453
472
|
# Collects job counts (ready, delayed, buried, reserved) for each tube
|