pgbus 0.0.1 → 0.1.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/README.md +37 -3
- data/Rakefile +98 -1
- data/app/controllers/pgbus/application_controller.rb +8 -0
- data/app/controllers/pgbus/recurring_tasks_controller.rb +36 -0
- data/app/helpers/pgbus/application_helper.rb +41 -0
- data/app/models/pgbus/application_record.rb +7 -0
- data/app/models/pgbus/batch_entry.rb +31 -0
- data/app/models/pgbus/blocked_execution.rb +40 -0
- data/app/models/pgbus/process_entry.rb +9 -0
- data/app/models/pgbus/processed_event.rb +9 -0
- data/app/models/pgbus/recurring_execution.rb +33 -0
- data/app/models/pgbus/recurring_task.rb +42 -0
- data/app/models/pgbus/semaphore.rb +29 -0
- data/app/views/layouts/pgbus/application.html.erb +1 -0
- data/app/views/pgbus/dashboard/_stats_cards.html.erb +9 -1
- data/app/views/pgbus/dead_letter/_messages_table.html.erb +55 -18
- data/app/views/pgbus/jobs/_enqueued_table.html.erb +46 -8
- data/app/views/pgbus/recurring_tasks/_tasks_table.html.erb +79 -0
- data/app/views/pgbus/recurring_tasks/index.html.erb +6 -0
- data/app/views/pgbus/recurring_tasks/show.html.erb +122 -0
- data/config/routes.rb +7 -0
- data/lib/active_job/queue_adapters/pgbus_adapter.rb +29 -0
- data/lib/generators/pgbus/add_recurring_generator.rb +56 -0
- data/lib/generators/pgbus/install_generator.rb +76 -2
- data/lib/generators/pgbus/templates/add_recurring_tables.rb.erb +31 -0
- data/lib/generators/pgbus/templates/migration.rb.erb +72 -4
- data/lib/generators/pgbus/templates/recurring.yml.erb +40 -0
- data/lib/generators/pgbus/templates/upgrade_pgmq.rb.erb +30 -0
- data/lib/generators/pgbus/upgrade_pgmq_generator.rb +60 -0
- data/lib/pgbus/active_job/adapter.rb +3 -6
- data/lib/pgbus/active_job/executor.rb +26 -12
- data/lib/pgbus/batch.rb +65 -72
- data/lib/pgbus/cli.rb +11 -16
- data/lib/pgbus/client.rb +32 -15
- data/lib/pgbus/concurrency/blocked_execution.rb +32 -37
- data/lib/pgbus/concurrency/semaphore.rb +11 -39
- data/lib/pgbus/concurrency.rb +10 -2
- data/lib/pgbus/configuration.rb +48 -0
- data/lib/pgbus/engine.rb +19 -1
- data/lib/pgbus/event_bus/handler.rb +10 -23
- data/lib/pgbus/instrumentation.rb +29 -0
- data/lib/pgbus/pgmq_schema/pgmq_v1.11.0.sql +2123 -0
- data/lib/pgbus/pgmq_schema.rb +159 -0
- data/lib/pgbus/process/consumer.rb +17 -9
- data/lib/pgbus/process/dispatcher.rb +33 -41
- data/lib/pgbus/process/heartbeat.rb +15 -23
- data/lib/pgbus/process/signal_handler.rb +23 -1
- data/lib/pgbus/process/supervisor.rb +79 -2
- data/lib/pgbus/process/worker.rb +42 -13
- data/lib/pgbus/recurring/already_recorded.rb +7 -0
- data/lib/pgbus/recurring/command_job.rb +28 -0
- data/lib/pgbus/recurring/config_loader.rb +35 -0
- data/lib/pgbus/recurring/schedule.rb +102 -0
- data/lib/pgbus/recurring/scheduler.rb +102 -0
- data/lib/pgbus/recurring/task.rb +111 -0
- data/lib/pgbus/serializer.rb +16 -6
- data/lib/pgbus/version.rb +1 -1
- data/lib/pgbus/web/data_source.rb +217 -36
- data/lib/pgbus.rb +8 -0
- data/lib/tasks/pgbus_pgmq.rake +62 -0
- metadata +51 -24
- data/.bun-version +0 -1
- data/.claude/commands/architect.md +0 -100
- data/.claude/commands/github-review-comments.md +0 -237
- data/.claude/commands/lfg.md +0 -271
- data/.claude/commands/review-pr.md +0 -69
- data/.claude/commands/security.md +0 -122
- data/.claude/commands/tdd.md +0 -148
- data/.claude/rules/agents.md +0 -49
- data/.claude/rules/coding-style.md +0 -91
- data/.claude/rules/git-workflow.md +0 -56
- data/.claude/rules/performance.md +0 -73
- data/.claude/rules/testing.md +0 -67
- data/CLAUDE.md +0 -80
- data/CODE_OF_CONDUCT.md +0 -10
- data/bun.lock +0 -18
- data/docs/README.md +0 -28
- data/docs/switch_from_good_job.md +0 -279
- data/docs/switch_from_sidekiq.md +0 -226
- data/docs/switch_from_solid_queue.md +0 -247
- data/package.json +0 -9
- data/sig/pgbus.rbs +0 -4
|
@@ -1,247 +0,0 @@
|
|
|
1
|
-
# Switch from SolidQueue to Pgbus
|
|
2
|
-
|
|
3
|
-
## Overview
|
|
4
|
-
|
|
5
|
-
SolidQueue and Pgbus are both PostgreSQL-backed job processors with similar architectures: supervisor/worker process model, `FOR UPDATE SKIP LOCKED` for contention-free polling, and forked processes. The migration is straightforward since both are ActiveJob adapters.
|
|
6
|
-
|
|
7
|
-
**Key differences:** Pgbus adds LISTEN/NOTIFY for instant wake-up (SolidQueue only polls), dead letter queues, worker recycling, and an event bus. Pgbus uses PGMQ under the hood instead of custom tables.
|
|
8
|
-
|
|
9
|
-
**Effort estimate:** Low. Both are pure ActiveJob adapters, so your jobs work unchanged.
|
|
10
|
-
|
|
11
|
-
## Step 1: Update dependencies
|
|
12
|
-
|
|
13
|
-
```ruby
|
|
14
|
-
# Gemfile
|
|
15
|
-
|
|
16
|
-
# Remove
|
|
17
|
-
gem "solid_queue"
|
|
18
|
-
gem "mission_control-jobs" # if used
|
|
19
|
-
|
|
20
|
-
# Add
|
|
21
|
-
gem "pgbus"
|
|
22
|
-
```
|
|
23
|
-
|
|
24
|
-
```bash
|
|
25
|
-
bundle install
|
|
26
|
-
rails generate pgbus:install
|
|
27
|
-
rails db:migrate
|
|
28
|
-
```
|
|
29
|
-
|
|
30
|
-
## Step 2: Switch the adapter
|
|
31
|
-
|
|
32
|
-
```ruby
|
|
33
|
-
# config/application.rb
|
|
34
|
-
|
|
35
|
-
# Before
|
|
36
|
-
config.active_job.queue_adapter = :solid_queue
|
|
37
|
-
|
|
38
|
-
# After
|
|
39
|
-
config.active_job.queue_adapter = :pgbus
|
|
40
|
-
```
|
|
41
|
-
|
|
42
|
-
If you set the adapter per-environment or use `config.solid_queue.connects_to` for a separate queue database, update those too.
|
|
43
|
-
|
|
44
|
-
## Step 3: Convert worker configuration
|
|
45
|
-
|
|
46
|
-
```yaml
|
|
47
|
-
# Before: config/queue.yml (SolidQueue)
|
|
48
|
-
production:
|
|
49
|
-
dispatchers:
|
|
50
|
-
- polling_interval: 1
|
|
51
|
-
batch_size: 500
|
|
52
|
-
workers:
|
|
53
|
-
- queues: "critical"
|
|
54
|
-
threads: 5
|
|
55
|
-
processes: 2
|
|
56
|
-
polling_interval: 0.1
|
|
57
|
-
- queues: "default,low"
|
|
58
|
-
threads: 3
|
|
59
|
-
processes: 3
|
|
60
|
-
polling_interval: 1
|
|
61
|
-
```
|
|
62
|
-
|
|
63
|
-
```yaml
|
|
64
|
-
# After: config/pgbus.yml
|
|
65
|
-
production:
|
|
66
|
-
workers:
|
|
67
|
-
- queues: [critical]
|
|
68
|
-
threads: 5
|
|
69
|
-
- queues: [critical]
|
|
70
|
-
threads: 5
|
|
71
|
-
- queues: [default, low]
|
|
72
|
-
threads: 3
|
|
73
|
-
- queues: [default, low]
|
|
74
|
-
threads: 3
|
|
75
|
-
- queues: [default, low]
|
|
76
|
-
threads: 3
|
|
77
|
-
max_retries: 5
|
|
78
|
-
max_jobs_per_worker: 10000
|
|
79
|
-
max_memory_mb: 512
|
|
80
|
-
```
|
|
81
|
-
|
|
82
|
-
> **Note:** SolidQueue's `processes: N` forks N identical workers. In Pgbus, list the same worker config N times, or let the supervisor handle it via configuration (one entry per process).
|
|
83
|
-
|
|
84
|
-
### Configuration mapping
|
|
85
|
-
|
|
86
|
-
| SolidQueue | Pgbus | Notes |
|
|
87
|
-
|------------|-------|-------|
|
|
88
|
-
| `polling_interval` | `polling_interval` | Pgbus defaults to 0.1s; LISTEN/NOTIFY makes this a fallback only |
|
|
89
|
-
| `threads` | `threads` | Same concept |
|
|
90
|
-
| `processes` | Repeat worker entry | One entry per forked process |
|
|
91
|
-
| `dispatchers[].batch_size` | N/A | Pgbus dispatcher does maintenance, not dispatch |
|
|
92
|
-
| `queues: "a,b"` (string) | `queues: [a, b]` (array) | Different format |
|
|
93
|
-
| `queues: "*"` (wildcard) | List queues explicitly | PGMQ queues are explicit |
|
|
94
|
-
|
|
95
|
-
## Step 4: Remove concurrency controls
|
|
96
|
-
|
|
97
|
-
SolidQueue's `limits_concurrency` is a SolidQueue-specific mixin. Remove it from your jobs:
|
|
98
|
-
|
|
99
|
-
```ruby
|
|
100
|
-
# Before: SolidQueue concurrency control
|
|
101
|
-
class ProcessOrderJob < ApplicationJob
|
|
102
|
-
limits_concurrency to: 1,
|
|
103
|
-
key: ->(order) { order.account_id },
|
|
104
|
-
duration: 15.minutes,
|
|
105
|
-
on_conflict: :block
|
|
106
|
-
|
|
107
|
-
def perform(order)
|
|
108
|
-
# ...
|
|
109
|
-
end
|
|
110
|
-
end
|
|
111
|
-
```
|
|
112
|
-
|
|
113
|
-
```ruby
|
|
114
|
-
# After: Remove the SolidQueue mixin
|
|
115
|
-
class ProcessOrderJob < ApplicationJob
|
|
116
|
-
def perform(order)
|
|
117
|
-
# ...
|
|
118
|
-
end
|
|
119
|
-
end
|
|
120
|
-
```
|
|
121
|
-
|
|
122
|
-
> Pgbus supports concurrency controls via `Pgbus::Concurrency`:
|
|
123
|
-
> ```ruby
|
|
124
|
-
> class ProcessOrderJob < ApplicationJob
|
|
125
|
-
> include Pgbus::Concurrency
|
|
126
|
-
> limits_concurrency to: 1,
|
|
127
|
-
> key: ->(order) { order.account_id },
|
|
128
|
-
> duration: 15.minutes,
|
|
129
|
-
> on_conflict: :block
|
|
130
|
-
> def perform(order)
|
|
131
|
-
> # ...
|
|
132
|
-
> end
|
|
133
|
-
> end
|
|
134
|
-
> ```
|
|
135
|
-
|
|
136
|
-
## Step 5: Migrate recurring tasks
|
|
137
|
-
|
|
138
|
-
If you use SolidQueue's `config/recurring.yml`:
|
|
139
|
-
|
|
140
|
-
```yaml
|
|
141
|
-
# Before: config/recurring.yml (SolidQueue)
|
|
142
|
-
production:
|
|
143
|
-
daily_cleanup:
|
|
144
|
-
class: CleanupJob
|
|
145
|
-
schedule: "every day at 2am"
|
|
146
|
-
queue: maintenance
|
|
147
|
-
hourly_sync:
|
|
148
|
-
class: SyncJob
|
|
149
|
-
schedule: "0 * * * *"
|
|
150
|
-
args: [42, "sync"]
|
|
151
|
-
```
|
|
152
|
-
|
|
153
|
-
Pgbus does not yet have built-in recurring task support. Options:
|
|
154
|
-
|
|
155
|
-
1. **Use the `whenever` gem** for cron-based scheduling:
|
|
156
|
-
```ruby
|
|
157
|
-
# config/schedule.rb (whenever gem)
|
|
158
|
-
every 1.day, at: "2:00 am" do
|
|
159
|
-
runner "CleanupJob.perform_later"
|
|
160
|
-
end
|
|
161
|
-
every :hour do
|
|
162
|
-
runner "SyncJob.perform_later(42, 'sync')"
|
|
163
|
-
end
|
|
164
|
-
```
|
|
165
|
-
|
|
166
|
-
2. **Use system cron** directly:
|
|
167
|
-
```cron
|
|
168
|
-
0 2 * * * cd /app && bin/rails runner "CleanupJob.perform_later"
|
|
169
|
-
0 * * * * cd /app && bin/rails runner "SyncJob.perform_later(42, 'sync')"
|
|
170
|
-
```
|
|
171
|
-
|
|
172
|
-
3. Wait for Pgbus recurring task support (planned).
|
|
173
|
-
|
|
174
|
-
## Step 6: Replace the dashboard
|
|
175
|
-
|
|
176
|
-
```ruby
|
|
177
|
-
# Before: config/routes.rb
|
|
178
|
-
mount MissionControl::Jobs::Engine, at: "/jobs"
|
|
179
|
-
|
|
180
|
-
# After:
|
|
181
|
-
mount Pgbus::Engine => "/pgbus"
|
|
182
|
-
```
|
|
183
|
-
|
|
184
|
-
## Step 7: Update process management
|
|
185
|
-
|
|
186
|
-
```bash
|
|
187
|
-
# Before
|
|
188
|
-
bundle exec rake solid_queue:start
|
|
189
|
-
|
|
190
|
-
# After
|
|
191
|
-
bundle exec pgbus start
|
|
192
|
-
```
|
|
193
|
-
|
|
194
|
-
## Step 8: Clean up SolidQueue tables
|
|
195
|
-
|
|
196
|
-
After verifying Pgbus processes jobs correctly and SolidQueue's tables are drained:
|
|
197
|
-
|
|
198
|
-
```ruby
|
|
199
|
-
class RemoveSolidQueue < ActiveRecord::Migration[7.1]
|
|
200
|
-
def up
|
|
201
|
-
drop_table :solid_queue_blocked_executions, if_exists: true
|
|
202
|
-
drop_table :solid_queue_claimed_executions, if_exists: true
|
|
203
|
-
drop_table :solid_queue_failed_executions, if_exists: true
|
|
204
|
-
drop_table :solid_queue_pauses, if_exists: true
|
|
205
|
-
drop_table :solid_queue_processes, if_exists: true
|
|
206
|
-
drop_table :solid_queue_ready_executions, if_exists: true
|
|
207
|
-
drop_table :solid_queue_recurring_executions, if_exists: true
|
|
208
|
-
drop_table :solid_queue_recurring_tasks, if_exists: true
|
|
209
|
-
drop_table :solid_queue_scheduled_executions, if_exists: true
|
|
210
|
-
drop_table :solid_queue_semaphores, if_exists: true
|
|
211
|
-
drop_table :solid_queue_jobs, if_exists: true
|
|
212
|
-
end
|
|
213
|
-
end
|
|
214
|
-
```
|
|
215
|
-
|
|
216
|
-
## What you gain
|
|
217
|
-
|
|
218
|
-
- **LISTEN/NOTIFY** -- SolidQueue only polls (100-150ms latency baseline). Pgbus wakes workers instantly via PostgreSQL LISTEN/NOTIFY, with polling as fallback only.
|
|
219
|
-
- **Dead letter queues** -- SolidQueue marks jobs as failed but keeps them in the same table. Pgbus routes failures to dedicated `_dlq` queues after `max_retries` for clear separation.
|
|
220
|
-
- **Worker recycling** -- SolidQueue workers run indefinitely. Pgbus recycles workers by job count, memory, or lifetime to prevent memory bloat.
|
|
221
|
-
- **Event bus** -- AMQP-style pub/sub with topic routing, not available in SolidQueue.
|
|
222
|
-
- **PGMQ under the hood** -- battle-tested message queue extension with visibility timeouts and atomic operations.
|
|
223
|
-
|
|
224
|
-
## What you lose (for now)
|
|
225
|
-
|
|
226
|
-
| SolidQueue feature | Status in Pgbus |
|
|
227
|
-
|--------------------|-----------------|
|
|
228
|
-
| `limits_concurrency` | `Pgbus::Concurrency` with `limits_concurrency` DSL |
|
|
229
|
-
| `config/recurring.yml` | Planned |
|
|
230
|
-
| Queue pausing (`SolidQueue::Queue.pause`) | Planned |
|
|
231
|
-
| Separate queue database | Not planned (PGMQ lives in your primary DB) |
|
|
232
|
-
| Numeric job priorities | PGMQ reads in FIFO order per queue; use separate queues for priority |
|
|
233
|
-
|
|
234
|
-
## Gotchas
|
|
235
|
-
|
|
236
|
-
1. **PgBouncer**: If you run PgBouncer in transaction mode, LISTEN/NOTIFY won't work. Use session mode or direct connections for Pgbus worker processes. This also applies to PGMQ's `FOR UPDATE SKIP LOCKED`.
|
|
237
|
-
|
|
238
|
-
2. **Separate queue database**: SolidQueue supports `connects_to` for a dedicated queue DB. Pgbus requires PGMQ in the same database it connects to. If you need isolation, use a separate PostgreSQL database with PGMQ installed and configure `Pgbus.configuration.database_url`.
|
|
239
|
-
|
|
240
|
-
3. **Queue naming**: SolidQueue uses bare queue names (`default`). Pgbus prefixes all queues (`pgbus_default`). Your `queue_as :default` declarations work unchanged -- the prefix is applied automatically.
|
|
241
|
-
|
|
242
|
-
4. **`ActionMailer::MailDeliveryJob`**: This can bypass the application-level adapter setting in some Rails versions. If mailer jobs don't appear in Pgbus, add to `ApplicationMailer`:
|
|
243
|
-
```ruby
|
|
244
|
-
class ApplicationMailer < ActionMailer::Base
|
|
245
|
-
self.deliver_later_queue_name = :mailers
|
|
246
|
-
end
|
|
247
|
-
```
|
data/package.json
DELETED
data/sig/pgbus.rbs
DELETED