=====================
Clockworkは定期的な処理が簡単に実装できるライブラリです。
使い方も簡単ですが、せっかくなのでチートシートを作りました。
Clockworkはcronの代替に使えます。RubyなのでDSL記法や便利な関数が使えます。
(Railsで利用するとActionPackなど更に便利なライブラリが使えます。)
Register
定期的に処理する内容をevery
に記述します。
every
は期間、処理(ジョブ)、条件を指定します。
every([period], [job name], [options]) [{job block}]
Period
ジョブを実行する期間(間隔)を指定します。
期間の単位は秒
、分
、時
、日
、週
です。
[数字].[単位のキーワード]で設定します。
キーワードの単数形と複数形はエイリアスです。
(数字が1なら単数形、2以上なら複数形を使うとよいです。)
List
単位 | 単数形 | 複数形 | Source |
---|---|---|---|
秒 | second | seconds | period * 1 |
分 | minute | minutes | period * 60 |
時 | hour | hours | period * 3600 |
日 | day | days | period * 86400 |
週 | week | weeks | period * 604800 |
Example
every(4.seconds, '4.seconds.job') # 4秒間隔
every(2.hours, '2.hours.job') # 2時間間隔
every(1.day, '1.day.job') # 1日間隔
Options
ジョブを実行する条件を指定します。
条件にはat
とif
があります。
at
何時にジョブを実行するか指定します。
'[時]:[分]' で設定します。
(時間は複数の指定ができます。また、曜日を指定できます。)
List
指定 | period | at | 処理される時間 |
---|---|---|---|
時分 | 1.day | '01:30' | 1時30分 |
0省略 | 1.day | '1:30' | 1時30分 |
毎時 | 1.hour | '**:30' | 毎時30分 |
複数 | 1.hour | ['12:00', '18:00'] | 12時と18時 |
曜日 | 1.week | 'Saturday 12:00' | 土曜日の12時 |
Week day list
曜日は省略を合わせると4パターンあります。
エイリアスなので好きなキーワードを使えます。
曜日 | 指定1 | 指定2 | 指定3 | 指定4 |
---|---|---|---|---|
日 | sunday | Sunday | sun | Sun |
月 | monday | Monday | mon | Mon |
火 | tuesday | Tuesday | tue | Tue |
水 | wednesday | Wednesday | wed | Wed |
木 | thursday | Thursday | thu | Thu |
金 | friday | Friday | fri | Fri |
土 | saturday | Saturday | sat | Sat |
Example
every(1.day, 'job', at: '01:30') # 1時30分
every(1.day, 'job', at: '1:30') # 1時30分
every(1.hour, 'job', at: '**:30') # 毎時30分
every(1.hour, 'job', at: ['12:00', '18:00']) # 12時と18時
every(1.week, 'job', at: 'Saturday 12:00') # 土曜日の12時
Anti-pattern
period
とat
の組合せに注意が必要です。
例では毎時30分の指定ですが期間が1日間隔なので、Clockworkが12時にスタートすると
初回は12時30分に実行されて、次回は翌日の12時30分に実行されます。
every(1.day, 'job', at: '**:30') # 毎時30分では実行しない!
if
ジョブを実行する条件を指定します。
lambda { |t| [式] } で設定します。
(式に時間が不要なら`|t|`を`|_|`に変更します。)
Example
月初や月末で指定できます。
every(1.day, 'job', at: '9:00', if: lambda { |t| t.day == 1 }) # 月初の9時
every(1.day, 'job', at: '21:00', if: lambda { |t| t.day == Date.new(t.year, t.month, -1).day }) # 月末の21時
Practical
処理の失敗をモニタリングしてアラートを通知することが簡単に実装できます。
(Sidekiqを利用すると非同期処理の実装が簡単です。)
every(1.minute, 'Failure::Worker', if: lambda { |_| Failure.all.count > 0 }) do
Failure::Worker.perform_async
end
Job
実行するジョブを指定します。
(ジョブはSidekiqなどを利用が必要です。)
every(period, [job name], options) [{job block}] で設定します。
{job block}に記述する方法と[job name]を利用してhandlerに記述する方法があります。
Job block
期間、条件、ジョブをまとめて記述できます。
every(1.second, '1.second.job') do
puts "Running job"
end
handler
期間、条件とジョブを分けて記述できます。
handler do |job|
case job
when '1.second.job'
"Running job"
end
end
every(1.second, '1.second.job')
Example
Practical
Rails
の例ですが、環境(開発や本番)に合わせて制御できます。
require_relative '../config/boot'
require_relative '../config/environment'
require 'clockwork'
include Clockwork
case Rails.env
when 'development'
every(1.second, 'seconds.job') do
puts "Running development job"
end
when 'staging'
every(1.minute, 'minutes.job') do
puts "Running staging job"
end
when 'production'
every(1.hour, 'hours.job') do
puts "Running staging job"
end
else # Unknown
every(1.day, 'days.job') do
puts "Running production job"
end
end
# Shared jobs
every(1.week, 'weeks.job') do
puts "Running common job"
end
Anti-pattern
Rubyはマルチスレッドの処理をしないとジョブが期待した時間に実行されません。
例では1秒間隔と10秒間隔のジョブを実行します。しかし、10秒間隔のジョブで
20秒の待ちが発生するので1秒間隔のジョブも20秒待たされます。
every(1.second, '1.second.job') {sleep 0}
every(10.seconds, '10.seconds.job') {sleep 20}
Tips
cronとは違いworker
の引数にオブジェクトを指定できるところがとても便利です。
(もちろんハッシュも使えます。)
every(1.minute, 'Time::Worker') do
Time::Worker.perform_async(Time.now, {foo: :bar})
end