Skip to content

Commit b5e2ce0

Browse files
committed
chore(specs): add solid queue to e2e specs
1 parent 2614348 commit b5e2ce0

7 files changed

Lines changed: 160 additions & 7 deletions

File tree

.devcontainer/.env.example

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ SENTRY_E2E_SVELTE_APP_PORT=4001
1212
SENTRY_E2E_RAILS_APP_URL="http://localhost:4000"
1313
SENTRY_E2E_SVELTE_APP_URL="http://localhost:4001"
1414

15-
# ActiveJob queue adapter under test: async | inline | sidekiq | resque | delayed_job
15+
# ActiveJob queue adapter under test: async | inline | sidekiq | resque | delayed_job | solid_queue
1616
SENTRY_E2E_ACTIVE_JOB_ADAPTER="async"
1717

1818
# Redis for the sidekiq/resque adapters (the Compose service is named "redis")

.github/workflows/e2e_tests.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ jobs:
3535
- sidekiq
3636
- resque
3737
- delayed_job
38+
- solid_queue
3839

3940
steps:
4041
- name: Checkout code

.mise.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ description = "Start the svelte-mini e2e app"
3333
run = "cd spec/apps/svelte-mini && npm run dev"
3434

3535
[tasks."e2e:worker"]
36-
description = "Start the rails-mini ActiveJob worker (sidekiq/resque/delayed_job; idles for async/inline)"
36+
description = "Start the rails-mini ActiveJob worker (sidekiq/resque/delayed_job/solid_queue; idles for async/inline)"
3737
run = "cd spec/apps/rails-mini && bundle exec ruby worker.rb"
3838

3939
[tasks."e2e:serve"]

spec/apps/rails-mini/Gemfile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,3 +16,4 @@ gem 'sentry-rails', path: Pathname(__dir__).join("../../..").realpath
1616
gem 'sidekiq'
1717
gem 'resque'
1818
gem 'delayed_job_active_record'
19+
gem 'solid_queue'

spec/apps/rails-mini/app.rb

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
Bundler.require
66

77
ENV["RAILS_ENV"] = "development"
8-
ENV["DATABASE_URL"] = "sqlite3:tmp/rails_mini_development.sqlite3"
8+
ENV["DATABASE_URL"] = "sqlite3:tmp/rails_mini_development.sqlite3?timeout=5000"
99

1010
require "action_controller/railtie"
1111
require "active_record/railtie"
@@ -39,7 +39,8 @@ class RailsMiniApp < Rails::Application
3939
"inline" => :inline,
4040
"sidekiq" => :sidekiq,
4141
"resque" => :resque,
42-
"delayed_job" => :delayed_job
42+
"delayed_job" => :delayed_job,
43+
"solid_queue" => :solid_queue
4344
}.freeze
4445

4546
adapter_name = ENV.fetch("SENTRY_E2E_ACTIVE_JOB_ADAPTER", "async").to_s.downcase
@@ -313,6 +314,13 @@ def set_cors_headers
313314
# avoiding a concurrent `force: true` drop/create race on the shared SQLite
314315
# file; it waits for these tables to appear before processing jobs.
315316
unless ENV["SENTRY_E2E_SKIP_DB_SETUP"] == "true"
317+
# Backing store for the :solid_queue adapter. Loaded first (before :posts)
318+
# unconditionally, for the same reason as :delayed_jobs below: the schema
319+
# stays adapter-agnostic, and since the worker waits for :posts as its
320+
# readiness signal, creating these tables first guarantees they exist by
321+
# the time the worker starts polling.
322+
load Pathname(__dir__).join("db/queue_schema.rb")
323+
316324
ActiveRecord::Schema.define do
317325
create_table :posts, force: true do |t|
318326
t.string :title, null: false
Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
# frozen_string_literal: true
2+
3+
# Backing store for the :solid_queue adapter. Loaded from app.rb's schema
4+
# setup so the same SQLite file works regardless of which adapter the
5+
# worker uses. Mirrors sentry-rails' dummy app queue schema.
6+
ActiveRecord::Schema[7.1].define(version: 1) do
7+
create_table "solid_queue_blocked_executions", force: :cascade do |t|
8+
t.bigint "job_id", null: false
9+
t.string "queue_name", null: false
10+
t.integer "priority", default: 0, null: false
11+
t.string "concurrency_key", null: false
12+
t.datetime "expires_at", null: false
13+
t.datetime "created_at", null: false
14+
t.index [ "concurrency_key", "priority", "job_id" ], name: "index_solid_queue_blocked_executions_for_release"
15+
t.index [ "expires_at", "concurrency_key" ], name: "index_solid_queue_blocked_executions_for_maintenance"
16+
t.index [ "job_id" ], name: "index_solid_queue_blocked_executions_on_job_id", unique: true
17+
end
18+
19+
create_table "solid_queue_claimed_executions", force: :cascade do |t|
20+
t.bigint "job_id", null: false
21+
t.bigint "process_id"
22+
t.datetime "created_at", null: false
23+
t.index [ "job_id" ], name: "index_solid_queue_claimed_executions_on_job_id", unique: true
24+
t.index [ "process_id", "job_id" ], name: "index_solid_queue_claimed_executions_on_process_id_and_job_id"
25+
end
26+
27+
create_table "solid_queue_failed_executions", force: :cascade do |t|
28+
t.bigint "job_id", null: false
29+
t.text "error"
30+
t.datetime "created_at", null: false
31+
t.index [ "job_id" ], name: "index_solid_queue_failed_executions_on_job_id", unique: true
32+
end
33+
34+
create_table "solid_queue_jobs", force: :cascade do |t|
35+
t.string "queue_name", null: false
36+
t.string "class_name", null: false
37+
t.text "arguments"
38+
t.integer "priority", default: 0, null: false
39+
t.string "active_job_id"
40+
t.datetime "scheduled_at"
41+
t.datetime "finished_at"
42+
t.string "concurrency_key"
43+
t.datetime "created_at", null: false
44+
t.datetime "updated_at", null: false
45+
t.index [ "active_job_id" ], name: "index_solid_queue_jobs_on_active_job_id"
46+
t.index [ "class_name" ], name: "index_solid_queue_jobs_on_class_name"
47+
t.index [ "finished_at" ], name: "index_solid_queue_jobs_on_finished_at"
48+
t.index [ "queue_name", "finished_at" ], name: "index_solid_queue_jobs_for_filtering"
49+
t.index [ "scheduled_at", "finished_at" ], name: "index_solid_queue_jobs_for_alerting"
50+
end
51+
52+
create_table "solid_queue_pauses", force: :cascade do |t|
53+
t.string "queue_name", null: false
54+
t.datetime "created_at", null: false
55+
t.index [ "queue_name" ], name: "index_solid_queue_pauses_on_queue_name", unique: true
56+
end
57+
58+
create_table "solid_queue_processes", force: :cascade do |t|
59+
t.string "kind", null: false
60+
t.datetime "last_heartbeat_at", null: false
61+
t.bigint "supervisor_id"
62+
t.integer "pid", null: false
63+
t.string "hostname"
64+
t.text "metadata"
65+
t.datetime "created_at", null: false
66+
t.string "name", null: false
67+
t.index [ "last_heartbeat_at" ], name: "index_solid_queue_processes_on_last_heartbeat_at"
68+
t.index [ "name", "supervisor_id" ], name: "index_solid_queue_processes_on_name_and_supervisor_id", unique: true
69+
t.index [ "supervisor_id" ], name: "index_solid_queue_processes_on_supervisor_id"
70+
end
71+
72+
create_table "solid_queue_ready_executions", force: :cascade do |t|
73+
t.bigint "job_id", null: false
74+
t.string "queue_name", null: false
75+
t.integer "priority", default: 0, null: false
76+
t.datetime "created_at", null: false
77+
t.index [ "job_id" ], name: "index_solid_queue_ready_executions_on_job_id", unique: true
78+
t.index [ "priority", "job_id" ], name: "index_solid_queue_poll_all"
79+
t.index [ "queue_name", "priority", "job_id" ], name: "index_solid_queue_poll_by_queue"
80+
end
81+
82+
create_table "solid_queue_recurring_executions", force: :cascade do |t|
83+
t.bigint "job_id", null: false
84+
t.string "task_key", null: false
85+
t.datetime "run_at", null: false
86+
t.datetime "created_at", null: false
87+
t.index [ "job_id" ], name: "index_solid_queue_recurring_executions_on_job_id", unique: true
88+
t.index [ "task_key", "run_at" ], name: "index_solid_queue_recurring_executions_on_task_key_and_run_at", unique: true
89+
end
90+
91+
create_table "solid_queue_recurring_tasks", force: :cascade do |t|
92+
t.string "key", null: false
93+
t.string "schedule", null: false
94+
t.string "command", limit: 2048
95+
t.string "class_name"
96+
t.text "arguments"
97+
t.string "queue_name"
98+
t.integer "priority", default: 0
99+
t.boolean "static", default: true, null: false
100+
t.text "description"
101+
t.datetime "created_at", null: false
102+
t.datetime "updated_at", null: false
103+
t.index [ "key" ], name: "index_solid_queue_recurring_tasks_on_key", unique: true
104+
t.index [ "static" ], name: "index_solid_queue_recurring_tasks_on_static"
105+
end
106+
107+
create_table "solid_queue_scheduled_executions", force: :cascade do |t|
108+
t.bigint "job_id", null: false
109+
t.string "queue_name", null: false
110+
t.integer "priority", default: 0, null: false
111+
t.datetime "scheduled_at", null: false
112+
t.datetime "created_at", null: false
113+
t.index [ "job_id" ], name: "index_solid_queue_scheduled_executions_on_job_id", unique: true
114+
t.index [ "scheduled_at", "priority", "job_id" ], name: "index_solid_queue_dispatch_all"
115+
end
116+
117+
create_table "solid_queue_semaphores", force: :cascade do |t|
118+
t.string "key", null: false
119+
t.integer "value", default: 1, null: false
120+
t.datetime "expires_at", null: false
121+
t.datetime "created_at", null: false
122+
t.datetime "updated_at", null: false
123+
t.index [ "expires_at" ], name: "index_solid_queue_semaphores_on_expires_at"
124+
t.index [ "key", "value" ], name: "index_solid_queue_semaphores_on_key_and_value"
125+
t.index [ "key" ], name: "index_solid_queue_semaphores_on_key", unique: true
126+
end
127+
128+
add_foreign_key "solid_queue_blocked_executions", "solid_queue_jobs", column: "job_id", on_delete: :cascade
129+
add_foreign_key "solid_queue_claimed_executions", "solid_queue_jobs", column: "job_id", on_delete: :cascade
130+
add_foreign_key "solid_queue_failed_executions", "solid_queue_jobs", column: "job_id", on_delete: :cascade
131+
add_foreign_key "solid_queue_ready_executions", "solid_queue_jobs", column: "job_id", on_delete: :cascade
132+
add_foreign_key "solid_queue_recurring_executions", "solid_queue_jobs", column: "job_id", on_delete: :cascade
133+
add_foreign_key "solid_queue_scheduled_executions", "solid_queue_jobs", column: "job_id", on_delete: :cascade
134+
end

spec/apps/rails-mini/worker.rb

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
# frozen_string_literal: true
22

33
# Background worker entrypoint for the worker-based ActiveJob adapters
4-
# (:sidekiq, :resque, :delayed_job). These adapters enqueue onto an
5-
# external broker (Redis / the DB) and rely on a separate process to
6-
# execute the job. The worker boots the same Rails + Sentry app as the
4+
# (:sidekiq, :resque, :delayed_job, :solid_queue). These adapters enqueue
5+
# onto an external broker (Redis / the DB) and rely on a separate process
6+
# to execute the job. The worker boots the same Rails + Sentry app as the
77
# web process, so the job's consumer transaction is emitted into the
88
# shared debug-transport log the e2e suite reads.
99
#
@@ -42,6 +42,15 @@
4242
worker.work(ENV.fetch("RESQUE_INTERVAL", "0.5").to_f)
4343
when "delayed_job"
4444
Delayed::Worker.new(sleep_delay: 0.5, quiet: false).start
45+
when "solid_queue"
46+
# Boot Solid Queue's supervisor, which forks a dispatcher (promotes
47+
# scheduled -> ready executions) and a worker (claims ready executions
48+
# and runs the jobs). No config/queue.yml exists, so it falls back to
49+
# the built-in single-worker + single-dispatcher defaults over the "*"
50+
# queues. The forked children inherit the Sentry SDK initialized when
51+
# this process booted the app above, so their consumer transactions land
52+
# in the shared debug-transport log.
53+
SolidQueue::Supervisor.start
4554
else
4655
# :async and :inline run jobs inside the web process. Stay alive as an
4756
# idle no-op so this stays a uniform, long-running service under process

0 commit comments

Comments
 (0)