solid_queue_guard 0.1.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.
Files changed (49) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +21 -0
  3. data/README.md +258 -0
  4. data/Rakefile +17 -0
  5. data/app/controllers/solid_queue_guard/application_controller.rb +6 -0
  6. data/app/controllers/solid_queue_guard/health_controller.rb +9 -0
  7. data/config/routes.rb +5 -0
  8. data/lib/generators/solid_queue_guard/install/USAGE +8 -0
  9. data/lib/generators/solid_queue_guard/install/install_generator.rb +17 -0
  10. data/lib/generators/solid_queue_guard/install/templates/solid_queue_guard.rb +17 -0
  11. data/lib/solid_queue_guard/check/result.rb +37 -0
  12. data/lib/solid_queue_guard/checks/base.rb +52 -0
  13. data/lib/solid_queue_guard/checks/config/adapter_check.rb +23 -0
  14. data/lib/solid_queue_guard/checks/config/connects_to_check.rb +38 -0
  15. data/lib/solid_queue_guard/checks/config/env_flags_check.rb +21 -0
  16. data/lib/solid_queue_guard/checks/config/process_heartbeat_config_check.rb +30 -0
  17. data/lib/solid_queue_guard/checks/config/puma_colocated_check.rb +33 -0
  18. data/lib/solid_queue_guard/checks/config/queue_database_check.rb +24 -0
  19. data/lib/solid_queue_guard/checks/config/queue_schema_check.rb +23 -0
  20. data/lib/solid_queue_guard/checks/config/scheduler_config_check.rb +32 -0
  21. data/lib/solid_queue_guard/checks/config/thread_pool_check.rb +38 -0
  22. data/lib/solid_queue_guard/checks/config/worker_coverage_check.rb +51 -0
  23. data/lib/solid_queue_guard/checks/registry.rb +48 -0
  24. data/lib/solid_queue_guard/checks/runtime/base.rb +21 -0
  25. data/lib/solid_queue_guard/checks/runtime/blocked_jobs_check.rb +9 -0
  26. data/lib/solid_queue_guard/checks/runtime/dispatcher_check.rb +9 -0
  27. data/lib/solid_queue_guard/checks/runtime/failed_jobs_check.rb +9 -0
  28. data/lib/solid_queue_guard/checks/runtime/finished_jobs_growth_check.rb +9 -0
  29. data/lib/solid_queue_guard/checks/runtime/orphaned_claims_check.rb +9 -0
  30. data/lib/solid_queue_guard/checks/runtime/paused_queue_lag_check.rb +9 -0
  31. data/lib/solid_queue_guard/checks/runtime/pidfile_check.rb +9 -0
  32. data/lib/solid_queue_guard/checks/runtime/process_topology_check.rb +9 -0
  33. data/lib/solid_queue_guard/checks/runtime/queue_lag_check.rb +9 -0
  34. data/lib/solid_queue_guard/checks/runtime/recurring_stale_check.rb +9 -0
  35. data/lib/solid_queue_guard/checks/runtime/scheduled_backlog_check.rb +9 -0
  36. data/lib/solid_queue_guard/checks/runtime/stale_process_check.rb +9 -0
  37. data/lib/solid_queue_guard/cli.rb +55 -0
  38. data/lib/solid_queue_guard/configuration.rb +33 -0
  39. data/lib/solid_queue_guard/engine.rb +21 -0
  40. data/lib/solid_queue_guard/formatters/json.rb +20 -0
  41. data/lib/solid_queue_guard/formatters/terminal.rb +43 -0
  42. data/lib/solid_queue_guard/notifiers/base.rb +17 -0
  43. data/lib/solid_queue_guard/queue_coverage.rb +37 -0
  44. data/lib/solid_queue_guard/report.rb +44 -0
  45. data/lib/solid_queue_guard/runner.rb +47 -0
  46. data/lib/solid_queue_guard/tasks.rb +39 -0
  47. data/lib/solid_queue_guard/version.rb +5 -0
  48. data/lib/solid_queue_guard.rb +38 -0
  49. metadata +346 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: bd60b98c25c507b3069f98b6b69282f627a398e96bd43d7a5d0713f0499c8610
4
+ data.tar.gz: c60a8995c311f4935456f58ca950e1d4cdb4b7e601dc1e6290f62f9d06931cb0
5
+ SHA512:
6
+ metadata.gz: ac5fbbb57df0cb133466076f0c4c1b698a13004b3f44e22bc64139e04e8c4bb51973a22e534ff0617329709a154a92a7a93ac9e083ea0087d86dadc73c6e89cf
7
+ data.tar.gz: b16bc3883213b26928b0cfa2c4d0b355ce43bd956a4c3df27e4cad4f8f71534748a15e5f9c892190a018741df8c9f1fbe4aaaa577e960f4e39a2a28c00a823ed
data/MIT-LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Rafael Pissardo
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,258 @@
1
+ # solid_queue_guard
2
+
3
+ **Production readiness checks and runtime guards for Rails Solid Queue.**
4
+
5
+ [![Gem Version](https://img.shields.io/gem/v/solid_queue_guard)](https://rubygems.org/gems/solid_queue_guard)
6
+ [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](MIT-LICENSE)
7
+
8
+ Rails 8 ships with [Solid Queue](https://github.com/rails/solid_queue). Redis is optional. Production config is not.
9
+
10
+ Your web tier can be **green** while your jobs are **dead**. Your queue can look **empty** while scheduled work is **stuck**. Your `queue.yml` can declare **10 threads** against a database pool of **5**.
11
+
12
+ **solid_queue_guard** catches that *before* it becomes a 3am incident.
13
+
14
+ > **Mission Control** shows what is happening.
15
+ > **solid_queue_guard** warns what is dangerous.
16
+
17
+ ---
18
+
19
+ ## Why this exists
20
+
21
+ Solid Queue is excellent. Operating it blindly is not.
22
+
23
+ | Symptom | What actually happened |
24
+ | ------- | ---------------------- |
25
+ | "Site is up, emails stopped" | Workers dead, heartbeats stale |
26
+ | "Only 3 jobs in the queue, why the panic?" | Oldest job waiting 40 minutes — **lag**, not depth |
27
+ | "Recurring billing just… stopped" | Scheduler not running, nobody noticed for a week |
28
+ | "Jobs hang after deploy" | Thread count > DB pool — connection starvation |
29
+ | "Health check passes, jobs don't" | `/up` doesn't know Solid Queue exists |
30
+
31
+ You don't need another dashboard. You need a **doctor**.
32
+
33
+ ---
34
+
35
+ ## See it in action
36
+
37
+ ```bash
38
+ bundle add solid_queue_guard
39
+ bin/rails solid_queue_guard:install
40
+ bin/rails solid_queue_guard:doctor
41
+ ```
42
+
43
+ ```text
44
+ SolidQueueGuard Report
45
+
46
+ Status: DEGRADED
47
+
48
+ Checks:
49
+ ✅ Active Job adapter is :solid_queue
50
+ ✅ Queue database configured in database.yml
51
+ ✅ Solid Queue connects_to queue database (pool: 10)
52
+ ✅ db/queue_schema.rb exists
53
+ ❌ Worker threads: 10, queue DB pool: 5
54
+ ⚠️ No workers configured for "mailers" queue
55
+ ⚠️ recurring.yml exists but scheduler may not run
56
+ ✅ Solid Queue is not co-located with Puma
57
+
58
+ Suggested fixes:
59
+ - Increase queue DB pool to at least 12 or reduce worker threads
60
+ - Add a worker for the mailers queue
61
+ - Verify scheduler process is running in production
62
+ ```
63
+
64
+ One command. Actionable output. No Datadog required to get started.
65
+
66
+ ---
67
+
68
+ ## What it checks
69
+
70
+ ### v0.1 — Configuration doctor (available now)
71
+
72
+ Runs locally, in CI, or pre-deploy. **No extra infrastructure.**
73
+
74
+ | Check | Catches |
75
+ | ----- | ------- |
76
+ | **Adapter** | Active Job not set to `:solid_queue` |
77
+ | **Queue database** | Missing `queue` entry in `database.yml` |
78
+ | **connects_to** | Solid Queue pointing at the wrong DB / pool |
79
+ | **Queue schema** | Missing `db/queue_schema.rb` |
80
+ | **Thread pool** | `threads` > available queue DB connections |
81
+ | **Worker coverage** | Queues with no worker assigned |
82
+ | **Scheduler** | `recurring.yml` tasks without a scheduler |
83
+ | **Env flags** | `SOLID_QUEUE_SKIP_RECURRING=true` in production |
84
+ | **Heartbeats** | Default thresholds that may not fit your deploy |
85
+ | **Puma plugin** | Solid Queue co-located with web in production |
86
+
87
+ ### v0.2+ — Runtime guards (roadmap)
88
+
89
+ | Check | Catches |
90
+ | ----- | ------- |
91
+ | **Queue lag** | Oldest ready job waiting too long |
92
+ | **Stale processes** | Dead workers, dispatchers, schedulers |
93
+ | **Dispatcher health** | Scheduled jobs never becoming ready |
94
+ | **Blocked jobs** | Concurrency control silently holding jobs |
95
+ | **Recurring staleness** | Cron tasks that stopped firing |
96
+ | **HTTP `/health`** | Kamal, ECS, K8s, UptimeRobot integration |
97
+
98
+ ---
99
+
100
+ ## Quick start
101
+
102
+ ### Install
103
+
104
+ ```bash
105
+ bundle add solid_queue_guard
106
+ bin/rails solid_queue_guard:install
107
+ ```
108
+
109
+ ### Run the doctor
110
+
111
+ ```bash
112
+ # Human-readable report
113
+ bin/rails solid_queue_guard:doctor
114
+
115
+ # JSON for scripts / CI
116
+ bin/rails "solid_queue_guard:doctor[json]"
117
+ SOLID_QUEUE_GUARD_FORMAT=json bin/rails solid_queue_guard:doctor
118
+
119
+ # Fail CI on warnings too
120
+ SOLID_QUEUE_GUARD_STRICT=1 bin/rails solid_queue_guard:doctor
121
+
122
+ # Full report (config + runtime when available)
123
+ bin/rails solid_queue_guard:report
124
+ ```
125
+
126
+ ### Exit codes
127
+
128
+ | Code | Meaning |
129
+ | ---- | ------- |
130
+ | `0` | Healthy or degraded |
131
+ | `1` | Unhealthy (or degraded in `--strict` / `SOLID_QUEUE_GUARD_STRICT=1`) |
132
+
133
+ Perfect for deploy pipelines:
134
+
135
+ ```yaml
136
+ # GitHub Actions
137
+ - name: Solid Queue production readiness
138
+ run: SOLID_QUEUE_GUARD_STRICT=1 bin/rails solid_queue_guard:doctor
139
+ ```
140
+
141
+ ### HTTP health (v0.2)
142
+
143
+ ```ruby
144
+ # config/routes.rb
145
+ mount SolidQueueGuard::Engine, at: "/solid_queue_guard"
146
+ ```
147
+
148
+ ```bash
149
+ curl localhost:3000/solid_queue_guard/health
150
+ # => { "status": "degraded", "queue_lag_seconds": 245, "warnings": [...] }
151
+ ```
152
+
153
+ Works with **Kamal**, **Heroku**, **Fly.io**, **ECS/Fargate**, **Kubernetes**, **Better Stack**, **UptimeRobot**.
154
+
155
+ ---
156
+
157
+ ## Configuration
158
+
159
+ ```ruby
160
+ # config/initializers/solid_queue_guard.rb
161
+ SolidQueueGuard.configure do |config|
162
+ config.enabled = Rails.env.production?
163
+
164
+ config.queue_lag_thresholds = {
165
+ critical: 30.seconds,
166
+ default: 5.minutes,
167
+ mailers: 15.minutes
168
+ }
169
+
170
+ config.failed_jobs_threshold = 20
171
+ config.stale_process_threshold = 5.minutes
172
+
173
+ # config.health_token = ENV["SOLID_QUEUE_GUARD_TOKEN"] # v0.2
174
+ # config.notify_with = [:rails_logger, :slack] # v0.3
175
+ end
176
+ ```
177
+
178
+ ---
179
+
180
+ ## solid_queue_guard vs Mission Control
181
+
182
+ | | [Mission Control — Jobs](https://github.com/rails/mission_control-jobs) | solid_queue_guard |
183
+ | --- | --- | --- |
184
+ | **Purpose** | Inspect & manage jobs | Detect production risk |
185
+ | **UI** | Dashboard | CLI + JSON + health endpoint |
186
+ | **Retry / discard** | Yes | No (use Mission Control) |
187
+ | **Config doctor** | No | Yes |
188
+ | **Queue lag alerts** | No | Yes (v0.2) |
189
+ | **Pre-deploy checks** | No | Yes |
190
+ | **Recurring job guard** | Manual inspection | Automatic (v0.2) |
191
+
192
+ **Use both.** They solve different problems.
193
+
194
+ ---
195
+
196
+ ## Roadmap
197
+
198
+ | Version | Ships |
199
+ | ------- | ----- |
200
+ | **v0.1** | `doctor` — config checks, CI integration, install generator |
201
+ | **v0.2** | Runtime health, queue lag, dispatcher/blocked jobs, HTTP endpoint |
202
+ | **v0.3** | Slack, Datadog, webhook notifications |
203
+ | **v0.4** | StatsD, Prometheus, OpenTelemetry metrics |
204
+ | **v0.5** | Auto-recommendations for `queue.yml` topology |
205
+
206
+ ---
207
+
208
+ ## Compatibility
209
+
210
+ | Gem version | Ruby | Rails |
211
+ | ----------- | ---- | ----- |
212
+ | 0.1.x | 3.1+ | 7.1, 7.2, 8.0 |
213
+
214
+ ## Requirements
215
+
216
+ - Ruby >= 3.1
217
+ - Rails >= 7.1, < 9.0
218
+ - [solid_queue](https://github.com/rails/solid_queue) >= 1.0, < 2.0
219
+
220
+ ---
221
+
222
+ ## Development
223
+
224
+ ```bash
225
+ git clone https://github.com/rafael-pissardo/solid_queue_guard.git
226
+ cd solid_queue_guard
227
+ bundle install
228
+ cd test/dummy && bin/setup
229
+ cd ../.. && bundle exec rake test
230
+ bundle exec rubocop
231
+ bundle exec appraisal install
232
+ bundle exec appraisal rake test
233
+ ```
234
+
235
+ ---
236
+
237
+ ## Contributing
238
+
239
+ Issues and PRs welcome. Keep it focused: **production safety**, not another job dashboard.
240
+
241
+ 1. Fork it
242
+ 2. Create your branch (`git checkout -b my-new-check`)
243
+ 3. Write a test first
244
+ 4. Make the check pass
245
+ 5. Open a PR
246
+
247
+ ---
248
+
249
+ ## License
250
+
251
+ MIT — see [MIT-LICENSE](MIT-LICENSE).
252
+
253
+ ---
254
+
255
+ <p align="center">
256
+ <strong>Run the doctor before you run the deploy.</strong><br>
257
+ <sub>Built for Rails teams who chose Solid Queue and still sleep at night.</sub>
258
+ </p>
data/Rakefile ADDED
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/setup'
4
+
5
+ APP_RAKEFILE = File.expand_path('test/dummy/Rakefile', __dir__)
6
+ load 'rails/tasks/engine.rake'
7
+
8
+ require 'bundler/gem_tasks'
9
+
10
+ require 'rake/testtask'
11
+
12
+ Rake::TestTask.new(:test) do |task|
13
+ task.libs << 'test'
14
+ task.pattern = 'test/**/*_test.rb'
15
+ end
16
+
17
+ task default: :test
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SolidQueueGuard
4
+ class ApplicationController < ActionController::Base
5
+ end
6
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SolidQueueGuard
4
+ class HealthController < ApplicationController
5
+ def show
6
+ render json: { status: 'not_implemented', message: 'HTTP health checks ship in v0.2' }, status: :not_implemented
7
+ end
8
+ end
9
+ end
data/config/routes.rb ADDED
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ SolidQueueGuard::Engine.routes.draw do
4
+ get 'health', to: 'health#show'
5
+ end
@@ -0,0 +1,8 @@
1
+ Description:
2
+ Installs Solid Queue Guard initializer with thresholds and feature flags.
3
+
4
+ Usage:
5
+ bin/rails generate solid_queue_guard:install
6
+
7
+ This will create:
8
+ config/initializers/solid_queue_guard.rb
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rails/generators/base'
4
+
5
+ module SolidQueueGuard
6
+ module Generators
7
+ class InstallGenerator < Rails::Generators::Base
8
+ source_root File.expand_path('templates', __dir__)
9
+
10
+ desc 'Creates Solid Queue Guard initializer'
11
+
12
+ def copy_initializer
13
+ template 'solid_queue_guard.rb', 'config/initializers/solid_queue_guard.rb'
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ SolidQueueGuard.configure do |config|
4
+ config.enabled = Rails.env.production?
5
+
6
+ config.queue_lag_thresholds = {
7
+ critical: 30.seconds,
8
+ default: 5.minutes,
9
+ mailers: 15.minutes
10
+ }
11
+
12
+ config.failed_jobs_threshold = 20
13
+ config.stale_process_threshold = 5.minutes
14
+
15
+ # config.health_token = ENV["SOLID_QUEUE_GUARD_TOKEN"]
16
+ # config.notify_with = [ :rails_logger ]
17
+ end
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SolidQueueGuard
4
+ module Check
5
+ Result = Data.define(:id, :status, :message, :suggestion, :metadata) do
6
+ def initialize(id:, status:, message:, suggestion: nil, metadata: {})
7
+ super
8
+ end
9
+
10
+ def pass?
11
+ status == :pass
12
+ end
13
+
14
+ def warn?
15
+ status == :warn
16
+ end
17
+
18
+ def fail?
19
+ status == :fail
20
+ end
21
+
22
+ def skip?
23
+ status == :skip
24
+ end
25
+
26
+ def to_h
27
+ {
28
+ id: id,
29
+ status: status.to_s,
30
+ message: message,
31
+ suggestion: suggestion,
32
+ metadata: metadata
33
+ }.compact
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,52 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SolidQueueGuard
4
+ module Checks
5
+ # @api private
6
+ class Base
7
+ def self.call(**options)
8
+ new(**options).call
9
+ end
10
+
11
+ def initialize(**options)
12
+ @options = options
13
+ end
14
+
15
+ def call
16
+ raise NotImplementedError
17
+ end
18
+
19
+ private
20
+
21
+ attr_reader :options
22
+
23
+ def pass(id, message, **kwargs)
24
+ build_result(id, :pass, message, **kwargs)
25
+ end
26
+
27
+ def warn(id, message, **kwargs)
28
+ build_result(id, :warn, message, **kwargs)
29
+ end
30
+
31
+ def failure(id, message, **kwargs)
32
+ build_result(id, :fail, message, **kwargs)
33
+ end
34
+
35
+ def skip(id, message, **kwargs)
36
+ build_result(id, :skip, message, **kwargs)
37
+ end
38
+
39
+ def build_result(id, status, message, suggestion: nil, metadata: {})
40
+ Check::Result.new(id: id, status: status, message: message, suggestion: suggestion, metadata: metadata)
41
+ end
42
+
43
+ def rails_root
44
+ Rails.root
45
+ end
46
+
47
+ def solid_queue_configuration
48
+ @solid_queue_configuration ||= SolidQueue::Configuration.new
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SolidQueueGuard
4
+ module Checks
5
+ module Config
6
+ class AdapterCheck < Base
7
+ def call
8
+ adapter = Rails.application.config.active_job.queue_adapter
9
+
10
+ if adapter.to_sym == :solid_queue
11
+ pass('adapter', 'Active Job adapter is :solid_queue')
12
+ else
13
+ failure(
14
+ 'adapter',
15
+ "Active Job adapter is #{adapter.inspect}, expected :solid_queue",
16
+ suggestion: 'Set config.active_job.queue_adapter = :solid_queue'
17
+ )
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SolidQueueGuard
4
+ module Checks
5
+ module Config
6
+ class ConnectsToCheck < Base
7
+ def call
8
+ connects_to = Rails.application.config.solid_queue.connects_to
9
+
10
+ if connects_to.blank?
11
+ return failure(
12
+ 'connects_to',
13
+ 'config.solid_queue.connects_to is not configured',
14
+ suggestion: 'Set config.solid_queue.connects_to = { database: { writing: :queue } }'
15
+ )
16
+ end
17
+
18
+ writing = connects_to.dig(:database, :writing) || connects_to.dig('database', 'writing')
19
+
20
+ if writing.to_s != 'queue'
21
+ failure(
22
+ 'connects_to',
23
+ "Solid Queue connects_to writing target is #{writing.inspect}, expected :queue",
24
+ suggestion: 'Point config.solid_queue.connects_to to the queue database'
25
+ )
26
+ elsif SolidQueue::Record.connection_pool.nil?
27
+ failure('connects_to', 'Solid Queue queue database connection pool is not available')
28
+ else
29
+ pass(
30
+ 'connects_to',
31
+ "Solid Queue connects_to queue database (pool: #{SolidQueue::Record.connection_pool.size})"
32
+ )
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SolidQueueGuard
4
+ module Checks
5
+ module Config
6
+ class EnvFlagsCheck < Base
7
+ def call
8
+ if Rails.env.production? && ActiveModel::Type::Boolean.new.cast(ENV.fetch('SOLID_QUEUE_SKIP_RECURRING', nil))
9
+ warn(
10
+ 'env_flags',
11
+ 'SOLID_QUEUE_SKIP_RECURRING=true in production',
12
+ suggestion: 'Remove SOLID_QUEUE_SKIP_RECURRING unless recurring jobs are intentionally disabled'
13
+ )
14
+ else
15
+ pass('env_flags', 'No dangerous Solid Queue environment flags detected')
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SolidQueueGuard
4
+ module Checks
5
+ module Config
6
+ class ProcessHeartbeatConfigCheck < Base
7
+ DEFAULT_HEARTBEAT_INTERVAL = 60.seconds
8
+ DEFAULT_ALIVE_THRESHOLD = 5.minutes
9
+
10
+ def call
11
+ heartbeat_interval = SolidQueue.process_heartbeat_interval
12
+ alive_threshold = SolidQueue.process_alive_threshold
13
+
14
+ if heartbeat_interval == DEFAULT_HEARTBEAT_INTERVAL && alive_threshold == DEFAULT_ALIVE_THRESHOLD
15
+ warn(
16
+ 'process_heartbeat_config',
17
+ 'Process heartbeat thresholds use defaults (interval: 60s, alive: 5m)',
18
+ suggestion: 'Consider customizing process_alive_threshold for your deployment latency requirements'
19
+ )
20
+ else
21
+ pass(
22
+ 'process_heartbeat_config',
23
+ "Process heartbeat interval: #{heartbeat_interval.inspect}, alive threshold: #{alive_threshold.inspect}"
24
+ )
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SolidQueueGuard
4
+ module Checks
5
+ module Config
6
+ class PumaColocatedCheck < Base
7
+ PUMA_PLUGIN_PATTERN = /plugin\s+:?solid_queue/
8
+
9
+ def call
10
+ puma_config = rails_root.join('config/puma.rb')
11
+
12
+ return pass('puma_colocated', 'No config/puma.rb found') unless puma_config.exist?
13
+
14
+ content = puma_config.read
15
+
16
+ if content.match?(PUMA_PLUGIN_PATTERN)
17
+ if Rails.env.production?
18
+ warn(
19
+ 'puma_colocated',
20
+ 'Solid Queue Puma plugin is enabled in production',
21
+ suggestion: 'Run Solid Queue in a dedicated job process for better isolation and memory management'
22
+ )
23
+ else
24
+ pass('puma_colocated', 'Solid Queue Puma plugin detected (non-production environment)')
25
+ end
26
+ else
27
+ pass('puma_colocated', 'Solid Queue is not co-located with Puma')
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SolidQueueGuard
4
+ module Checks
5
+ module Config
6
+ class QueueDatabaseCheck < Base
7
+ def call
8
+ config = Rails.application.config.database_configuration
9
+ env_config = config[Rails.env]
10
+
11
+ if env_config.is_a?(Hash) && env_config.key?('queue')
12
+ pass('queue_database', 'Queue database configured in database.yml')
13
+ else
14
+ failure(
15
+ 'queue_database',
16
+ "No queue database entry in database.yml for #{Rails.env}",
17
+ suggestion: 'Add a queue database configuration for Solid Queue'
18
+ )
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SolidQueueGuard
4
+ module Checks
5
+ module Config
6
+ class QueueSchemaCheck < Base
7
+ def call
8
+ schema_path = rails_root.join('db/queue_schema.rb')
9
+
10
+ if schema_path.exist?
11
+ pass('queue_schema', 'db/queue_schema.rb exists')
12
+ else
13
+ warn(
14
+ 'queue_schema',
15
+ 'db/queue_schema.rb not found',
16
+ suggestion: 'Run bin/rails solid_queue:install to generate the queue schema'
17
+ )
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end