Skip to content

feat(rails): carry request context into active job - #308

Open
pauldambra wants to merge 4 commits into
posthog/rails-span-contextfrom
posthog/active-job-context
Open

pauldambra wants to merge 4 commits into
posthog/rails-span-contextfrom
posthog/active-job-context

Conversation

@pauldambra

@pauldambra pauldambra commented Oct 17, 2026 •

Copy link
Copy Markdown
Member

[Robot] Prepared with PostHog Desktop on behalf of @pauldambra.

💡 Motivation and Context

Rails users need background job events and spans to keep the session and person IDs from the request that queued the job. Current automatic job instrumentation captures exceptions but loses those IDs across the queue.

  • Use the existing auto_instrument_active_job option to copy only session and distinct IDs into the job payload. Request properties are excluded.
  • Restore a fresh job scope after argument deserialization. The existing job identity extractor takes precedence over the saved browser identity.
  • Keep the snapshot across retries and restore the surrounding context after each attempt. Old jobs without saved IDs run with empty context.
  • Retain one exception capture path, so handled retry and discard errors do not produce extra exception events.

Events, optional logs, and child spans use the same job context. An existing job span receives IDs only when its public Active Job markers match the current job. Other caller spans remain unchanged. No public option, runtime dependency, trace provider, or W3C trace transfer is added.

The scope covers the perform callback and final unhandled exception capture. Custom retry and discard handlers run outside that callback and do not receive its IDs. Bulk enqueue snapshots IDs when the adapter serializes the job.

Builds on #306. Tracks sdk-specs#128.

💚 How did you test it?

  • The OpenTelemetry bundle passes all 1,307 examples. The default bundle has no failures; its 26 optional cases pass in the OpenTelemetry bundle.
  • Real Active Job tests cover JSON queue payloads, delayed serialization, direct execution, bulk enqueue, retries, discarded errors, identity precedence, concurrent workers, and cleanup.
  • A real Rails app sends a request through the installed middleware, queues a job, and executes its serialized payload outside the request.
  • Span and log export checks preserve explicit values and link the active job IDs. No production ingestion or replay test was run.
  • The official OpenTelemetry Active Job instrumentation verifies two jobs, their child spans, an unchanged caller span, and cleanup.
  • The public API snapshot stays unchanged. Full RuboCop, formatting, lock checks, and normal commit hooks pass.

Verified with Rails and Active Job 7.2.3.1 and OpenTelemetry Active Job instrumentation 0.13.0. A full Rails version and queue adapter matrix was not run.

📝 Checklist

  • I reviewed the submitted code.
  • I added tests to verify the changes.
  • I updated the docs if needed.
  • No breaking change or entry added to the changelog.

If releasing new changes

  • Ran pnpm changeset to generate a changeset file

🤖 Agent context

Autonomy: Human-driven (agent-assisted)

Models: GPT-6 (Codex) implemented the job context. GPT-6 Astra reviewed it and implemented the caller-span fix. Used PostHog Desktop. Used Ruby tools, GitHub CLI, and a synthetic Rails app. The implementation reuses the shared context and the existing job instrumentation option. Human review is required.


Created with PostHog Desktop

@pauldambra
pauldambra added this pull request to stack #309 October 17, 2026 20:40
@pauldambra pauldambra self-assigned this Oct 17, 2026
@pauldambra pauldambra changed the title posthog/active job context feat(rails): carry request context into active job Oct 17, 2026

@posthog posthog Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

PostHog Review · Standard · reviewed 0be7d06: 2 Should fix.

This is the only automatic review while this pull request is a draft. Comment @posthog review to review new changes sooner. Otherwise, a review of the new changes runs when you mark it ready for review.

Comment thread posthog-rails/lib/posthog/rails/active_job.rb Outdated
Comment thread posthog-rails/lib/posthog/rails/active_job.rb Outdated
@github-actions

github-actions Bot commented Oct 17, 2026 •

Copy link
Copy Markdown

posthog-ruby-async Compliance Report

Date: 2026-10-18T10:53:41.558363+00:00
Duration: 98173ms

⚠️ Some Tests Failed

46/47 tests passed, 1 failed


Capture Tests

✅ 30/30 tests passed

View Details
Test Status Duration
Format Validation.Event Has Required Fields ✅ 106ms
Format Validation.Event Has Uuid ✅ 105ms
Format Validation.Event Has Lib Properties ✅ 107ms
Format Validation.Distinct Id Is String ✅ 106ms
Format Validation.Token Is Present ✅ 104ms
Format Validation.Custom Properties Preserved ✅ 105ms
Format Validation.Event Has Timestamp ✅ 105ms
Format Validation.Non Utc Event Timestamp Is Converted To Utc ✅ 8ms
Retry Behavior.Retries On 503 ✅ 5407ms
Retry Behavior.Does Not Retry On 400 ✅ 2106ms
Retry Behavior.Does Not Retry On 401 ✅ 2107ms
Retry Behavior.Respects Retry After Header ✅ 8114ms
Retry Behavior.Implements Backoff ✅ 15622ms
Retry Behavior.Retries On 500 ✅ 5210ms
Retry Behavior.Retries On 502 ✅ 5210ms
Retry Behavior.Retries On 504 ✅ 5210ms
Retry Behavior.Max Retries Respected ✅ 15509ms
Deduplication.Generates Unique Uuids ✅ 109ms
Deduplication.Preserves Uuid On Retry ✅ 5210ms
Deduplication.Preserves Uuid And Timestamp On Retry ✅ 10316ms
Deduplication.Preserves Uuid And Timestamp On Batch Retry ✅ 5212ms
Deduplication.No Duplicate Events In Batch ✅ 108ms
Deduplication.Different Events Have Different Uuids ✅ 105ms
Compression.Sends Gzip When Enabled ✅ 104ms
Batch Format.Uses Proper Batch Structure ✅ 105ms
Batch Format.Flush With No Events Sends Nothing ✅ 3ms
Batch Format.Multiple Events Batched Together ✅ 106ms
Error Handling.Does Not Retry On 403 ✅ 2106ms
Error Handling.Does Not Retry On 413 ✅ 2107ms
Error Handling.Retries On 408 ✅ 5211ms

Feature_Flags Tests

⚠️ 16/17 tests passed, 1 failed

View Details
Test Status Duration
Request Payload.Request With Person Properties Device Id ✅ 105ms
Request Payload.Flags Request Uses V2 Query Param ✅ 106ms
Request Payload.Flags Request Hits Flags Path Not Decide ✅ 107ms
Request Payload.Flags Request Omits Authorization Header ✅ 107ms
Request Payload.Token In Flags Body Matches Init ✅ 106ms
Request Payload.Groups Round Trip ✅ 105ms
Request Payload.Groups Default To Empty Object ✅ 105ms
Request Payload.Disable Geoip False Propagates As Geoip Disable False ✅ 105ms
Request Payload.Disable Geoip Omitted Defaults To False ❌ 104ms
Request Payload.Flag Keys To Evaluate Contains Only Requested Key ✅ 104ms
Request Lifecycle.No Flags Request On Init Alone ✅ 3ms
Request Lifecycle.No Flags Request On Normal Capture ✅ 103ms
Request Lifecycle.Two Flag Calls Produce Two Remote Requests ✅ 110ms
Request Lifecycle.Mock Response Value Is Returned To Caller ✅ 104ms
Retry Behavior.Retries Flags On 502 ✅ 251ms
Retry Behavior.Retries Flags On 504 ✅ 240ms
Side Effect Events.Get Feature Flag Captures Feature Flag Called Event ✅ 107ms

Failures

request_payload.disable_geoip_omitted_defaults_to_false

Field 'geoip_disable' not found in /flags request body at path 'geoip_disable'. Available keys: ['distinct_id', 'groups', 'person_properties', 'group_properties', 'flag_keys_to_evaluate', 'token']

@github-actions

github-actions Bot commented Oct 17, 2026 •

Copy link
Copy Markdown

posthog-ruby-sync Compliance Report

Date: 2026-10-18T10:53:34.932362+00:00
Duration: 94035ms

⚠️ Some Tests Failed

45/47 tests passed, 2 failed


Capture Tests

⚠️ 29/30 tests passed, 1 failed

View Details
Test Status Duration
Format Validation.Event Has Required Fields ✅ 10ms
Format Validation.Event Has Uuid ✅ 6ms
Format Validation.Event Has Lib Properties ✅ 7ms
Format Validation.Distinct Id Is String ✅ 8ms
Format Validation.Token Is Present ✅ 6ms
Format Validation.Custom Properties Preserved ✅ 5ms
Format Validation.Event Has Timestamp ✅ 6ms
Format Validation.Non Utc Event Timestamp Is Converted To Utc ✅ 6ms
Retry Behavior.Retries On 503 ✅ 5300ms
Retry Behavior.Does Not Retry On 400 ✅ 2012ms
Retry Behavior.Does Not Retry On 401 ✅ 2012ms
Retry Behavior.Respects Retry After Header ✅ 8018ms
Retry Behavior.Implements Backoff ✅ 15336ms
Retry Behavior.Retries On 500 ✅ 5116ms
Retry Behavior.Retries On 502 ✅ 5117ms
Retry Behavior.Retries On 504 ✅ 5116ms
Retry Behavior.Max Retries Respected ✅ 15537ms
Deduplication.Generates Unique Uuids ✅ 21ms
Deduplication.Preserves Uuid On Retry ✅ 5144ms
Deduplication.Preserves Uuid And Timestamp On Retry ✅ 10231ms
Deduplication.Preserves Uuid And Timestamp On Batch Retry ✅ 5124ms
Deduplication.No Duplicate Events In Batch ✅ 21ms
Deduplication.Different Events Have Different Uuids ✅ 10ms
Compression.Sends Gzip When Enabled ✅ 6ms
Batch Format.Uses Proper Batch Structure ✅ 7ms
Batch Format.Flush With No Events Sends Nothing ✅ 4ms
Batch Format.Multiple Events Batched Together ❌ 21ms
Error Handling.Does Not Retry On 403 ✅ 2013ms
Error Handling.Does Not Retry On 413 ✅ 2012ms
Error Handling.Retries On 408 ✅ 5118ms

Failures

batch_format.multiple_events_batched_together

Expected 1 requests, got 5

Feature_Flags Tests

⚠️ 16/17 tests passed, 1 failed

View Details
Test Status Duration
Request Payload.Request With Person Properties Device Id ✅ 12ms
Request Payload.Flags Request Uses V2 Query Param ✅ 7ms
Request Payload.Flags Request Hits Flags Path Not Decide ✅ 7ms
Request Payload.Flags Request Omits Authorization Header ✅ 7ms
Request Payload.Token In Flags Body Matches Init ✅ 6ms
Request Payload.Groups Round Trip ✅ 7ms
Request Payload.Groups Default To Empty Object ✅ 6ms
Request Payload.Disable Geoip False Propagates As Geoip Disable False ✅ 7ms
Request Payload.Disable Geoip Omitted Defaults To False ❌ 8ms
Request Payload.Flag Keys To Evaluate Contains Only Requested Key ✅ 7ms
Request Lifecycle.No Flags Request On Init Alone ✅ 2ms
Request Lifecycle.No Flags Request On Normal Capture ✅ 7ms
Request Lifecycle.Two Flag Calls Produce Two Remote Requests ✅ 9ms
Request Lifecycle.Mock Response Value Is Returned To Caller ✅ 7ms
Retry Behavior.Retries Flags On 502 ✅ 152ms
Retry Behavior.Retries Flags On 504 ✅ 147ms
Side Effect Events.Get Feature Flag Captures Feature Flag Called Event ✅ 14ms

Failures

request_payload.disable_geoip_omitted_defaults_to_false

Field 'geoip_disable' not found in /flags request body at path 'geoip_disable'. Available keys: ['distinct_id', 'groups', 'person_properties', 'group_properties', 'flag_keys_to_evaluate', 'token']

@pauldambra

pauldambra commented Oct 17, 2026 •

Copy link
Copy Markdown
Member Author

Note

🤖 Automated comment by QA Swarm — not written by a human

Verdict: ✅ APPROVE (privacy round @ 98c5c85)

Restacked on the Rails client-owner fix. Job execution now binds the worker's PostHog.client, so a missing or disabled worker client adds no span IDs. No client is written into job data. Handler context and numeric-ID review threads are fixed and resolved.

Checks

Default and OpenTelemetry suites (1,330 each), RuboCop, and the public API check pass. An independent review accepted the change.

Earlier rounds

Verdict: ✅ APPROVE (round 1 @ 0be7d06)

No remaining actionable finding in the reviewed change. The review checked two-ID queue snapshots, identity precedence, retry cleanup, and exact Active Job span ownership. The recorded official instrumentation proof and full bundle results were reused.

Key findings

  • None remain in this revision. Existing tests and completed review coverage were reused where applicable.
  • Human review and the shared specification decision remain required. This comment does not approve a merge or release.

Convergence

No remaining duplicate finding.

Reviewer summaries

Reviewer Assessment
Router (GPT-6 (Codex)) Complexity HIGH, confidence HIGH. Existing review and validation evidence was reused where applicable. No new delegation was needed for this round.

Automated by QA Swarm. Human review is required. This comment does not approve a merge or release.

Generated-By: PostHog Desktop
Task-Id: 5681be44-4986-48db-b140-1bda88f75f96
Generated-By: PostHog Desktop
Task-Id: 5681be44-4986-48db-b140-1bda88f75f96
Generated-By: PostHog Desktop
Task-Id: 5681be44-4986-48db-b140-1bda88f75f96
Generated-By: PostHog Desktop
Task-Id: bfd18848-e498-4352-a58a-b9ba85de4198
@pauldambra
pauldambra force-pushed the posthog/active-job-context branch from 0be7d06 to 98c5c85 Compare October 18, 2026 10:51

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant