Gem 如何使用 Sidekiq 进行异步处理

heroyct · May 14, 2018 · Last by heroyct replied at May 21, 2018 · 10828 hits
Topic has been selected as the excellent topic by the admin.

什么是 sidekiq

提供了异步处理功能的gem
这里简单了归纳了一下如何在 rails 的项目里面使用 sidekiq

准备工作

异步处理的数据放在 redis 里面,所以需要安装 redis
如果用的是 mac 的话,可以用brew install redis安装

添加 Gem

在 Gemfile 里面添加,然后bundle install --path vender/bundle进行安装

gem 'sidekiq'

设置

创建一个文件 config/initializers/sidekiq.rb

require 'sidekiq/web'

Sidekiq.configure_server do |config|
  config.redis = { url: "#{Settings.redis.url}/#{Settings.redis.sidekiq_db}", namespace: Settings.redis.sidekiq_namespace }
  config.server_middleware do |chain|
    chain.add Sidekiq::Middleware::Server::RetryJobs, max_retries: 4
  end
end
Sidekiq.configure_client do |config|
  config.redis = { url: "#{Settings.redis.url}/#{Settings.redis.sidekiq_db}", namespace: Settings.redis.sidekiq_namespace }
end

开发环境和实际的服务器环境的 redis 的设置不同,所以放在 settings 里面

redis:
  url: <%= ENV['REDIS_URL'] || 'redis://127.0.0.1:6379' %>
  db: '0'
  sidekiq_db: '1'
  sidekiq_namespace: sidekiq<%= ENV['RAILS_ENV'] %>

发送邮件

在 application.rb 里面添加以下代码

config.active_job.queue_adapter       = :sidekiq

然后发送邮件的时候使用 deliver_later 就可以异步发送

UserMailer.send_mail(User.find(1)).deliver_later

Worker

进行异步处理的 worker 类都放在 app/workers 文件夹下面

比如要对用户数据进行排名 app/workers/use_ranking_worker.rb

class UserRankingWorker
  include Sidekiq::Worker
  sidekiq_options queue: :event, retry: 3

  def perform(user_id)
    user = User.find_by(user_id)
    return if user.blank?
    ## do something
  end
end

把人物加入 Queue(队列)

使用 perform_async 方法来加入队列

class UserService
  def ranking(user)
    UserRankingWorker.perform_async user.id
  end
end

也可以使用 perform_in 在指定时间后执行

class UserService
  def ranking(user)
    UserRankingWorker.perform_in 1.hour, @event.id
  end
end

sidekiq 起動

设置

config/sidekiq.yml

# thread数
:concurrency: 35
:pidfile: ./tmp/pids/sidekiq.pid
:logfile: ./log/sidekiq.log
:daemon: true
# 对需要立刻处理的任务指定优先级
:queues:
  - [mailers, 100]
  - [events, 1]

启动 sidekiq

bundle exec sidekiq -C config/sidekiq.yml -d

发布

需要注意的是,新的代码更新后,sidekiq 必须重新启动才可以
现在的项目用的是 capistrano 来进行发布,添加capistrano-sidekiq这个 GEM 后,在 config/deploy.rb 添加一下代码后,可以在每次发布后重新启动 config/deploy.rb

set :sidekiq_role, :worker
set :sidekiq_config, "#{current_path}/config/sidekiq.yml"
SSHKit.config.command_map[:sidekiq] = 'bundle exec sidekiq'
SSHKit.config.command_map[:sidekiqctl] = "bundle exec sidekiqctl"

为了不影响 web 服务器,所以新建了一个 worker 服务器,专门用来运行 sidekiq,可以根据实际情况进行调整

管理画面

sidekiq 自带了一个管理画面,按照下面的方法可以很容易的添加
可以看到正在进行的任务,失败的任务,成功的任务
失败的任务还可以选择以后从画面上重启

添加 Gem

gem 'sinatra', require: false

在 routes.rb 追加 routing config/routes.rb

require 'sidekiq/web'

MyApp::Application.routes.draw do
  authenticate :operator, lambda { |o| o.developer? } do
    mount Sidekiq::Web => '/sidekiq'
  end
end

因为这个画面不能让任何人都看到,所以设置成在管理画面里面并且是开发人员才可以看到 然后/sidekiq 就可以看到了

总结

在提高服务器的应答速度的时候,可以进行异步处理的部分都可以用 sidekiq 来处理,这样可以有效提高服务器应答速度
发送邮件之类的,由于网络原因或者邮件服务器原因一时无法发送的时候可以重新执行任务,非常简单实用

huacnlee mark as excellent topic. 17 May 18:10

其实 sidekiq 后来已经不需要 sinatra 这个 gem 了。https://github.com/mperham/sidekiq/pull/3075

Reply to liukun_lk

而且是两年前的事情了 😹

Reply to liukun_lk

后来好像又加上了。。。

Reply to lithium4010

咦~ 是么,这就不知道了

我记得我当时要做一个 Sidekiq 监控聚合,本来觉得这个有什么难的,秒秒钟的事儿。然后就发现他们把 sinatra 干掉了…干掉了……基于原生 Rack 重写了。于是我又花了几天研究 Rack 直接写应用,从此开启了一条不归路,同事要写个什么小东西,我就会跑过去丢一句:这个用什么 Rails,来跟我写 Rack 吧 😅

Reply to lithium4010

从源码上面查没查到后面把 sinatra 加上去的 PR 呀😂

,jhhj,jh,hj,

我现在使用的 sidekiq 版本是 4.1.2,在 web ui 里面是需要 Sinatra 的,等会把相关 rails,gem 的 version 添加上去

看 sidekiq github 的修改履历,4.2.0 以后就已经不依存 Sinatra 了,使用 Rack https://github.com/mperham/sidekiq/blob/822a75db12befdedaf66980a2394c62dbf9c3322/Changes.md#420

You need to Sign in before reply, if you don't have an account, please Sign up first.