Heroku で cron 処理をする gem を作ってみた時の知見

IRKitly を作った時の知見です。
Heroku の無料プランで cron 処理をするには Heroku Scheduler を使うのが一般的です。
しかし、Heroku Scheduler では分単位で指定することはできません。

ChronoCross

この問題を解決するために Chrono という gem をラップした ChronoCross という gem を作りました。
スレッドを立てて、指定した時間まで sleep することで cron 処理を実現しています。
ChronoCross の gem の中で、Chrono::Trigger を参照しているのが最大の見所です。

問題点

この gem は一見するとうまく動くように見えますが、以下の2つの問題があることがわかりました。

  1. Heroku の Web プロセスは一定時間アクセスが無いと、プロセスごと落とされてスレッドが止まる
  2. Heroku は一日一回必ず再起動するので、スレッドを復元しなければならない

1つ目の問題に対しては、New Relic APM | Heroku Dev Center を使って、ping を飛ばし続ける定番の方法で回避しました。

2つ目の問題に対しては、config/initializers に、「DB を select してジョブを登録するスクリプト」を追加することで回避しました。
IRKitly のコード が参考になるかもしれません。

このように Heroku で使うには少しクセがある gem ですが、なんといっても Heroku の Web プロセス 1 dyno で済むのが最大の特長となっています。

その他の方法

sidekiq-cron を使う方法もあるようです。
無料プランで使う場合には、sidekiq プロセスだけで dyno を動かす必要があります。

Unicorn の before_fork に入れる方法もあるようですが、おそらく Web プロセスを寝かさないようにする必要がありそうです。

まとめ

Heroku でも cron 処理をしよう!