iT邦幫忙

第 12 屆 iT 邦幫忙鐵人賽

DAY 25
0
自我挑戰組

Ruby on Rails 與它們相關的東西系列 第 25

Day25 - Ruby on Rails 中的 Sidekiq 的介紹與應用

前言

Sidekiq 是 Ruby on Rails 中蠻常用的後台任務處理系統,上篇介紹了 Resque Gem,已知這 2 套 Gem 相比,Sidekiq 的效能比較好...

本身提供的 API 十分簡潔,連 Source Code 也是易於閱讀 (例如這段),Sidekiq 分成 3 種版本 (開源、專業、企業版),欲知差異可到官方網站往下滑便能看到差異比較表,本文以 OSS (Open Source Software) 進行操作

後續的文章會以此 repo 作為範例

如何安裝

放在 Gemfile 檔案中,可參考此 commit

# Gemfile
gem 'sidekiq', '~> 6.1', '>= 6.1.2'

# 記得要 bundle

加上 Web 介面,可參考此 commit

# config/routes.rb
require 'sidekiq/web'
mount Sidekiq::Web => '/sidekiq'

將 ActiveJob 改由 Sidekiq 處理,可參考此 commit

備註: 預設情況下的佇列 (Queue) 的優先順序都為 1,下方 ['default', 1]['mailers', 1] 可縮寫成 defaultmailers

# config/application.rb
config.active_job.queue_adapter = :sidekiq


# config/sidekiq.yml
:concurrency: 10
:queues:
  - ['default', 1]
  - ['mailers', 1]
:timeout: 86400

寫個 Worker 確認能否執行

可參考此 commit

# app/controllers/users_controller.rb
Api::CreateOrderWorker.perform_async(@user.id)


# app/worker/api/create_order_worker.rb
module Api
  class CreateOrderWorker
    include Sidekiq::Worker
    sidekiq_options retry: 7, dead: true, queue: 'create_order_worker'

    sidekiq_retry_in { |count| count + 86_400 }

    sidekiq_retries_exhausted do |msg, _ex|
      subject = "[Api::CreateOrderWorker]Out of retries! #{msg['class']} with #{msg['args']}"
      _message = "error: #{msg['error_message']}"
      FileLog.logger('worker/api/create_order_worker.log').error(subject)
      # ...
    end

    def perform(user_id)
      logger.info "====== start ====== user_id: #{user_id}"
      puts 'hello world'
      logger.info '====== done ======'
    rescue StandardError => e
      logger.error "[Api::CreateOrderWorker] ERROR:\n #{e.inspect}\n #{e.backtrace}"
    end

    private

    def logger
      FileLog.logger('worker/api/create_order_worker.log')
    end
  end
end


# config/sidekiq.yml
  - ['create_order_worker', 10]

如何執行

終端機輸入

sidekiq
# or
bundle exec sidekiq

Sidekiq 啟動成功畫面

bundle exec sidekiq


               m,
               `$b
          .ss,  $$:         .,d$
          `$$P,d$P'    .,md$P"'
           ,$$$$$b/md$$$P^'
         .d$$$$$$/$$$P'
         $$^' `"/$$$'       ____  _     _      _    _
         $:     ,$$:       / ___|(_) __| | ___| | _(_) __ _
         `b     :$$        \___ \| |/ _` |/ _ \ |/ / |/ _` |
                $$:         ___) | | (_| |  __/   <| | (_| |
                $$         |____/|_|\__,_|\___|_|\_\_|\__, |
              .d$$                                       |_|


2020-09-27T07:58:31.874Z pid=95276 tid=1z4c INFO: Booted Rails 6.0.3.3 application in development environment
2020-09-27T07:58:31.874Z pid=95276 tid=1z4c INFO: Running in ruby 2.7.1p83 (2020-03-31 revision a0c7c23c9c) [x86_64-darwin19]
2020-09-27T07:58:31.874Z pid=95276 tid=1z4c INFO: See LICENSE and the LGPL-3.0 for licensing details.
2020-09-27T07:58:31.874Z pid=95276 tid=1z4c INFO: Upgrade to Sidekiq Pro for more features and support: https://sidekiq.org
2020-09-27T07:58:31.874Z pid=95276 tid=1z4c INFO: Booting Sidekiq 6.1.2 with redis options {}
2020-09-27T07:58:31.876Z pid=95276 tid=1z4c INFO: Starting processing, hit Ctrl-C to stop

Sidekiq Web 介面

指定時間執行 Sidekiq

需額外安裝擴充套件 sidekiq-scheduler Gem,可參考此 commit

備註: 可參考 sidekiq-scheduler GitHub 官方文件

# Gemfile
gem 'sidekiq-scheduler', '~> 3.0', '>= 3.0.1'

# 記得要 bundle

相關設定及範例如下,可參考此 commit

備註: 對 Cron 不熟悉的話,可看 Wiki 說明,並搭配 Crontab.guru 這網站使用

# config/application.rb
Redis.exists_returns_integer = true


# config/routes.rb
require 'sidekiq-scheduler/web'


# config/sidekiq.yml
  - ['scheduler', 5]

:schedule:
  CheckWorker:
    cron: '30 * * * *'
    queue: scheduler
    enabled: true
		
		
# app/worker/check_worker.rb
class CheckWorker
  include Sidekiq::Worker
  sidekiq_options retry: 0, queue: 'check_worker'

  def perform
    puts 'At minute 30.'
  end
end


# 這範例是每整點的 30 分,會執行一次 CheckWorker

Sidekiq Recurring Jobs 畫面

更多指令

sidekiq -h

INFO: sidekiq [options]
  -c, --concurrency INT            processor threads to use
  -d, --daemon                     Daemonize process
  -e, --environment ENV            Application environment
  -g, --tag TAG                    Process tag for procline
  -q, --queue QUEUE[,WEIGHT]       Queues to process with optional weights
  -r, --require [PATH|DIR]         Location of Rails application with workers or file to require
  -t, --timeout NUM                Shutdown timeout
  -v, --verbose                    Print more verbose output
  -C, --config PATH                path to YAML config file
  -L, --logfile PATH               path to writable logfile
  -P, --pidfile PATH               path to pidfile
  -V, --version                    Print version and exit
  -h, --help                       Show help

參考資料

  1. RailsCasts - #366 Sidekiq
  2. 在 Rails 專案中使用 Sidekiq 處理非同步任務
  3. Sidekiq 如何處理非同步任務

小結

Sidekiq 功能非常強大且容易上手,工作上蠻常使用,舉例來說,它的 retry 機制很實用,像打 API 建立訂單,若過程中發生錯誤的話,透過 retry 機制,能重新執行該 job (能設定 retry 上限、每次間隔時間、超過 retry 上限的話...),並設定 Slack 與 Email 通知 (這部分要自己實作),能即時知道發生異常,進而判斷要如何處理,本身的 Wiki 文件也很完整,且網路上有許多文章、影片 (ex: Youtube 等) 可以參考


鐵人賽文章連結:https://ithelp.ithome.com.tw/articles/10246607
medium 文章連結:https://link.medium.com/RPXFvaCabab
本文同步發布於 小菜的 Blog https://riverye.com/

備註:之後文章修改更新,以個人部落格為主


上一篇
Day24 - Ruby on Rails 中的 Resque 的介紹與應用
下一篇
Day26 - Ruby on Rails 中使用 FFmpeg 處理影音轉檔、合併、上字幕
系列文
Ruby on Rails 與它們相關的東西31

尚未有邦友留言

立即登入留言