Membedah Active Job dan Action Mailer: latar belakang kerja asinkron, queue adapters seperti Solid Queue dan Sidekiq, background jobs, mailer dengan template & delivery options, plus praktik notifikasi email async

Setelah di episode 10 kalian melindungi aplikasi dengan test, episode 11 membahas pekerjaan yang tidak boleh memblokir respons HTTP: background jobs (Active Job) dan email (Action Mailer). Dua hal ini hampir selalu berjalan beriringan — mengirim email adalah contoh klasik kerja lambat yang sebaiknya asinkron.
Mengapa penting dikuasai? Karena di aplikasi nyata, hal-hal seperti mengirim email ke ribuan user, memproses gambar, atau memanggil API eksternal tidak boleh membuat user menunggu. Memindahkan kerja berat ke background queue membuat respons cepat dan pengalaman pengguna mulus. Dan email yang terkirim dengan benar adalah tulang punggung komunikasi aplikasi — verifikasi, reset password, notifikasi.
Bayangkan user klik "simpan" lalu harus menunggu 10 detik karena app menghubungi API eksternal yang lambat. Itulah yang dihindari background job:
Request selesai secepat save data; kerja berat (email, API, resizing gambar) dikerjakan worker di luar request. User mendapat respons instan, dan jika worker crash, job tetap antri dan bisa diulang.
Active Job adalah antarmuka umum untuk semua backend queue. Job hanyalah class Ruby:
bin/rails g job ProcessReportclass ProcessReportJob < ApplicationJob
queue_as :default
def perform(report_id)
report = Report.find(report_id)
rows = report.generate_rows
ReportExporter.export(rows)
end
endDijalankan di mana pun:
ProcessReportJob.perform_later(report.id)
ProcessReportJob.set(wait: 5.minutes).perform_later(report.id)
ProcessReportJob.perform_now(report.id) # sinkron, untuk debugperform_later menaruh job ke queue; set(wait:) menjadwalkan. Kode yang memanggil job tidak peduli backend apa yang dipakai — Active Job menyembunyikannya.
Rails 8 memakai Solid Queue secara default — queue berbasis database, tanpa layanan tambahan:
config.active_job.queue_adapter = :solid_queueUntuk kebutuhan throughput tinggi, Sidekiq (Redis) adalah pilihan klasik:
config.active_job.queue_adapter = :sidekiq| Adapter | Backend | Kelebihan | Kekurangan |
|---|---|---|---|
| Solid Queue | PostgreSQL/MySQL | Tanpa infra tambahan, transactional, sudah default Rails 8 | Kinerja menengah untuk volume sangat besar |
| Sidekiq | Redis | Sangat cepat, UI monitoring | Butuh Redis; job bisa hilang saat Redis crash tanpa mode pro |
| Async (dev) | In-process | Mudah untuk development | Tidak bertahan restart |
Action Mailer adalah modul email Rails. Mailer adalah class seperti controller, dengan view sendiri:
bin/rails g mailer PostMailer post_publishedclass PostMailer < ApplicationMailer
def post_published(user, post)
@user = user
@post = post
mail(to: user.email, subject: "Post baru terbit: #{post.title}")
end
endTemplate email di app/views/post_mailer/ — versi teks dan HTML:
<h1>Halo <%= @user.name %></h1>
<p>Post terbaru telah terbit: <%= link_to @post.title, @post %></p>Konfigurasi delivery di environment:
config.action_mailer.delivery_method = :smtp
config.action_mailer.smtp_settings = {
address: "smtp.example.com", port: 587,
user_name: Rails.application.credentials.smtp[:user],
password: Rails.application.credentials.smtp[:password]
}Di development, config.action_mailer.raise_delivery_errors = true membuat error email langsung terlihat. Tools seperti Letter Opener menampilkan email di browser tanpa mengirim sungguhan.
Kombinasi mailer + job adalah pola paling umum. Kita bungkus pengiriman di job agar tidak memblokir request:
class PostNotificationJob < ApplicationJob
def perform(post_id)
post = Post.find(post_id)
User.where(subscribed: true).each do |user|
PostMailer.post_published(user, post).deliver_now
end
end
endController hanya mengantri:
def create
@post = Post.new(post_params)
if @post.save
PostNotificationJob.perform_later(@post.id)
redirect_to @post, notice: "Post terbit. Email sedang dikirim."
else
render :new, status: :unprocessable_entity
end
endPola ini membuat response cepat; pengiriman ribuan email berjalan di worker. Untuk email per-user lebih baik kirim per-user di dalam loop job (bukan satu job raksasa) agar satu kegagalan tidak menggagalkan semua.
Job tidak berjalan otomatis di development; worker harus dijalankan:
bin/rails solid_queue:startDi production, bin/rails solid_queue:start dijalankan sebagai proses terpisah (dibahas di episode 22 & 24). Lupa menjalankan worker adalah alasan paling umum "email tidak terkirim di development".
Warning
Jangan memanggil API eksternal atau mengirim email sinkron di dalam request kecuali benar-benar diperlukan. Response jadi lambat, dan jika proses crash di tengah jalan, kerja hilang tanpa jejak. Background job memberi retry otomatis dan audit trail.
perform(post_id) lalu fetch dari DB (bukan meneruskan objek), agar job memakai snapshot terkini dan aman di-serialize.rescue/retry_on agar satu kegagalan tidak membatalkan batch.deliver_now untuk volume besar di dalam request — gunakan job; deliver_later menempatkan ke queue.retry_on/max retry sesuai kebutuhan.Episode 11 membekali kalian kerja asinkron Rails: Active Job sebagai API seragam, Solid Queue default database-driven vs Sidekiq untuk throughput tinggi, Action Mailer dengan template teks/HTML dan SMTP settings, serta pola notifikasi email yang dienkue dari controller agar response tetap cepat.
Inti yang harus dibawa pulang:
perform_later untuk async, set(wait:) untuk jadwal.Di episode 12 selanjutnya kita akan membedah caching & performance — fragment/page caching, Russian Doll caching, low-level cache, cache stores (Redis, Solid Cache), serta optimasi query N+1 dengan includes/joins. Sampai jumpa di episode 12!