Background jobs với resque gem, cách hoạt động của các background job framework
Resque là một trong ba background processing frameworks được sử dụng phổ biến nhất hiện nay (delay_job, sidekiq, resque). Resque có nhiều ưu điểm trong đó có ưu điểm về tốc độ và sự phân tách tốt giữa background và foreground code trong ứng dụng. Bài viết này tôi sẽ giới thiệu đến các bạn cách sử ...
Resque là một trong ba background processing frameworks được sử dụng phổ biến nhất hiện nay (delay_job, sidekiq, resque). Resque có nhiều ưu điểm trong đó có ưu điểm về tốc độ và sự phân tách tốt giữa background và foreground code trong ứng dụng. Bài viết này tôi sẽ giới thiệu đến các bạn cách sử dụng resque cũng như là cách thực hoạt động bên trong của resque như thế nào.
1, Cài đặt
- Giống như sidekiq, resque hoạt động dựa trên redis. Redis là một kỹ thuật lưu dữ liệu mới xuất hiện từ năm 2009 với ưu điểm là tốc độ và khả năng lưu được những cấu trúc dữ liệu phức tạp. Để hiểu hơn về redis các bạn có thể đọc thêm tại đây (http://redis.io/). Do đó, để có một app resque hoạt động trước tiên bạn cần phải cài đặt redis.
Cài redis-server:
sudo apt-get install redis-server
Khởi động redis-server:
redis-server
Nếu trên terminal xuất hiện thông báo như hình trên có nghĩa là bạn đã cài đặt redis server thành công.
- Tiếp theo tiến hành cài đặt resque
Trong Gemfile thêm dòng:
gem "resque"
Sau đó gõ lệnh:
bundle install
Cài đặt rake tasks
Resque có cung cấp một số rake tasks cho phép chạy workers trong ứng dụng. Để có thể sử dụng các rake tasks này thêm file lib/tasks/resque.rake và định nghĩa rake tasks liên quan của resque
require 'resque/tasks'
Để các workers có thể access tới models bạn cần thêm dòng sau tới file resque.rake vừa tạo
task “resque:setup” => :environment
Như vậy đến đây chúng ta đã thực hiện xong phần cài đặt và cấu hình cho resque
2. Tạo background jobs
Tạo thư mục app/workers
Thư mục này sẽ là nơi chứa các jobs của resque
Trong phần này tôi sẽ viết một job đơn giản tên là print với chức năng cơ bản là in ra terminal dòng có dạng như: “Hello everybody. My input: ….”
Tạo file print.rb trong thư mục app/workers/ có nội dung như sau:
class Print @queue = :print class << self def perform input puts "hello everybody. My input is #{input}" end end end
Đầu tiên bạn định nghĩa một biến instance class có giá trị là tên của queue mà Print jobs được đưa vào. Sau đó định nghĩa class method perform đây chính là method được gọi để xử lý job trong queue. Đến đây bạn đã định nghĩa xong một jobs. Bước tiếp theo là đưa job vào queue và dùng worker để xử lý các jobs
Ở phần 1 chúng ta đã cấu hình cho các rake tasks của resque, đây là lúc sử dụng chúng. Hãy gõ lệnh sau để bật worker cho Print jobs
rake resque:work QUEUE=print
Lưu ý print ở đây chính là giá trị của biến instance class @queue
worker đã được start, lúc này nó sẽ kiểm tra xem trong print queue có job nào không nếu có sẽ thực hiện lần lượt cho đến hết. Nếu không có thì mặc định 5s sau nó lại kiểm tra tiếp. Quy trình cứ tiếp tục cho đến khi nào worker bị stop. Hiện tại trong print queue chưa có job nào nên worker không xử lý gì cả. Vậy làm thế nào để tạo ra các jobs, resque có cung cấp class method “enqueue” để tạo ra các jobs trong queue. Bật rails console và thực hiện cách lệnh sau:
Khi đó 1 job đã được tạo và đưa vào queue tương ứng là “print”. Worker phát hiện trong queue có một job và nó sẽ thực hiện xử lý job đó.
3. Giao diện quản lý resque
Resque có cung cấp một giao diện Sinatra-base, từ đây có thể xem trang thái hiện tại của các queue
Để sử dụng được giao diện này. Thêm dòng require 'resque/server' ở vị trí đầu của route.rb file. Sau đó định nghĩa path cho resque như sau trong route.rb file
mount Resque::Server.new, :at => "/resque"
Sau đó access url sau để xem kết quả: localhost:3000/resque
Như đã biết, resque cũng như sidekiq làm việc dựa trên redis. Mọi xử lý bên trong có thể minh họa bằng ví dụ đơn giản dưới đây:
- Đầu tiên tạo một biến global là instance của Redis Tạo file config/initializers/redis.rb và thêm dòng sau:
$redis = Redis.new
- Cấu hình để rails tự động load các file .rb trong thư mục /lib/
Trong file application.rb thêm dòng sau:
config.autoload_paths += %W(#{config.root}/lib)
- Tạo file lib/bg/queue_job.rb Trong file này chúng ta sẽ tiến hành tạo Bg::QueueJob class sau đó thêm các methods cần thiết để mô phỏng một hệ thống tạo các background job, queuing jobs và processing jobs:
- Tạo các methods để enqueueing, xóa hết jobs trong queue, xóa queue, xem số lượng jobs trong queue, xóa một job trong queue, xem job tiếp theo trong queue
class Bg::QueueJob def enqueue queue_name, data $redis.sadd "queues", queue_name $redis.rpush "queue:#{queue_name}", data.to_json end def clear queue_name $redis.del "queue:#{queue_name}" end def destroy queue_name self.clear queue_name $redis.srem "queues", "queue:#{queue_name}" end def length queue_name $redis.llen "queue:#{queue_name}" end def remove_job queue_name, data $redis.lrem queue_name, 0, data.to_json end def peek queue_name $redis.lrange "queue:#{queue_name}", 0, 0 end end
Ở đây, mỗi queue được đại diện bởi một list trong redis, mỗi job trong queue là một phần tử trong list.
- Tiếp theo thêm các methods sau vào QueueJob class để xử lý các jobs có trong queues
def dequeue queues $redis.blpop(*queues.map{|q| "queue:#{q}"}.push(60)) end def work queues while true do job = self.dequeue queues process_job job unless job.nil? end end private def process_job job puts "#{job.inspect} " end
Phương thức dequeue dùng để lấy ra các jobs trong các queues, nếu trong các queues đó không có jobs nào thì tiếp tục chờ trong 60s, trong khoảng thời gian chờ này nếu có job mới được đưa vào queue thì trả về job nếu vẫn không có job nào được đưa vào thì hết 60s sẽ trả về nil
Phương thức work có cách thức hoạt động giống worker trong resque, nó tạo một vòng lặp vô hạn nghĩa là work luôn luôn làm việc và cứ 60s lại check xem có job nào được đưa vào queue không nếu có thì xử lý job với phương thức process_job
Phương thức process_job đơn giản chỉ để in ra dữ liệu của job được đưa vào queue
worker ban đầu xử lý các jobs đang có trong các queue sau đó chờ các jobs khác được đưa vào queue để xử lý
Thêm một job vào queue
Kết quả là job được xử lý bởi worker đang được bật.
Bài viết trình bày cơ bản cách sử dụng resque để tạo các background jobs. Tiếp theo bài viết có đề cập đến cách thức các framework background job hoạt động dựa trên redis thông qua một ví dụ đơn giản. Mong rằng bài viết này sẽ giúp bạn có cái nhìn sau hơn về resque cũng như các background framework khác. Cám ơn bạn đã quan tâm đến bài viết. Hẹn gặp lại trong các bài viết tiếp theo.
_**