rufus-scheduler,ジョブのスケジューリングをシンプルに行える。
類似のところでwheneverというgemがあるが,そちらではcronで実行するジョブをわかりやすいrubyシンタックスで記述できcronに反映させるが,rufus-schedulerはシンプルなスレッドとして実装されている。cronというメソッドもあるが,cronには影響しない。
シンプルなスレッドの実装であり,プロセスが終了するとschedulerも終了するので,バックグラウンドで動かすにはデーモン化する。試しにこんな感じで書いてみる。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 |
require 'rufus-scheduler' begin puts "daemonize..." Process.daemon end if ARGV.include?("--daemon") scheduler = Rufus::Scheduler.new( lockfile: "/tmp/rufus-scheduler.pid", ) puts "#{scheduler.started_at} start scheduler" Signal.trap(:INT) do |signo| puts "just get a signal #{signo}, so shutdown now..." scheduler.shutdown :wait puts "ok" exit end # in job = scheduler.in '5s', :job => true do |job, time| puts "#{Time.now}, #{time} schedule in" end puts job # at scheduler.at '2015/07/11 02:10:00' do |job, time| puts "#{Time.now}, #{time} schedule at" end # every scheduler.every '5s', :overlap => true, :myarg => 'myarg' do |job, time| job[:counter] = if job[:counter].nil? 1 else job[:counter] + 1 end puts "#{Time.now}, #{time} schedule every, #{job[:counter]}, opts: #{job.opts}" if job[:counter] >= 5 puts "#{Time.now}, #{time} stop schedule every" puts "mean work time: #{job.mean_work_time}" job.unschedule end sleep 6 puts "#{Time.now} schedule every done" end # interval scheduler.interval '5s' do |job, time| puts "#{Time.now}, #{time} schedule interval" sleep 6 puts "#{Time.now} schedule interval done" end # per 1 minute scheduler.cron "*/1 * * * *", :timeout => '10s' do |job, time| puts "#{Time.now}, #{time} schedule cron" begin sleep 15 rescue Rufus::Scheduler::TimeoutError puts "#{Time.now}, #{time} timeout #{job}" end end scheduler.every '60s', :overlap => false, :tag => :impala do |job, time| #require 'impala' #Impala.connect('impala_host', 21000) do |conn| # conn.execute('refresh access_log') #end puts "#{Time.now}, #{time} refresh access_log" sleep 2 end scheduler.jobs(:tag => :impala).each {|job| puts "#{job.id} #{job.opts}" } scheduler.join |
実行すると以下のようになる。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
$ bundle exec ruby rufus-scheduler-sample.rb 2015-07-12 00:09:15 +0900 start scheduler #<Rufus::Scheduler::InJob:0x007ff55190ec70> every_1436627355.0505002_383478777958208319 {:overlap=>false, :tag=>:impala} 2015-07-12 00:09:15 +0900, 2015-07-12 00:09:15 +0900 schedule at 2015-07-12 00:09:20 +0900, 2015-07-12 00:09:20 +0900 schedule in 2015-07-12 00:09:20 +0900, 2015-07-12 00:09:20 +0900 schedule every, 1, opts: {:overlap=>true, :myarg=>"myarg"} 2015-07-12 00:09:20 +0900, 2015-07-12 00:09:20 +0900 schedule interval 2015-07-12 00:09:25 +0900, 2015-07-12 00:09:25 +0900 schedule every, 2, opts: {:overlap=>true, :myarg=>"myarg"} 2015-07-12 00:09:26 +0900 schedule interval done 2015-07-12 00:09:26 +0900 schedule every done 2015-07-12 00:09:30 +0900, 2015-07-12 00:09:30 +0900 schedule every, 3, opts: {:overlap=>true, :myarg=>"myarg"} 2015-07-12 00:09:31 +0900 schedule every done 2015-07-12 00:09:31 +0900, 2015-07-12 00:09:31 +0900 schedule interval 2015-07-12 00:09:35 +0900, 2015-07-12 00:09:35 +0900 schedule every, 4, opts: {:overlap=>true, :myarg=>"myarg"} 2015-07-12 00:09:36 +0900 schedule every done 2015-07-12 00:09:37 +0900 schedule interval done 2015-07-12 00:09:40 +0900, 2015-07-12 00:09:40 +0900 schedule every, 5, opts: {:overlap=>true, :myarg=>"myarg"} 2015-07-12 00:09:40 +0900, 2015-07-12 00:09:40 +0900 stop schedule every mean work time: 4.50305275 2015-07-12 00:09:41 +0900 schedule every done 2015-07-12 00:09:42 +0900, 2015-07-12 00:09:42 +0900 schedule interval 2015-07-12 00:09:46 +0900 schedule every done 2015-07-12 00:09:48 +0900 schedule interval done 2015-07-12 00:09:53 +0900, 2015-07-12 00:09:53 +0900 schedule interval 2015-07-12 00:09:59 +0900 schedule interval done 2015-07-12 00:10:00 +0900, 2015-07-12 00:10:00 +0900 schedule cron 2015-07-12 00:10:05 +0900, 2015-07-12 00:10:05 +0900 schedule interval 2015-07-12 00:10:10 +0900, 2015-07-12 00:10:00 +0900 timeout #<Rufus::Scheduler::CronJob:0x007ff551357a48> 2015-07-12 00:10:11 +0900 schedule interval done 2015-07-12 00:10:15 +0900, 2015-07-12 00:10:15 +0900 refresh access_log 2015-07-12 00:10:16 +0900, 2015-07-12 00:10:16 +0900 schedule interval ^Cjust get a signal 2, so shutdown now... ok |
lockfileの中身。
1 2 |
$ cat /tmp/rufus-scheduler.pid pid: 47122, scheduler.object_id: 70345803096920, time: 2015-07-12 00:09:15 +0900, timestamp: 1436627355.0475981 |
バックグラウンドで実行。
1 |
$ bundle exec ruby rufus-scheduler-sample.rb --daemon |
in, atは,非repeatableなジョブ。repeatableなジョブは,everyやinterval,cronになる。
everyとintervalの違いは,everyはジョブの開始時間を起点にスケジュールし,intervalはジョブ終了時間から次の開始時間までの間隔でスケジュールする(jobs.rbより)。
mutexを使って関連するジョブの制御もできる。
1 2 3 4 5 6 7 8 9 10 11 12 |
require 'rufus-scheduler' scheduler = Rufus::Scheduler.new puts "#{scheduler.started_at} start scheduler" $mutex = Mutex.new scheduler.every '5s', :mutex => $mutex do |job, time| puts "#{Time.now}, #{time} every 5s" end scheduler.interval '3s', :mutex => $mutex do |job, time| puts "#{Time.now}, #{time} interval 3s" sleep 5 end scheduler.join |
実行すると以下。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
2015-07-12 00:12:33 +0900 start scheduler 2015-07-12 00:12:36 +0900, 2015-07-12 00:12:36 +0900 interval 3s 2015-07-12 00:12:41 +0900, 2015-07-12 00:12:38 +0900 every 5s 2015-07-12 00:12:43 +0900, 2015-07-12 00:12:43 +0900 every 5s 2015-07-12 00:12:44 +0900, 2015-07-12 00:12:44 +0900 interval 3s 2015-07-12 00:12:49 +0900, 2015-07-12 00:12:48 +0900 every 5s 2015-07-12 00:12:52 +0900, 2015-07-12 00:12:52 +0900 interval 3s 2015-07-12 00:12:57 +0900, 2015-07-12 00:12:53 +0900 every 5s 2015-07-12 00:12:58 +0900, 2015-07-12 00:12:58 +0900 every 5s 2015-07-12 00:13:00 +0900, 2015-07-12 00:13:00 +0900 interval 3s 2015-07-12 00:13:05 +0900, 2015-07-12 00:13:03 +0900 every 5s 2015-07-12 00:13:08 +0900, 2015-07-12 00:13:08 +0900 interval 3s 2015-07-12 00:13:13 +0900, 2015-07-12 00:13:09 +0900 every 5s 2015-07-12 00:13:14 +0900, 2015-07-12 00:13:14 +0900 every 5s 2015-07-12 00:13:16 +0900, 2015-07-12 00:13:16 +0900 interval 3s 2015-07-12 00:13:21 +0900, 2015-07-12 00:13:19 +0900 every 5s 2015-07-12 00:13:24 +0900, 2015-07-12 00:13:24 +0900 every 5s 2015-07-12 00:13:25 +0900, 2015-07-12 00:13:25 +0900 interval 3s ^C |
他にも,色々とオプションがある(以下のREADMEを参照)
参考:jmettraux/rufus-scheduler · GitHub
- 追記 2015-7-25
rakeと合わせると使いやすいかもしれない。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
require "thor" require "rufus-scheduler" require "rake" task :hello do |t| t.reenable puts "#{Time.now}" end class TaskRunner < Thor desc "exec TASK", "run tasks" def exec(task) Rake.application[task].invoke end desc "start_scheduler", "run a job scheduler" def start_scheduler STDOUT.puts "==> start scheduler" scheduler = Rufus::Scheduler.new scheduler.interval "5s" do Rake.application["hello"].invoke end STDOUT.puts "waiting..." scheduler.join end end TaskRunner.start(ARGV) |
コメント