Skip to content

Add support for Solid Queue#1623

Open
lairtonmendes wants to merge 1 commit into
elastic:mainfrom
lairtonmendes:feat/solid-queue-spy
Open

Add support for Solid Queue#1623
lairtonmendes wants to merge 1 commit into
elastic:mainfrom
lairtonmendes:feat/solid-queue-spy

Conversation

@lairtonmendes

@lairtonmendes lairtonmendes commented Jun 4, 2026

Copy link
Copy Markdown

What does this pull request do?

Adds support for Solid Queue, the
Active Record–backed queue adapter that became the default in Rails 8.
The new spy instruments SolidQueue::ClaimedExecution#perform and produces one APM transaction per job:

  • transaction.name = the job's class name (the wrapped ActiveJob)
  • transaction.type = SolidQueue
  • label :queue = the queue the job was claimed from
  • exceptions raised by the job are reported via ElasticAPM.report and mark the transaction outcome=failure

Implementation notes worth surfacing for review:

  • SolidQueue::ClaimedExecution lives under app/models and is autoloaded by the Rails engine via Zeitwerk, so the spies' Kernel.require hook never fires. The prepend is installed inside Rails.application.reloader.to_prepare, which both delays installation until the engine's autoload paths are in place and re-applies the patch after dev-mode reloads.
  • Fork mode (solid_queue's default supervisor) is already handled by Agent#detect_forking!, which runs on every start_transaction / start_span / report and rebuilds the agent's background threads in the forked child. No spy-side lifecycle hooks are needed.
  • Gemfile gates gem 'solid_queue' to Rails ≥ 7.1 so the older Rails matrix entries keep resolving.

Why is it important?

Solid Queue is the default Active Job adapter in Rails 8 and is the queue shipped by rails new for every new Rails app from 8.0 onward. Without this instrumentation, jobs executed by solid_queue produce no APM transactions, leaving an entire class of work invisible in Kibana.

Checklist

  • I have signed the Contributor License Agreement.
  • My code follows the style guidelines of this project (rubocop clean on the new files)
  • I have rebased my changes on top of the latest main branch
  • I have added tests that prove my fix is effective or that my feature works (spec/elastic_apm/spies/solid_queue_spec.rb, 6 examples covering success, failure, queue label, multi-perform, prepend, and graceful no-op when agent is not running)
  • New and existing unit tests pass locally (bundle exec rspec spec/elastic_apm/spies/ → 110 examples, 0 failures)
  • I have made corresponding changes to the documentation
  • I have updated docs/release-notes/index.md
  • I have updated docs/reference/supported-technologies.md

Verification

End-to-end smoke test against a Rails 8.1 app using solid_queue as the
Active Job adapter, with traces captured by a mock APM server:

  • async supervisor mode — all enqueued jobs produced one transaction each (success, failure with reported exception, non-default queue label).
  • fork supervisor mode (solid_queue's default) — same coverage; each forked Worker process produces transactions, handled by the existing Agent#detect_forking!.

Related issues

N/A

@cla-checker-service

cla-checker-service Bot commented Jun 7, 2026

Copy link
Copy Markdown

💚 CLA has been signed

@lairtonmendes

Copy link
Copy Markdown
Author

❌ Author of the following commits did not sign a Contributor Agreement: , , 485d3b7, c9622e2

Please, read and sign the above mentioned agreement if you want to contribute to this project

Already signed


def self.finalize(io)
proc { io.close }
proc do

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The finalizer registered via ObjectSpace.define_finalizer in proxy_pipe.rb calls io.close, which Ruby forbids inside a signal trap context (ThreadError). SolidQueue workers install persistent Signal.trap handlers; if GC runs while a trap is active (triggered by normal allocations mid-job), the finalizer fires in that context and Ruby
prints a warning. Fixed by rescuing ThreadError in the finalizer the fd is reclaimed by the OS on process exit, so skipping silently is safe

@lairtonmendes lairtonmendes force-pushed the feat/solid-queue-spy branch from c9622e2 to 446ce28 Compare June 7, 2026 15:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant