getsentry / getsentry/sentry-ruby

New spec suite for Active Job integrations

Open
#2,933 1 comment 0 reactions 1 assignee Claimed by @solnic View on GitHub
Improvement Ruby Spans
Dominant language
Ruby
Stars
987
Forks
541
Avg merge
17h 40m
Merged PRs (30d)
19

Description

### Description

⚠️ This won't be done all-at-once - this issue is an anchor for all the work that must be done for the epic issue getsentry/sentry-ruby#2932. It will be growing and most likely being refined as we move forward. It will be done/closed once all the backends have been ported.

---

The existing [activejob_spec.rb]() is a monolithic file that mixes lifecycle, context, tracing, retries and cron into one describe block and only runs against `:test`. It is not a suitable foundation for a rework that has to prove identical behavior across all AJ-based integrations.

The goal is to replace the original specs with a dedicated, shared-example-driven AJ spec suite under a new tree (e.g. `sentry-rails/spec/active_job/`). Each feature area lives in its own shared-example file. Each backend ships as a thin spec file whose entire body is roughly:

```ruby
RSpec.describe "Sentry + ActiveJob on SolidQueue" do
include_context "active_job backend harness", adapter: :solid_queue
it_behaves_like "a Sentry-instrumented ActiveJob backend"
end
```

General principles and ideas:

* One top-level shared example — "a Sentry-instrumented ActiveJob backend" — composes smaller per-area shared examples. Adding a new backend is a one-line include.
* Shared examples never branch on adapter name. Per-backend quirks go through a harness helper (boot, enqueue, drain, reset) that each backend's spec file supplies via `let` or shared context.
* Backend-specific behaviors (e.g. sidekiq retry middleware, solid_queue recurring jobs) live in the respective backend-specific dirs or dedicated gems (sentry-sidekiq).

**Feature areas the shared suite must cover**

* **Harness & scaffolding.** New spec tree, shared context for adapter setup / teardown / draining, fixture jobs (normal, failing, retryable, discardable, scheduled, mailer, rescue-from, deserialization-error, nested-enqueue), transport/event helpers. No behavioral assertions yet — just the rails the rest of Phase 0 runs on.
* **Job lifecycle.** `perform_now`, `perform_later` + drain, `set(wait:)` / `set(wait_until:)` scheduled jobs, `retry_on`, `discard_on`, `rescue_from` (both suppressing and re-raising), `ActiveJob::DeserializationError` root-cause unwrapping, `ActionMailer::MailDeliveryJob` path.
* **Error capture & context.** Exception type/message/stacktrace round-trip, `extra` payload (active_job, arguments, scheduled_at, job_id, provider_job_id, locale, queue, executions), tags (job_id, provider_job_id, queue), scope cleared between jobs, `rescue_from`-suppressed errors produce no event, errors raised from `rescue_from` callbacks produce both events.
* **Consumer-side tracing.** Transaction name = job class, `source: :task`, op + origin conventions, `status: ok` / `internal_error`, event linked to transaction via same `trace_id`, messaging span data (`messaging.destination.name`, `messaging.message.id`, retry count, latency, provider job id), gated correctly by `traces_sample_rate`.
* **Producer-side tracing.** Enqueue within an active transaction produces a `queue.publish` child span; span carries the same messaging data; scheduled enqueue does the same. *(Pending until Phase 1.)*
* **Distributed tracing.** Producer trace headers round-trip through the payload; consumer transaction's `trace_id` matches producer's; consumer's `parent_span_id` points at the producer's publish span; baggage survives. Verified per backend — this is the shared suite's most important test for adapter conformance.
* **Scope & context propagation.** Hub cloned per job, user set on producer scope surfaces on consumer scope, tags propagate, no scope leak between consecutive jobs, no leak across threads/fibers.
* **Retry & discard semantics.** `active_job_report_on_retry_error` true/false, final-attempt-only reporting, discarded jobs emit no event, retry count reflected in transaction span data and tags, exhausted-retry capture.
* **Argument serialization.** Ports the existing GlobalID / nested / Range / TimeWithZone / raising-`to_global_id` coverage from the old file into a dedicated shared-examples file. Adds sensitive-value handling (`send_default_pii`) if applicable.
* **Concurrency.** Parallel job execution keeps scopes isolated; thread-local hub is not shared; trace ids do not cross-contaminate.
* **Backend wiring.** One thin spec file per adapter: `:test`, `:inline`, `:async`, `solid_queue`, `good_job`, `sidekiq`. Each just configures the adapter via the harness and includes the top-level shared example.

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.