ruby 43 lines · 6 steps

Instrumenting every job in Rails

A base ActiveJob class that adds retry policy and structured, timed logging around every job's execution.

Explained by highlit
1class ApplicationJob < ActiveJob::Base
2 retry_on ActiveRecord::Deadlocked, wait: 5.seconds, attempts: 3
3 discard_on ActiveJob::DeserializationError
4 
5 around_perform do |job, block|
6 metadata = {
7 job_id: job.job_id,
8 job_class: job.class.name,
9 queue: job.queue_name,
10 arguments: job.arguments.map { |arg| summarize(arg) },
11 executions: job.executions,
12 enqueued_at: job.enqueued_at
13 }
14 
15 Rails.logger.tagged("job:#{job.class.name}", job.job_id) do
16 started = Process.clock_gettime(Process::CLOCK_MONOTONIC)
17 Rails.logger.info(metadata.merge(event: "job.started").to_json)
18 
19 begin
20 block.call
21 rescue => error
22 Rails.logger.error(metadata.merge(event: "job.failed", error: error.class.name, message: error.message).to_json)
23 raise
24 ensure
25 duration = Process.clock_gettime(Process::CLOCK_MONOTONIC) - started
26 Rails.logger.info(metadata.merge(event: "job.finished", duration_ms: (duration * 1000).round(2)).to_json)
27 end
28 end
29 end
30 
31 private
32 
33 def summarize(argument)
34 case argument
35 when ActiveRecord::Base
36 { gid: argument.to_gid_param }
37 when Hash
38 argument.transform_values { |value| summarize(value) }
39 else
40 argument
41 end
42 end
43end
01 / 01
STEP 01

Walkthrough

Space play step click any line
Three takeaways
  1. 1An around_perform callback is the natural place to wrap every job with cross-cutting concerns like logging and timing.
  2. 2Emitting JSON events with a monotonic clock gives you reliable, queryable metrics on job duration and failures.
  3. 3Sanitizing arguments before logging keeps sensitive records and payloads out of your logs while preserving traceability.

Related explainers

Share this explainer

Here's the card — post it anywhere.

Instrumenting every job in Rails — share card
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code