Rails Whenever 每 20 秒执行任务

liurui12w · 2018年05月03日 · 最后由 davidqhr 回复于 2018年05月25日 · 2851 次阅读

针对 whenever 每 20 秒走一波任务的需求 利用 rake 任务 首先在 rake 里写好自己想要 20 秒一次的执行的任务 之后再 利用 whenever 的 config/schedule.rb 写一个每分钟执行一次

本狗子第一次发还望各位大佬 多多指教(新手) 有更好的方法 还望指点 以上就是我目前的解决方法

lithium4010 回复

能指点一下不足吗 我目前也就只能想到这样的法子

timers

利用 current-ruby 的 Concurrent::ScheduledTask,activejob 的 async_adapter 用的就是这个。

jruby 的话,有 TimerTask

不过我没做过测试,不知道这些解决方案的精准度、容错之类的怎么样。

yfractal 回复

感谢 有机会我试试

20s 这种频率的话,我觉得就不一定要用 whenever 了,频率太高用它反而是一种消耗(每次都要初始化环境)

建议直接用 jmettraux/rufus-scheduler,注意不要在 console 里面加载这个就好了

参见 https://github.com/jmettraux/rufus-scheduler#so-rails

还有一个挺有意思的 gem

https://github.com/nickelser/zhong 中文名大概叫『钟』吧,它依赖了一个 gem 叫 suo 『锁』

他的特点是用了 redis 做执行记录和分布式情况下避免多节点执行,非常有特色的命名方式

要知道,这个作者是个地道的老外

可以用sidekiq-scheduler,是结合了上面的rufus-schedulersidekiq,还在sidekiq的后台管理页面里面集成了循环定时任务的管理

xxx 那里 做一个异步处理 交给 active_job 处理

或者就像 @w7938940 同学说的那样 用 sidekiq-scheduler

IChou 回复

😊 感谢

w7938940 回复

我大概理解您的意思 我也差不多顺着您的思路 做了一遍 我写了一个每分钟执行一次 然后我又在 job 里写了简单的 10 秒一次执行三次 后面我用 sidekiq 执行这个任务

是这个意思吗

liurui12w 回复

sidekiq-scheduler 就不需要 whenever

app/schedulers/product_scheduler.rb

require 'sidekiq-scheduler'

class ProductScheduler
  include Sidekiq::Worker

  def perform
    puts 'Hello world'
  end
end

config/sidekiq.yml

.
.
.
:schedule:
  ProductScheduler:
    every: '1m'
w7938940 回复

ok 谢谢前辈

Product.ceshi 很有灵性 哈哈。纯吐槽。不要在意

dearest 回复

随便皮一下 嘿嘿 谢谢指教 以后不这样搞了

了解一下 daemons,写一个文件,然后在文件里 sleep 20

loop do
  # code goes here
  sleep 20
end
xiaok 回复

😊 谢谢指教

xiaok 回复

那这样执行时间也算在里面了。极端条件下比如执行时间是 10s 那么这个脚本就变成 30s 一次了

sidekiq-cron 也是个选择

xiaok 回复

『一新呀 你可长点心吧』 突然就想到了这句话,别打我,哈哈哈哈~~~

另外建议用 sidekiq 的同学,有考虑过 LZ 的项目还没有使用 sidekiq 的情况么

如果没有,那么就为了一个 20s 循环任务引入一个 sidekiq + 定时插件,感觉亏亏的

用 daemons 倒是别出心裁,即方便控制,有能保证不因意外死掉,至于执行时间的问题,new 一个新线程就好了 /机智

楼上说的 daemon 应该不是用 daemon process 作为执行任务单元吧,只是一种思路,应该是可行的。

yfractal 回复

再提供个思路,用 Concurrent::TimerTask,actioncable 用的是这个。 ActionCable::Channel::PeriodicTimers 提供了 periodically :transmit_progress, every: 5.seconds 这样的语法糖。

直接起个进程,死循环 + sleep。

需要 登录 后方可回复, 如果你还没有账号请 注册新账号