Solid Queue dan Solid Cache di Rails 8: Panduan Lengkap untuk Interview Teknis 2026

Pembahasan mendalam tentang Solid Queue dan Solid Cache, komponen database-backed default di Rails 8. Job batches, mode eksekusi fiber, Active Job Continuations, dan pengetahuan siap interview untuk 2026.

Arsitektur Solid Queue dan Solid Cache pada Rails 8 dengan pemrosesan job dan caching berbasis database

Kehadiran Solid Queue dan Solid Cache di Rails 8 menandai pergeseran infrastruktur paling besar dalam sejarah framework Ruby on Rails. Kedua komponen ini disertakan sebagai default, menggantikan peran Redis untuk pengelolaan background jobs dan caching dengan pendekatan berbasis database yang menghilangkan satu lapisan kompleksitas operasional secara menyeluruh.

Trifecta Solid pada Rails 8

Rails 8 mengadopsi tiga komponen berbasis database sebagai default: Solid Queue untuk background jobs, Solid Cache untuk cache store, dan Solid Cable untuk WebSockets. Ketiga komponen ini secara kolektif menghapus kebutuhan akan Redis pada sebagian besar aplikasi Rails. Topik ini termasuk salah satu yang paling sering diujikan dalam interview teknis Rails 8 saat ini.

Cara Kerja Solid Queue Menggantikan Backend Job Berbasis Redis

Solid Queue merupakan backend Active Job berbasis database yang menyimpan job secara langsung di PostgreSQL, MySQL, atau SQLite. Mekanisme utama yang mendasari kinerjanya adalah FOR UPDATE SKIP LOCKED, sebuah fitur SQL yang tersedia di PostgreSQL 9.5+ dan MySQL 8+ yang memungkinkan tabel database biasa berfungsi sebagai antrian job konkuren tanpa terjadi blocking antar proses.

Arsitektur Solid Queue dibangun dari tiga komponen utama:

  • Workers melakukan polling pada tabel solid_queue_ready_executions dan mengklaim job menggunakan mekanisme SKIP LOCKED
  • Dispatchers bertugas memindahkan scheduled jobs dari tabel solid_queue_scheduled_executions ke tabel ready begitu waktu eksekusi tiba
  • Schedulers menangani recurring tasks yang didefinisikan dalam file konfigurasi
ruby
# config/solid_queue.yml
production:
  dispatchers:
    - polling_interval: 1
      batch_size: 500
  workers:
    - queues: "*"
      threads: 5
      polling_interval: 0.1
      processes: 2

Konfigurasi di atas menjalankan dua proses worker dengan masing-masing 5 thread, yang melakukan polling setiap 100 milidetik. Dispatcher memeriksa ketersediaan scheduled jobs setiap satu detik dengan ukuran batch sebanyak 500 entri.

Transactional Job Enqueuing pada Rails 8

Salah satu keunggulan paling signifikan Solid Queue dibandingkan backend berbasis Redis terletak pada fitur transactional enqueuing. Ketika sebuah job di-enqueue di dalam transaksi database, job tersebut baru menjadi visible setelah transaksi berhasil di-commit. Backend berbasis Redis tidak mampu memberikan jaminan serupa, karena sebuah job berpotensi tereksekusi sebelum transaksi yang memicunya selesai, sehingga mereferensikan record yang belum tersimpan di database.

ruby
# app/jobs/send_welcome_email_job.rb
class SendWelcomeEmailJob < ApplicationJob
  self.enqueue_after_transaction_commit = true

  queue_as :default

  def perform(user_id)
    user = User.find(user_id)
    UserMailer.welcome(user).deliver_now
  end
end

# app/models/user.rb
class User < ApplicationRecord
  after_create do
    SendWelcomeEmailJob.perform_later(id)
    # Job only enqueued after the CREATE transaction commits
    # No risk of the job running before the user record exists
  end
end

Dengan mengaktifkan enqueue_after_transaction_commit, eksekusi job ditunda hingga transaksi pembungkus berhasil. Apabila transaksi mengalami rollback, job tidak akan pernah di-enqueue. Mekanisme ini mengeliminasi seluruh kelas race condition yang kerap mengganggu sistem berbasis Redis.

Kontrol Concurrency dan Priority Queue

Solid Queue menyediakan mekanisme kontrol concurrency bawaan yang pada Sidekiq hanya tersedia melalui tier berbayar Enterprise. Opsi limits_concurrency membatasi jumlah job dari tipe tertentu yang boleh berjalan secara simultan.

ruby
# app/jobs/api_sync_job.rb
class ApiSyncJob < ApplicationJob
  limits_concurrency to: 3, key: ->(account_id) { "api_sync_#{account_id}" }

  def perform(account_id)
    account = Account.find(account_id)
    ExternalApi.sync(account)
  end
end

Konfigurasi tersebut memastikan bahwa maksimal 3 job API sync berjalan secara bersamaan untuk setiap akun, sehingga mencegah pelanggaran rate limit tanpa memerlukan koordinasi tambahan. Job yang tertunda disimpan dalam tabel solid_queue_blocked_executions dan secara otomatis dirilis begitu slot tersedia kembali.

Sistem prioritas pada Solid Queue beroperasi pada dua tingkatan: prioritas numerik per job (angka lebih rendah berarti prioritas lebih tinggi) dan urutan queue dalam konfigurasi worker. Kedua mekanisme ini dapat dikombinasikan untuk memperoleh kontrol granular terhadap urutan eksekusi job.

Wawasan untuk Interview

Pertanyaan interview Rails 8 yang sangat umum membahas perbandingan antara Solid Queue dan Sidekiq. Perbedaan kuncinya: Solid Queue menawarkan jaminan transaksional dan kontrol concurrency bawaan tanpa biaya tambahan. Sidekiq unggul pada raw throughput untuk beban kerja bervolume tinggi (10.000+ jobs per menit) karena Redis beroperasi secara in-memory. Untuk 95% aplikasi Rails, performa Solid Queue sudah lebih dari memadai. Lihat perbandingan lengkap di artikel Rails background jobs.

Job Batches untuk Operasi Terkelompok

Solid Queue 1.7.0 memperkenalkan fitur job batches, yang memungkinkan pengelompokan dan pelacakan beberapa job sebagai satu kesatuan. Fitur ini mendukung callback ketika seluruh job dalam batch selesai, sebuah pattern yang sebelumnya hanya tersedia di Sidekiq Pro.

ruby
# app/jobs/batch_import_job.rb
class BatchImportJob < ApplicationJob
  def perform(file_id)
    file = ImportFile.find(file_id)
    
    SolidQueue::Batch.enqueue(
      on_finish: BatchFinishedJob,
      on_success: NotifyUserJob,
      on_failure: AlertOpsJob
    ) do |batch|
      file.rows.each_slice(100) do |rows|
        ProcessRowsJob.perform_later(rows.map(&:id))
      end
    end
  end
end

Batch melacak seluruh job yang di-enqueue dalam bloknya. Ketika semua job selesai, callback on_finish dipanggil terlepas dari status keberhasilan atau kegagalan. Jika seluruh job berhasil, on_success dipanggil. Jika ada job yang gagal, on_failure dipanggil. Mekanisme ini memungkinkan workflow seperti proses import di mana langkah akhir harus menunggu semua bagian selesai terlebih dahulu.

Job yang dibuat di luar batch tetapi di-enqueue di dalam batch akan bergabung dengan batch tersebut. Batch yang tidak memiliki job akan langsung selesai dan memanggil callback-nya segera.

Mode Eksekusi Fiber untuk Workload I/O-Bound

Solid Queue 1.6.0 menambahkan mode eksekusi worker berbasis fiber menggunakan gem Async. Mode ini menjalankan job pada fiber alih-alih thread, yang memberikan keuntungan signifikan untuk workload I/O-bound seperti panggilan API LLM di mana sebagian besar waktu dihabiskan untuk menunggu respons.

ruby
# config/solid_queue.yml
production:
  workers:
    - queues: [llm_calls, external_apis]
      fibers: 100
      polling_interval: 0.5

Dengan 100 fiber, 100 job I/O-bound dapat berjalan secara konkuren dalam satu proses dengan overhead memori yang minimal. Ini jauh lebih efisien dibandingkan 100 thread, yang akan mengonsumsi memori secara signifikan lebih besar dan menghadapi kontentsi pada GVL (Global VM Lock).

Mode fiber memerlukan Rails dikonfigurasi untuk isolasi fiber:

ruby
# config/application.rb
config.active_support.isolation_level = :fiber

Job yang CPU-bound tetap sebaiknya menggunakan thread, karena fiber tidak memberikan keuntungan ketika pekerjaan tidak melakukan yield ke I/O.

Active Job Continuations pada Rails 8.1

Rails 8.1 memperkenalkan Active Job Continuations, yang memungkinkan job yang berjalan lama untuk dijeda dan dilanjutkan dari checkpoint. Fitur ini menyelesaikan masalah job yang harus restart dari awal ketika terganggu oleh deployment atau restart container.

ruby
# app/jobs/process_import_job.rb
class ProcessImportJob < ApplicationJob
  include ActiveJob::Continuable

  def perform(import_id)
    @import = Import.find(import_id)

    step :validate do
      @import.validate!
    end

    step :process_records do |step|
      @import.records.find_each(start: step.cursor) do |record|
        record.process
        step.advance!(from: record.id)
      end
    end

    step :finalize do
      @import.mark_complete!
    end
  end
end

Method step mendefinisikan tahapan-tahapan diskrit. Jika job terganggu, eksekusi akan dilanjutkan dari step terakhir yang selesai. Dalam satu step, step.cursor melacak progres: step.advance!(from: record.id) menyimpan posisi cursor. Saat dilanjutkan, find_each(start: step.cursor) melanjutkan dari posisi terakhir yang diproses.

Persyaratan Adapter

Continuations memerlukan queue adapter yang mengimplementasikan stopping?. Solid Queue mendukung ini sejak v1.2.0. Delayed Job dan Resque tidak mendukung graceful interruption tanpa pekerjaan tambahan.

Cursor dapat berupa nilai apa pun yang dapat diserialisasi. Untuk loop bertingkat, gunakan array:

ruby
step :process_nested, start: [0, 0] do |step|
  Account.find_each(start: step.cursor[0]) do |account|
    account.records.find_each(start: step.cursor[1]) do |record|
      record.process
      step.set!([account.id, record.id + 1])
    end
    step.set!([account.id + 1, 0])
  end
end

Recurring Jobs Tanpa Cron

Solid Queue menggantikan kebutuhan penjadwalan berbasis cron dengan scheduler bawaan. Tugas-tugas berulang didefinisikan dalam file konfigurasi YAML dan dikelola oleh proses scheduler.

ruby
# config/recurring.yml
production:
  cleanup_expired_sessions:
    class: CleanupExpiredSessionsJob
    schedule: every 6 hours
  daily_report:
    class: DailyReportJob
    schedule: every day at 6am
    queue: reports
  weekly_digest:
    class: WeeklyDigestJob
    schedule: every Monday at 9am

Proses scheduler membaca file konfigurasi ini dan meng-enqueue job yang sesuai pada interval yang telah ditentukan. Berbeda dengan cron, scheduler berjalan dalam process supervisor yang sama dan berbagi koneksi database yang identik. Dukungan timezone ditambahkan di Solid Queue 1.5.0.

Deployment dengan Integrasi Puma

Rails 8 yang dikombinasikan dengan Kamal menyediakan deployment tanpa konfigurasi tambahan untuk Solid Queue. Pengaturan variabel environment SOLID_QUEUE_IN_PUMA=1 menginstruksikan Puma untuk melakukan fork dan mengawasi proses Solid Queue secara bersamaan dengan web server.

ruby
# config/puma.rb (Rails 8 default)
plugin :solid_queue if ENV["SOLID_QUEUE_IN_PUMA"]

Model deployment single-process ini menyederhanakan orkestrasi container. Satu Docker image dapat menjalankan web server dan job processor sekaligus, mengurangi overhead operasional untuk aplikasi berskala kecil hingga menengah.

Siap menguasai wawancara Ruby on Rails Anda?

Berlatih dengan simulator interaktif, flashcards, dan tes teknis kami.

Solid Cache: Arsitektur Caching Berbasis Database yang Skalabel

Solid Cache adalah implementasi ActiveSupport::Cache::Store berbasis database yang memanfaatkan performa SSD modern untuk menggantikan Redis dan Memcached sebagai cache store default di Rails 8. Premis dasarnya: SSD hanya sedikit lebih lambat dibandingkan RAM untuk operasi baca, namun menawarkan kapasitas penyimpanan yang jauh lebih besar dengan biaya yang secara signifikan lebih rendah. Solid Cache digunakan di production oleh Basecamp dengan kapasitas 10TB dan retensi 60 hari, memotong waktu render P95 hingga separuhnya.

Solid Cache menggunakan strategi expiry FIFO (First In, First Out) alih-alih LRU (Least Recently Used). Meskipun FIFO secara teoretis kurang efisien, kapasitas penyimpanan yang jauh lebih besar memberikan kompensasi: entri cache bertahan jauh lebih lama, sehingga menurunkan cache miss secara keseluruhan.

ruby
# config/environments/production.rb
config.cache_store = :solid_cache_store

# config/solid_cache.yml
production:
  databases:
    - cache
  store_options:
    max_age: 604800        # 1 week in seconds
    max_size: 256           # Max entry size in KB
    namespace: "app_v1"
    expiry_batch_size: 100  # Entries cleaned per expiry cycle

Mekanisme Expiry Cache dan Arsitektur

Solid Cache melacak operasi write menggunakan counter internal. Ketika counter mencapai 50% dari nilai expiry_batch_size yang dikonfigurasi, tugas background secara otomatis terpicu untuk membersihkan entri yang telah expired. Pendekatan amortized ini menghindari jeda stop-the-world yang sering terjadi pada eviction LRU di Redis instance dengan kapasitas memori terbatas.

Tabel solid_cache_entries menyimpan seluruh data cache:

ruby
# db/cache_schema.rb (generated by installer)
create_table :solid_cache_entries do |t|
  t.binary :key, null: false, limit: 1024
  t.binary :value, null: false, limit: 262144  # 256 KB default
  t.datetime :created_at, null: false
  t.index :key, unique: true
  t.index :created_at  # For FIFO expiry
end

Operasi baca dan tulis pada tabel ini secara default menggunakan connection pool yang sama dengan aplikasi utama. Untuk aplikasi dengan traffic tinggi, konfigurasi database terpisah untuk data cache mencegah operasi cache mempengaruhi performa database utama.

Konfigurasi Database Terpisah untuk Cache

Memisahkan Solid Cache ke database yang dedicated merupakan langkah yang direkomendasikan untuk beban kerja production yang menghasilkan traffic cache dalam volume besar.

yaml
# config/database.yml
production:
  primary:
    <<: *default
    database: myapp_production
  cache:
    <<: *default
    database: myapp_cache_production
    migrations_paths: db/cache_migrate

Pemisahan ini menjamin bahwa jutaan operasi write cache tidak membengkakkan WAL (Write-Ahead Log) database utama atau bersaing memperebutkan slot connection pool dengan query aplikasi.

Pertimbangan Penting untuk Production

Tanpa database terpisah, operasi baca dan tulis Solid Cache akan turut berpartisipasi dalam setiap transaksi ActiveRecord yang sedang berjalan. Implikasinya, transaksi yang berjalan lama akan menahan entri cache dalam status uncommitted. Selalu konfigurasi database dedicated untuk cache pada lingkungan production.

Sharding dan Enkripsi Data Cache

Solid Cache mendukung distribusi data cache ke beberapa database melalui mekanisme sharding untuk menyebarkan beban secara merata. Selain itu, Solid Cache juga mendukung encrypted attributes, data cache tetap terenkripsi saat disimpan (at rest), memenuhi persyaratan kepatuhan untuk aplikasi yang menangani informasi sensitif.

ruby
# config/solid_cache.yml
production:
  databases:
    - cache_shard_1
    - cache_shard_2
    - cache_shard_3
  store_options:
    max_age: 1209600  # 2 weeks

Entri didistribusikan ke shard menggunakan consistent hashing berdasarkan cache key. Penambahan atau penghapusan shard akan menyebabkan peningkatan sementara pada cache miss selama proses redistribusi, namun tidak terjadi kehilangan data.

Monitoring dengan Mission Control Jobs

Mission Control Jobs menyediakan dashboard web untuk memeriksa dan mengelola job Solid Queue. Dashboard ini menampilkan informasi tentang workers, queues, serta status job (in progress, finished, blocked, failed) melalui Rails engine yang di-mount.

ruby
# config/routes.rb
Rails.application.routes.draw do
  mount MissionControl::Jobs::Engine, at: "/jobs"
end

# Gemfile
gem "mission_control-jobs", ">= 1.0.1"

Mission Control juga menyediakan API konsol untuk operasi bulk pada failed jobs:

ruby
# Rails console
ActiveJob.jobs.failed.where(job_class: "ApiSyncJob").retry_all
ActiveJob.jobs.failed.where(job_class: "BrokenJob").discard_all

Akses programatik ini sangat penting untuk menangani kegagalan job dalam jumlah besar tanpa harus mengklik satu per satu melalui antarmuka dashboard.

Sources

Pertanyaan Interview Teknis yang Sering Diajukan

Sesi interview Rails 8 semakin banyak memfokuskan pembahasan pada Solid Stack. Berikut adalah pertanyaan-pertanyaan yang paling sering muncul beserta kedalaman jawaban yang diharapkan.

T: Bagaimana Solid Queue mencapai pemrosesan job secara konkuren tanpa Redis? Solid Queue memanfaatkan klausa SQL FOR UPDATE SKIP LOCKED yang memungkinkan beberapa worker melakukan polling pada tabel yang sama tanpa saling memblokir. Setiap worker mengunci sejumlah baris, memproses job pada baris tersebut, lalu menghapus record eksekusi. Worker lain secara otomatis melewati baris yang sudah terkunci dan mengklaim job yang berbeda.

T: Masalah apa yang diselesaikan oleh fitur transactional enqueuing? Transactional enqueuing mencegah job dari tereksekusi sebelum transaksi database yang memicunya berhasil di-commit. Tanpa fitur ini, sebuah job dapat mereferensikan record yang sudah di-rollback, menyebabkan error ActiveRecord::RecordNotFound.

T: Mengapa Solid Cache memilih strategi FIFO dibanding LRU? FIFO lebih sederhana untuk diimplementasikan pada database dan menghindari write amplification yang timbul dari pembaruan access timestamp pada setiap operasi baca. Trade-off ini dikompensasi oleh kapasitas SSD yang jauh lebih besar, sehingga entri cache bertahan lebih lama dan hit rate tetap tinggi meskipun strategi eviction kurang optimal secara teoretis.

T: Bagaimana cara kerja job batches di Solid Queue? Job yang di-enqueue dalam blok SolidQueue::Batch.enqueue dilacak bersama. Batch memanggil on_finish ketika semua job selesai, on_success jika semua berhasil, atau on_failure jika ada yang gagal. Ini memungkinkan workflow seperti batch import di mana langkah akhir bergantung pada penyelesaian semua bagian.

T: Apa itu Active Job Continuations dan kapan sebaiknya digunakan? Continuations memungkinkan job yang berjalan lama untuk menyimpan checkpoint progress dan melanjutkan setelah interupsi. Gunakan untuk job yang memproses dataset besar, seperti import atau batch updates, di mana memulai ulang dari awal pada setiap deployment akan membuang waktu dan resource yang signifikan.

T: Dalam kondisi seperti apa sebuah aplikasi tetap sebaiknya menggunakan Redis dibanding Solid Stack? Redis tetap menjadi pilihan yang lebih tepat untuk aplikasi yang memproses lebih dari 10.000 job per menit, beban kerja yang memerlukan pembacaan cache dengan latensi sub-millisecond, atau aplikasi yang sudah memanfaatkan Redis untuk keperluan lain seperti Pub/Sub, rate limiting, atau session storage. Solid Stack dirancang untuk menyederhanakan operasional, bukan untuk mengejar throughput puncak.

Latihan pertanyaan-pertanyaan ini dan pertanyaan lainnya tersedia di modul ActiveJob & Background Jobs SharpSkill serta modul Caching Strategies.

Siap menguasai wawancara Ruby on Rails Anda?

Berlatih dengan simulator interaktif, flashcards, dan tes teknis kami.

Hal Penting yang Perlu Diingat tentang Solid Queue dan Solid Cache di Rails 8

  • Solid Queue menggantikan antrian job berbasis Redis dengan solusi database-backed yang menggunakan FOR UPDATE SKIP LOCKED untuk pemrosesan konkuren
  • Transactional enqueuing mengeliminasi race condition antara penulisan database dan eksekusi job, sebuah jaminan yang tidak dapat diberikan oleh Redis
  • Job batches (v1.7.0) memungkinkan operasi terkelompok dengan completion callbacks, sebelumnya hanya tersedia di Sidekiq Pro
  • Mode eksekusi fiber (v1.6.0) meningkatkan throughput untuk workload I/O-bound seperti panggilan API LLM
  • Active Job Continuations (Rails 8.1) memungkinkan job yang berjalan lama untuk menyimpan checkpoint dan melanjutkan setelah interupsi
  • Kontrol concurrency bawaan, recurring jobs, dan integrasi Puma tersedia langsung dengan Solid Queue tanpa biaya tambahan
  • Solid Cache menggunakan caching FIFO berbasis SSD dengan dukungan sharding dan enkripsi opsional, menghilangkan kebutuhan Memcached dan Redis dari stack infrastruktur
  • Konfigurasi database terpisah untuk Solid Cache mencegah operasi cache churn dari mempengaruhi performa database utama
  • Mission Control Jobs menyediakan monitoring production dan pengelolaan job secara bulk melalui dashboard web dan API konsol
  • Untuk sebagian besar aplikasi Rails 8 di tahun 2026, Solid Stack merupakan pilihan default yang direkomendasikan. Redis tetap menjadi opsi yang relevan hanya untuk kasus khusus high-throughput yang melebihi 10.000 job per menit

Mulai berlatih!

Uji pengetahuan Anda dengan simulator wawancara dan tes teknis kami.

Tantangan harian

Bisakah kamu menemukan bug di Ruby on Rails?

Satu potongan kode nyata, satu bug tersembunyi, satu percobaan per hari. Tanpa akun untuk mencoba.

Anthony Fillion-Maillet

Ditulis oleh

Anthony Fillion-Maillet

Pendiri SharpSkill

Developer fullstack selama lebih dari 10 tahun. Ia menjalankan SharpSkill dan bertanggung jawab atas semua yang diterbitkan di sini.

Diperbarui 10 Oktober 2026

Tag

#ruby-on-rails
#solid-queue
#solid-cache
#rails-8
#background-jobs
#caching
#interview

Bagikan

Artikel terkait