Rails 定时任务实现之 sidekiq+sidekiq-cron

image.png

平时的开发中总有一些需要延迟执行的程序和一些需要定时执行的程序。

延迟执行一般我们使用sidekiq,还是挺好用的,也没有什么问题,如果有更多需求可以付费购买PRO版。

定时任务之前我们一直使用sidetiq,但是sidetiq在几年前停止了支持,所以我们要找一个新的替代gem,它就是sidekiq-cron,看名字就知道是专门用来和sidekiq搭配实现定时任务的。

接下来我们就来配置异步执行(sidekiq)和定时执行(sidekiq-cron)的环境。

一、安装Gem包
首先我们先来安装 gem,修改Gemfile文件增加两个gem

Ruby
gem 'sidekiq'
gem 'sidekiq-cron'
然后执行

Bash
bundle install

二、配置 sidekiq
由于sidekiq是基于redis的,所以我们需要给sidekiq配置要使用的redis。

*如果你使用的redis和你的应用在同一台机器,那么你就可以不用配置sidekiq的redis了。

新建一个文件onfig/intializers/sidekiq.rb ,配置如下代码:

Ruby

Server

Sidekiq.configure_server do |config|
config.redis = { url: "redis://172.16.0.40:6379/15"} # 这里的redis根据自己需要修改

# 这里是配置 sidekiq-cron 的定时任务从 config/sidekiq_cron.yml 文件读取
schedule_file = 'config/sidekiq_cron.yml'
if File.exist?(schedule_file)
    Sidekiq::Cron::Job.load_from_hash YAML.load_file(schedule_file)
end

end

Client

Sidekiq.configure_client do |config|
config.redis = { url: "redis://172.16.0.40:6379/15" } # 这里的redis根据自己需要修改
end

接下来是运行时的参数配置文件
config/sidekiq.yml

Ruby

:concurrency: 5 #并发线程数
:pidfile: tmp/pids/sidekiq.pid #进程id
:logfile: log/sidekiq.log # 输出日志文件
staging:
:concurrency: 10
production:
:concurrency: 20
:queues:

  • [critical, 2] # 使用数组的形式写, 第一个参数为打开的 queue 的名称, 第二个为优先级
  • default # 写在队列参数中的, 表示让 sidekiq 处理这个 queue
  • low
    config/sidekiq_cron.yml

Ruby
my_first_work:
cron: "*/1 * * * *" # 每分钟执行一次,这里的配置方式和系统的crontab配置一样
class: "TimeKeyClubWorker"
queue: critcal # 指定要进入的队列,这会覆盖sidekiq_options中指定的queue

三、创建 Worker 类
创建worker

Ruby
rails g sikiq:worker TimeKeyClub
会生成文件 /app/workers/time_key_club_worker.rb
修改代码为如下

Ruby
class TimeKeyClubWorker
include Sidekiq::Worker
sidekiq_options queue: 'critical' #进入指定队列

def perform(*args)
# Do something
Rails.logger.info('time key club worker running !' + Time.now.strftime('%Y-%m-%d %H:%M:%S'))
end
end

四、启动 sidekiq
Bash
bundle exec sidekiq -e production -q default -d # 监控default队列
bundle exec sidekiq -e production -q critical -d # 监控critical队列
bundle exec sidekiq -e production -C config/sidekiq.yml -d # 只监控并执行sidekiq.yml中queues中的队列
启动sidekiq的代码如上,可以看到我们可以只监控并运行其中的一个队列,这样我们就可以把不同的队列跑在不同的服务器上,降低某一台服务器的压力。

启动成功之后我们就可以在日志中看到我们的worker输出的内容了 。

五、注意事项
sidekiq-cron 定时任务的运行时间并不是很精确,如上我们的定时任务,并不是很精确的每60秒执行一次。

sidekiq-cron 如果修改了名字需要运行代码删除原来的定时任务,否则会执行多个定时任务
例如:原来的配置如本文上面的sidekiq_cron.yml
现在把其中的 my_first_work 修改为 my_work ,再次启动sidekiq,我们的worker每分钟会执行两次
删除方法:

Ruby
Sidekiq::Cron::Job.destroy "my_first_work"