Clockwork Cheat Sheet

=====================

[Clockwork](https://github.com/tomykaira/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

```ruby
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

```ruby
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分に実行されます。

```ruby
every(1.day, 'job', at: '**:30') # 毎時30分では実行しない！
```

### if

ジョブを実行する条件を指定します。

```
lambda { |t| [式] } で設定します。

(式に時間が不要なら`|t|`を`|_|`に変更します。)
```

#### Example

月初や月末で指定できます。

```ruby
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](http://mperham.github.io/sidekiq/)を利用すると非同期処理の実装が簡単です。)

```ruby
every(1.minute, 'Failure::Worker', if: lambda { |_| Failure.all.count > 0 }) do 
  Failure::Worker.perform_async
end
```

## Job

実行するジョブを指定します。
(ジョブは[Sidekiq](https://github.com/tomykaira/clockwork#use-with-queueing)などを利用が必要です。)

```
every(period, [job name], options) [{job block}] で設定します。

{job block}に記述する方法と[job name]を利用してhandlerに記述する方法があります。
```

### Job block

期間、条件、ジョブをまとめて記述できます。

```ruby
every(1.second, '1.second.job') do
  puts "Running job"
end
```

### handler

期間、条件とジョブを分けて記述できます。

```ruby
handler do |job|
  case job
  when '1.second.job'
    "Running job"
  end 
end

every(1.second, '1.second.job')
```

### Example

#### Practical

`Rails`の例ですが、環境(開発や本番)に合わせて制御できます。

```ruby:clock.rb
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秒待たされます。

```ruby
every(1.second, '1.second.job') {sleep 0}
every(10.seconds, '10.seconds.job') {sleep 20}
```


# Tips

**cron**とは違い`worker`の引数にオブジェクトを指定できるところがとても便利です。
(もちろんハッシュも使えます。)

```ruby
every(1.minute, 'Time::Worker') do 
  Time::Worker.perform_async(Time.now, {foo: :bar})
end
```