Background job luôn là một phần quan trọng trong bất kỳ ứng dụng Ruby on Rails nào. Gửi email, xử lý ảnh, đồng bộ dữ liệu, update cache, xuất file CSV… đều là những tác vụ nặng phải chạy bất đồng bộ để giữ cho ứng dụng nhanh và mượt.
Trong suốt nhiều năm, Sidekiq + Redis gần như là tiêu chuẩn vàng cho background job của Rails. Nhưng từ Rails 8, mọi thứ đã thay đổi: Rails chính thức giới thiệu Solid Queue, một hệ thống queue native, không cần Redis, không cần thêm server phụ trợ.
Bài viết này sẽ giúp bạn hiểu về Solid Queue là gì, cách nó hoạt động và vì sao nên dùng Solid Queue trong các dự án Rails 8 trở lên. Ngoài ra cũng sẽ có phần so sánh với Sidekiq.
Solid Queue là gì?
Solid Queue là hệ thống background job dùng database làm job queue, được phát triển trong Rails Solid Suite (gồm Solid Cache, Solid Queue, Solid Cable).
Khác với Sidekiq sử dụng Redis, Solid Queue lưu job vào bảng database và có worker process đọc, thực thi job.
Nghĩa là:
- Không cần Redis
- Không cần cài Sidekiq
- Không cần chi phí server phụ
- Tích hợp sâu với ActiveJob
- Cài đặt cực đơn giản
Nó sinh ra để làm cho Rails đơn giản hơn, đặc biệt là với startup, dự án nhỏ, trung bình, hoặc môi trường cần hạn chế chi phí.
Những thành phần chính và cơ sở dữ liệu của Solid Queue
Solid Queue không chỉ có 1 bảng đơn giản, nó sử dụng nhiều bảng để quản lý lifecycle của job và đảm bảo an toàn + hiệu suất.
Một số bảng quan trọng:
- solid_queue_jobs: lưu metadata của job, tên class, arguments, queue name, priority, thời gian scheduled_at nếu job delay, id job, v.v.
- solid_queue_ready_executions: chứa các job “đã sẵn sàng” để thực thi ngay, tức job được enqueue (hoặc scheduled tới thời điểm), ready để worker pickup.
- solid_queue_scheduled_executions: chứa job đã schedule (delay / tương lai), chưa tới thời điểm thực thi.
- solid_queue_claimed_executions: lưu thông tin job mà worker đã claim để thực thi, để tránh nhiều worker chạy cùng job.
- solid_queue_blocked_executions: chứa các job bị block, không thể chạy ngay.
- solid_queue_failed_executions: lưu các job đã thực thi nhưng bị lỗi, giúp quan sát & debug.
Nhờ thiết kế nhiều bảng rõ ràng, Solid Queue có thể phân tách rõ vai trò, giúp logic rõ ràng hơn, dễ quản lý.
Vòng đời của một job trong Solid Queue
Để hiểu cách Solid Queue hoạt động và lý do tại sao nó cần nhiều bảng khác nhau, chúng ta hãy xem xét vòng đời đầy đủ của một job, từ lúc được enqueue, được worker pick-up, được thực thi, cho đến lúc bị xóa.
1. Khi job được gọi (enqueue)
Khi bạn gọi MyJob.perform_later(args), Solid Queue sẽ thực hiện hai thao tác ghi dữ liệu vào database:
- Ghi vào bảng solid_queue_jobs: Đây là nơi lưu metadata cho job, ví dụ:
queue_name
,class_name
,arguments
,priority
,active_job_id
,scheduled_at
,finished_at
,concurrency_key
. - Nếu job chạy ngay: ghi thêm dữ liệu vào solid_queue_ready_executions. Bảng này chứa các job đã sẵn sàng để worker xử lý.
2. Worker tìm job để chạy (polling)
Các worker liên tục “poll” bảng solid_queue_ready_executions để lấy job mới. Worker sẽ làm 2 việc sau:
- Claim job: Khi worker chọn một job trong bảng solid_queue_ready_executions, nó sẽ ghi một record vào bảng solid_queue_claimed_executions. Record này giúp đảm bảo không có hai worker chạy cùng một job.
- Perform: Sau khi claim, worker sẽ gọi method perform của class job để thực thi.
3. Khi job hoàn tất, xóa record
Nếu job chạy thành công, worker sẽ xóa job khỏi toàn bộ các bảng liên quan: solid_queue_jobs, solid_queue_ready_executions, solid_queue_claimed_executions. Khi đó, job hoàn toàn biến mất
khỏi queue.
Tóm tắt dễ hiểu vòng đời của 1 job
| Giai đoạn | Bảng liên quan | Mục đích |
|---|---|---|
| Enqueue job | solid_queue_jobs |
Lưu metadata job |
| Job ready | solid_queue_ready_executions |
Worker có thể pick-up |
| Worker claim | solid_queue_claimed_executions |
Đảm bảo 1 worker chạy 1 job |
| Thực thi | N/A | Worker gọi perform |
| Hoàn tất | Xóa nhiều bảng | Dọn dẹp record |
Độ an toàn, không để job bị “mất”
Một trong những yêu cầu quan trọng: job đã enqueue phải được ít nhất thực thi một lần, không được mất. Solid Queue xử lý các edge-case như worker crash / kill / process chết bằng hình thức sau:
- Mỗi worker khi start sẽ tạo record trong solid_queue_processes, và định kỳ update last_heartbeat_at.
- Khi worker claim job, ghi record vào solid_queue_claimed_executions, kèm process id.
- Có một supervisor process (mặc định) chạy nền, check bảng processes: nếu tìm thấy một process không heartbeat quá ngưỡng thời gian cho phép (ví dụ > 5 phút), xem đó như worker chết → supervisor xoá process đó và re-enqueue các job mà worker đó đang giữ (claim) trở lại ready queue, để các worker khác có thể pick.
Nhờ vậy, ngay cả khi worker bị crash, job không bị mất, đảm bảo toàn vẹn dữ liệu.
So sánh Solid Queue và Sidekiq
Solid Queue và Sidekiq đều là hệ thống background job phổ biến trong Rails, nhưng được thiết kế với triết lý khác nhau. Bảng dưới đây giúp bạn thấy rõ sự khác biệt.
| Tiêu chí | Solid Queue (Rails 8) | Sidekiq |
|---|---|---|
| Backend lưu trữ | Database (PostgreSQL / MySQL / SQLite) | Redis (in-memory, cực nhanh) |
| Tích hợp Rails | Native, built-in chính thức từ Rails 8 | Ngoài core, dùng qua gem |
| Hiệu năng | Tốt cho workload nhỏ, trung bình | Rất cao, phù hợp workload lớn |
| Độ trễ (latency) | Cao hơn do dùng database | Thấp (Redis in-memory) |
| Cài đặt | Dễ, không cần service phụ | Cần cài Redis + cấu hình Sidekiq |
| Chi phí vận hành | Gần như bằng 0 (dùng DB sẵn có) | Redis tốn chi phí, nhất là production |
| Reliability | Cao (SQL transaction + job claim) | Rất cao nhưng phụ thuộc Redis |
| Retry logic | Có, lưu trong DB | Có, mạnh mẽ & linh hoạt |
| Dashboard | Chưa có UI mạnh | Có web UI đầy đủ, real-time monitoring |
| Scaling | Scale theo DB & worker process | Scale rất tốt, đặc biệt cho job-heavy apps |
| Scheduled job | Có (nội bộ DB) | Có (redis-based) |
| Recurring job | Hỗ trợ thông qua extension | Sidekiq Enterprise hỗ trợ native |
| Concurrency model | Dựa trên SKIP LOCKED + transactional locking | Redis atomic ops → concurrency rất cao |
| Deployment | Đơn giản: chỉ cần Rails + DB | Cần thêm Redis cluster để production ổn định |
| Khi nào phù hợp? | Ứng dụng nhỏ, vừa, startup, app không quá tải job | Ứng dụng lớn, job nặng, nhiều queue phức tạp |
Khi nào nên chọn Solid Queue?
- Bạn muốn loại bỏ Redis để giảm chi phí.
- Hạ tầng của bạn đơn giản.
- Ứng dụng của bạn không có job volume quá lớn.
- Bạn thích dùng công cụ official, không phụ thuộc gem ngoài.
→ Tóm lại hãy chọn Solid Queue nếu bạn muốn đơn giản, nhẹ, native, tiết kiệm chi phí.
Khi nào Sidekiq vượt trội hoàn toàn?
- Khi bạn xử lý hàng nghìn, hàng triệu job mỗi ngày.
- Khi bạn cần độ trễ thấp và mức độ song song rất cao.
- Khi bạn cần UI quản lý job mạnh mẽ.
- Khi hệ thống của bạn đã dùng Redis từ trước.
→ Tóm lại hãy chọn Sidekiq nếu bạn muốn nhanh, mạnh, phù hợp hệ thống lớn.
Kết luận
Solid Queue đánh dấu một bước tiến lớn của Rails 8 trong việc đơn giản hóa hạ tầng và mang lại trải nghiệm “bật lên là chạy” đúng nghĩa. Việc tích hợp trực tiếp background job vào core framework giúp các dự án nhỏ và vừa không còn phải phụ thuộc Redis hay Sidekiq, giảm đáng kể chi phí vận hành mà vẫn đảm bảo độ ổn định, an toàn và khả năng xử lý job đáng tin cậy.
Trong tương lai, khi Solid Queue tiếp tục hoàn thiện và được cộng đồng đóng góp thêm tính năng, rất có thể nó sẽ trở thành lựa chọn mặc định cho mọi ứng dụng Rails. Còn với Rails 8 hiện tại, Solid Queue đã đủ trưởng thành để trở thành một nền tảng background job mạnh mẽ, an toàn và cực kỳ dễ dùng.
