無料プランの Heroku Web アプリ (Web Dyno) を Sleep させないようにするには cron-job.org が良いかも

Heroku の無料プラン (Free Dyno) で使える、Web アプリを稼動させる仮想環境「Web Dyno」は、30分間その Web アプリにアクセスがないと自動的に Sleep してしまう。

Web Dyno が Sleep してしまうと、次回その Heroku アプリに初回アクセスした時に、Web Dyno が再起動してレスポンスを返すまで、15〜30秒くらい待たされてしまう。

この初回アクセス時のレスポンスの悪さを解消するために、自分が Heroku アプリを使いたくなる時間帯には、予め Web Dyno の Sleep を解除しておきたいと思った。

今回は Web Dyno を Sleep させないようにする、Sleep していたら自動的に再起動させてやるための方法を調べたので、それを紹介する。

目次

Web Dyno を Sleep させないようにするには、Heroku アプリにアクセスがあればいい

Web Dyno が Sleep するのは、30分間アクセスが一切なかった場合だ。ということは、30分以内に1回以上 Heroku アプリにアクセスがあれば、その Web Dyno は Sleep しないということだ。

Heroku アプリの URL に対してリクエストが飛ばせれば何でも良いので、ブラウザからのアクセスでなくても良くて、curl で叩くだけでも良いのだ。

ココからの問題は、24時間好きなタイミングで Heroku アプリに curl するにはどうしたらいいかということだ。Heroku の他に自分でサーバを借りたりしていれば、そこに定期的なジョブを仕込んだりもできるかもしれないし、自宅の PC を24時間つけっぱなしにしているような人であれば、そこでスクリプトを常駐させるだけでも良いだろう。

しかし今回は、24時間稼動している自分用のサーバを持っていない人向けの方法を考えてみる。

Heroku Scheduler から自身の Heroku Web アプリに curl する

前述のとおり、定期的に自アプリの URL を curl できれば良い、というのであれば、最初に思いつくのは Heroku Scheduler だろうか。

起こしておきたい Heroku プロジェクトに Heroku Scheduler をインストールし、起こしたいタイミングで

$ curl https://example-app.herokuapp.com/

といったコマンドを実行するジョブを設定する、というモノ。

Heroku プロジェクト内で完結するので導入が簡単ではあるが、Heroku Scheduler は

という設定しかできないため、タイミングの制御が難しい。

24時間つけっぱなしにしたいのであれば10分ごとに叩けば良いが、「昼休みの間だけ使いたい」というような特定の時間帯だけ curl したい場合には設定が面倒になる。作れるジョブ数に制限はないようだが、「1日ごと」の時刻指定を細かく作らないといけなさそうだ。

「30分間無アクセス」な状態を作るには、「30分間隔でのジョブ」では足りなくて、20〜25分間隔ぐらいで動作するようにしたいが、Heroku Scheduler はそのような細かな分 (minutes) の設定もできないので難儀。

自分の用途でそれに向いているなら良いのだが…。

UptimeRobot というサービスを使う

UptimeRobot というサービスは、任意の URL に対して定期的に ping を投げられるサービスだ。

実際に登録して設定してみたが、「実行間隔」を分単位でしか設定できず、「この時間帯は実行しない」といった制御ができなかった。「25分ごとにアクセス」といった定期実行はできるので、24時間稼動させっぱなしにしたい場合はコレでも良いかもしれない。

Web アプリ自身に自分へのリクエストを投げる処理を実装してしまう

24時間、自アプリを立ち上げっぱなしにしたいのであれば、Web アプリ自身に、自サイトへのリクエストを投げさせる処理を組み込む、ということも考えられる。

例えば Node.js 製のプロジェクトで、Express サーバを立ち上げているのであれば、こんな乱暴なコードを埋め込んでも良いかもしれない。

const express = require('express');
const http = require('http');

const app = express();

// サーバを起動したり (コードは省略)
app.listen(8080);

// 25分ごとに自サイトへリクエストを投げる
setInterval(() => {
  http.get('https://example-app.herokuapp.com/', (res) => {
    console.log('Keep-Alive');
  });
}, 1000 * 60 * 25);

要は Web Dyno が Sleep する前に、自身へのリクエストを自分で投げておけば、この setInterval() の処理も動き続けるだろう、ということだ。このようなスケジューリングを行うライブラリは色々存在するので、しっかり組むつもりならもう少し調べた方が良いが、原理的にはそういうことだ。

ただ、このやり方は24時間稼動させっぱなしになることが前提。Web Dyno が Sleep した時にはこのようなインターバル処理は実行されなくなるからだ。

cron-job.org を使う

最後に本命。最初に紹介した Heroku Scheduler は柔軟性がなかったのがデメリットだったワケだが、であれば cron が組めるウェブサービスがないかと思い探したところ、cron-job.org というサイトがあった。

このサイトに登録すると、指定の URL にアクセスする cron ジョブをウェブ上で組める。

ユーザ定義で実行タイミングを設定しようとすると、日・曜日・月・時・分を細かく指定できる。この時、「何も選択していない項目」があると、いずれの条件にも合致せず一生実行されないジョブになってしまうので注意。「曜日に関わらず0時15分に…」と設定する時は、日・曜日・月の各項目を全選択することで、cron における * のような表現になる。

指定する時刻のタイムゾーンだが、ユーザ設定画面で指定したタイムゾーンに則って設定できるため、ユーザ設定で「Asia/Tokyo」を選んであれば、日本時間 (JST) の感覚のままで「9時」「17時」などと設定できる。

設定が上手くいっていると、ジョブ一覧画面で「次回の実行予定時刻」が表示される他、実行結果ログも後で見られたりする。

以上

cron-job.org なら、「昼間だけ」「夕方だけ」Heroku アプリを Sleep させないでおく、といった細かな設定も柔軟にできる。

自分は cron-job.org に3つのジョブを作り、好みの時間帯に20分間隔で ping を飛ばすように設定した。コレで、通勤と昼休みの間だけ、自分の Heroku アプリを Sleep させないでおいて、スムーズにアクセスできるように設定できた。