2015年10月追記: Heroku の無料プランが改訂されて dyno のアイドル条件が厳しくなり、30分以上アクセスがない dyno はスリープするようになった。また24時間のうち6時間以上はスリープ状態でなければならないルールも加わった。
TL;DR: HEROKU_URL
での ping をやめて、 Uptime Robot などのモニタリングサービスを使う。 Hubot には適当に200を返すハンドラを書く。
2014年9月30日ごろから、 Heroku に置いた Hubot のプロセスが起動後しばらくしてアイドル状態に入るようになった。
元々 Heroku の無料プランでは1時間アクセスのない web dyno をアイドルするようになっている。 Hubot にはこの対策が組み込まれていて、環境変数 HEROKU_URL
をセットすると、自分に向けて定期的に HTTP リクエストを出してアイドルを防ぐようになっている。
ところが、最近になって Heroku プラットフォームに変更があったらしく、自分に向けたリクエストが Request Interrupted
なる理由で失敗するようになった。 web プロセスは失敗したリクエストに関知しないので、しばらくするとアイドル状態になってしまう。
リクエストが失敗するとおおよそ以下のようなログが出る(抜粋、一部伏せ字):
$ heroku logs
2014-10-14T06:40:15.984974+00:00 app[web.1]: [Tue Oct 14 2014 06:40:15 GMT+0000 (UTC)] INFO keep alive ping!
2014-10-14T07:00:15.980907+00:00 heroku[router]: sock=backend at=error code=H18 desc="Request Interrupted" method=POST path="/hubot/ping" host=(***).herokuapp.com request_id=(***)
ba08941 fwd="(***)" dyno=web.1 connect=0ms service=1ms status=503 bytes=140
Hubot のリポジトリにも同様の issue が報告されている:Hubot idling on Heroku after 503s · Issue #779 · github/hubot · GitHub
失敗するのは自分に向けたリクエストだけなので、 web プロセスを生かしておくには外部からリクエストを送ればよい。上記 issue には Uptime Robot を使って解決したというコメントがあった。これは無料で50サイトまでの生存確認をしてくれるサービスらしい。
Uptime Robot にアカウントを作り、 Hubot インスタンスを HTTP でモニタリングするように設定した:
モニタ先が404を返すとダウンしているとみなされるようなので(きちんと確認していないが……)、200を返すハンドラを Hubot に仕込んだ:
# Description:
# Handles GET /
module.exports = (robot) ->
robot.router.get '/', (req, res) ->
res.send 'pong'
これで Hubot が生き続けるようになった。