ruby 36 lines · 8 steps

Resilient background jobs in Rails

An Active Job and a controller cooperate to send order confirmations reliably, with retries, guards, and strong params.

Explained by highlit
1class OrderConfirmationJob < ApplicationJob
2 queue_as :mailers
3 
4 retry_on Net::OpenTimeout, wait: :polynomially_longer, attempts: 5
5 discard_on ActiveJob::DeserializationError
6 
7 def perform(order)
8 return if order.confirmation_sent?
9 
10 OrderMailer.with(order: order).confirmation.deliver_later(wait: 5.seconds)
11 
12 order.touch(:confirmation_sent_at)
13 end
14end
15 
16class OrdersController < ApplicationController
17 def create
18 @order = current_user.orders.build(order_params)
19 
20 if @order.save
21 OrderMailer.with(order: @order, user: current_user)
22 .confirmation
23 .deliver_later(queue: :mailers)
24 
25 redirect_to @order, notice: "Your order is confirmed."
26 else
27 render :new, status: :unprocessable_entity
28 end
29 end
30 
31 private
32 
33 def order_params
34 params.require(:order).permit(:address_id, :payment_method, line_items: [:sku, :quantity])
35 end
36end
01 / 01
STEP 01

Walkthrough

Space play step click any line
Three takeaways
  1. 1Declarative retry_on and discard_on let a job handle transient and permanent failures without manual rescue blocks.
  2. 2Guard clauses plus a persisted timestamp make a job idempotent so re-runs don't double-send.
  3. 3Enqueuing mail with deliver_later keeps request handling fast by pushing delivery off the web thread.

Related explainers

Share this explainer

Here's the card — post it anywhere.

Resilient background jobs in Rails — share card
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code