All jobs

Fix a Rails App Bug From a Datadog Monitor Alert

Yes. A Datadog monitor starts a run; the agent traces failing background jobs to your Rails code, adds a Minitest test, runs bin/rails test and opens a pull request.

Run this on RushIn a Project that has your repository.

What the agent does

Many Rails alerts come from background jobs, not web requests, and the agent reads them that way. Through the Datadog connection it reads the monitor and then the job errors, logs and traces from the 30 minutes around the alert. Datadog's Ruby tracer reports each Sidekiq job under its class name, so a monitor on job failures points at a class such as SendDailyTriageEmailJob or SendSingleTriageEmailJob, with the exception and backtrace on the error span.

In a Rails app like codetriage/CodeTriage (Ruby 4.0.5 per .ruby-version, Rails 8.1.3.1 in the Gemfile, Sidekiq for jobs), issue assignment runs through a short chain. SendDailyTriageEmailJob#perform skips users for reasons it names in reason_for_skip, then calls user.issue_assignments_to_deliver, which returns undelivered assignments up to daily_issue_limit or calls IssueAssigner#assign! to make new ones. IssueAssigner in app/models/issue_assigner.rb walks each subscription and stops at its email_limit. After the mail is queued with deliver_later, the job marks assignments delivered and stamps last_sent_at. The agent reads each step against the backtrace, because a failure after the mail is queued and before update_all sends the same issues again.

It reproduces the failure in Minitest beside the existing job tests in test/jobs/, such as send_daily_triage_email_job_test.rb, an ActiveJob::TestCase that calls perform directly and checks the mail job with assert_enqueued_with, using the fixtures in test/fixtures/. IssueAssigner takes can_access_network: !Rails.env.test?, so tests never call GitHub; the agent keeps it that way. The repository's CI creates the test database with bin/rails db:create db:schema:load on Postgres and runs bin/rake test, and the agent does the same in its sandbox, first the one file with bin/rails test, then everything.

It opens a pull request quoting the job's error log lines and the trace, linking the monitor, and saying what users saw: no email, a duplicate email, or the same issue twice. If the cause is GitHub's API rate limit rather than the code, it says so and changes nothing.

Start it with one API call

POST https://api.prix.dev/o/{org}/sessions with this body:

{
  "agent": "claude",
  "input": "A Datadog monitor on this Ruby on Rails service fired; its webhook payload follows this prompt. Use the Datadog connection to read the monitor and the failing Sidekiq job errors, logs and traces from the 30 minutes around the alert, grouped by job class and exception. Find the code path that produced them in the issue-assignment jobs: app/jobs/send_daily_triage_email_job.rb, send_single_triage_email_job.rb, User#issue_assignments_to_deliver and app/models/issue_assigner.rb. Write a Minitest regression test in test/jobs/ with the existing fixtures and no network calls, set up the Postgres test database, fix the code, run bin/rails test, and open a pull request that quotes the log lines the fix addresses and links the monitor.\n\nMonitor payload:\n{payload}",
  "resources": [
    {
      "url": "https://github.com/your-org/your-app"
    }
  ],
  "connections": [
    "datadog"
  ]
}
  1. Get an API key. In the console, open Settings, then API keys, and create a key for your org. Send it in the Authorization header as a Bearer token.
  2. Send the request. POST the body in request.json to https://api.prix.dev/o/{org}/sessions, with your repository as the resources URL. The run starts in its own cloud sandbox.
  3. Read what came back. Follow the run on its live stream or wait for the run.completed webhook, then read the result and its trajectory.

What comes back

You get a pull request with the fix in a job or in IssueAssigner, and a new test in test/jobs/ that fails on the old code. The description has the quoted job errors, the job class and exception from the trace, the monitor link and the test run's summary. Your CI runs it against Postgres as usual.

The session's result, in data.result on the run.completed webhook, states the cause and the change briefly. The transcript keeps each Datadog query, the database setup and every test run's output, so the reviewer can confirm the suite passed and that no test reached GitHub.

Review the order of operations most carefully. A job that sends mail and then marks it delivered must not send twice when it retries, and a fix that moves update_all should come with a test for the retry. Also check that the skip reasons in reason_for_skip still hold, since they decide who gets email at all.

Run it on every Datadog monitor alert

Add an automation with a webhook trigger to the Project for this app, with this prompt and a saved agent that names the Datadog connection. In Datadog's Webhooks integration, send to the trigger's URL with the trigger's secret as a bearer token, and add @webhook-<name> to the job-failure monitor. Its body follows the prompt as event text; max_runs_per_hour caps runs from a monitor that keeps re-alerting while Sidekiq retries.

Or receive the webhook in your own app and call POST /o/{org}/sessions with this request, the payload appended to input and the alert id as the Idempotency-Key, so Datadog's retries start one run. A webhook on the key tells you when it finishes.

The use case this job follows, with its automation and trigger: Fix a bug from an alert.

Why run it on Rush?

Job bugs surface hours after the code that caused them, usually when a user says they got an email twice or not at all. A Rush run starts when the monitor fires, reads the failing jobs with your Datadog connection, sets up Ruby and Postgres in its own sandbox and runs the real suite, with every command's output kept on the session.

The fix comes with proof: the production errors quoted, a test that reproduces them, and a transcript that shows nothing called GitHub or touched real users. Several monitors can fire at once and each gets its own run and branch.

Frequently asked questions

We report errors to Sentry too. Does that matter?

No. CodeTriage itself reports errors to Sentry through a SentryJob, and the agent reads Datadog because that is where the monitor and traces are. If you want it to read both, connect Sentry as well and name both connections.

Will it send email while testing?

No. config/environments/test.rb sets the mailer's delivery_method to :test and Active Job's queue_adapter to :test, so mail is only enqueued and asserted on. The agent works on a clone with fixture users.

Does it need Redis for Sidekiq?

Not for the tests, which use Active Job's test adapter and call perform directly. If a fix depends on Sidekiq's retry behaviour, the agent can start Redis in the sandbox and says so in the pull request.

Can it retry the failed jobs in production?

No. It fixes code and opens a pull request. Re-enqueueing failed jobs after the fix is deployed is a decision for your team.