+3

Tìm hiểu Gem sidekiq trong ruby on rails

1. Giới thiệu

  • Sidekiq là một gem phục vụ cho việc chạy ngầm các công việc trong ứng dụng rails.

  • Sidekiq sử dụng đa luồng và Redis để xử lý nhiều công việc đồng thời nhau.

  • Redis được hiểu như là một database store để lưu trữ các công việc trong hàng đợi.

  • Theo mặc định thì Sidekiq kết nối với Redis qua cổng localhost:6379 trong môi trường development

2. Configuration

Sidekiq:

  • Trong Gemfile thêm dòng: gem "sidekiq"

  • Sau đó chạy bundle install

Redis:

Sidekiq.configure_server do |config|
  config.redis = {
    url: "redis://127.0.0.1:6379/12"
  }
end

Sidekiq.configure_client do |config|
  config.redis = {
    url: "redis://127.0.0.1:6379/12"
  }
end

Một số option config khác mình sẽ giới thiệu trong phần sau.

3. Luồng hoạt động

Sidekiq gồm 3 phần chính là sidekiq client, sidekiq server, redis

Sidekiq client:

  • Chịu trách nhiệm đẩy job vào hàng đợi trong Redis.

  • Dùng hàm JSON.dump để chuyển dữ liệu thành một hash.

  • Lưu ý: các đối số truyền vào phải là các kiểu json đơn giản như string, integer, boolean, float, null(nil), hash, array

Sidekiq server:

  • Chịu trách nhiệm lấy job từ hàng đợi trong Redis để xử lý.

  • Khởi động Worker và gọi tới hàm perform với các tham số truyền vào.

Redis: Nơi lưu trữ các job.

4. Vòng đời của một job

Các bạn có thể hình dung tổng quan dưới hình này

1.Scheduled: Danh sách các job đang chờ được thực thi

2.Enqueued: Thực hiện một job trong hàng đợi

3.Busy: Job đang được thực thi

4.Failed counter: Số lần job được thực thi nhưng bị lỗi và không hoàn thành.

  • Mặc định số lần có thể xảy ra lỗi của job trước khi bị destroy là 25.
  • Nếu vượt quá số lần thì job sẽ được chuyển sang hàng đợi Dead Queue.
  • Khi tạo job ta có thể custom lại như sau: sidekiq_options :retry => 5

5.Processed: Job hoàn thành

6.Retries: Khi một job bị fail thì nó sẽ được đưa luôn vào Retries Queue nếu Failed Counter chưa vượt quá số lần fail cho phép.

7.Dead Queue: Job đã có số lần fail vượt quá số lần cho phép sẽ được đẩy vào dead queue

5. Sử dụng

Sau khi config SidekiqRedis, bây giờ bạn đã sẵn sàng sử dụng Sidekiq.

Chạy lệnh sau: rails g sidekiq:worker Hard

Khi đó nó sẽ tự động tạo ra file app/workers/hard_worker.rb. Hoặc bạn cũng có thể tạo file đó bằng tay.

class HardWorker
  include Sidekiq::Worker

  def perform(*args)
    # do something
  end
end

Trong đó, perform sẽ là hàm thực thi các tác vụ chạy ngầm.

*args là các đối số truyền vào. Lưu ý là các đối số truyền vào phải là các kiểu json đơn giản như string, integer, boolean, float, null(nil), hash, array, không nên sử dụng symbol, name parameter, ruby object như Date, Time.

Tạo job để chạy ngầm:

  • Tạo job để xử lý bất đồng bộ:
HardWorker.perform_async('bob', 5)
  • Hoặc bạn cũng có thể tạo job để chạy trong tương lai:
HardWorker.perform_in(5.minutes, 'bob', 5)
HardWorker.perform_at(5.minutes.from_now, 'bob', 5)

Mặc định thì sidekiq scheduler sẽ kiểm tra các schedule job cách 5s một lần (15s đối với sidekiq < 5.1), và bạn có thể set lại giá trị đó trong file config/initializers/sidekiq.rb

Sidekiq.configure_server do |config|
  config.average_scheduled_poll_interval = 15
end

Chạy thử: Để thực thi được bạn phải mở 3 tab

  • Tab 1: chạy redis-server redis-server

  • Tab 2: chạy sidekiq bundle exec sidekiq

  • Tab 3: chạy server rails s

    Tạo job chạy và xem kết quả

6. Các cài đặt nâng cao

Bạn có thể config một số option nâng cao trong file config/sidekiq.yml

---
  :concurrency: 5
staging:
  :concurrency: 10
production:
  :concurrency: 20
:queues:
  - critical
  - default
  - low

Queue: Theo mặc định sidekiq sử dụng một hàng đợi duy nhất cho việc xử lý job có tên là default. Bạn có thể tùy chỉnh các hàng đợi với các mức ưu tiên khác nhau.

Concurrency: Sidekiq xử lý các luồng bất đồng bộ, concurrency thể hiện số lượng các luồng chạy trong cùng một lúc.

Sidekiq web: Trong file routes.rb

require "sidekiq/web"
  	mount Sidekiq::Web => "/sidekiq"

7. Server die

Khi sidekiq đang chạy mà stop sidekiq server thì sidekiq sẽ đưa job đang chạy trở lại hàng đợi, và khi sidekiq chạy lại thì job đó sẽ được thực hiện lại từ đầu.

Nếu Redis server bị lỗi thì ngay lập tức sẽ báo lỗi khi Sidekiq gọi đến hàm perform.

Bạn có thể bắt exception tại đó để tránh chết trang:

begin
  SidekiqWorker.perform_async
rescue
  # Do something
end

8. Tham khảo

https://github.com/mperham/sidekiq


All Rights Reserved

Viblo
Let's register a Viblo Account to get more interesting posts.