Skip to content
Takashi Hayasaka edited this page Mar 30, 2014 · 1 revision

Schedulerは、アプリケーション上のジョブをスケジュールされた時間帯に実行するアドオンです。トラディショナルなサーバー環境のcronに似ています。

Schedulerはベストエフォート型のサービスです。ジョブが実行されることは予定となり、必ず実行が保証されるものではありません。Schedulerは、時々(レアなケースですが)スケジュール化されたジョブの実行をし忘れることがあります。スケジュール化されたジョブの実行がアプリケーションのクリティカルなコンポーネントとなる場合、 実行時間をカスタムしたプロセスを走らせることを推奨します。 こちらの方が、信頼性があり、制御や視覚的な操作が可能となります。

Schedulerアドオンは、one-off dynosを実行します。[one-off dynos]は、毎月チャージされるdynoの使用時間に換算されます。

ダッシュボードは、ジョブの実行をある特定の時間に、10分毎、1時間毎、1日毎に設定することが可能となります。ジョブの呼び出しが行われるとone-off dynosとして実行され、ログ上にscheduler.Xのような形式で出力されます。

Scheduler Dashboard

アドオンのインストール

Schedulerを使用するには、アドオンのインストールが必要です。:

:::term
$ heroku addons:add scheduler:standard 

Dynoのコスト

Schedulerは、毎月のdynoの使用時間に換算されるone-off dynosを実行します。Schedulerのタスクによるdynoの使用時間は、heroku runやdynoのスケールと同じ仕組みでカウントされます。Herokuからのインボイスには、"scheduler"タイプのdynoとして記載されます。

タスクの定義

タスクは、アプリケーション上で実行可能なコマンドであれば、いかなる物も定義可能です。

Railsでは、rakeタスクをセットアップすることが規約です。Railsにスケジュールされたタスクをクリエイトするには、下記のコードをlib/tasks/scheduler.rakeへコピーし、あなたのアプリケーション用にカスタマイズして下さい。

:::ruby
desc "This task is called by the Heroku scheduler add-on"
task :update_feed => :environment do
  puts "Updating feed..."
  NewsFeed.update
  puts "done."
end

task :send_reminders => :environment do
  User.send_reminders
end

その他のフレームワークや言語で作成されたアプリケーションでは、タスクとして動作するbin/配下へスクリプトを格納するのが規約となります。以下は、bin/clean-sessionsスクリプトの例です。:

:::ruby
#!/usr/bin/env ruby
require "sequel"
DB = Sequel.connect ENV["DATABASE_URL"]
puts "Cleaning old sessions..."
DB["DELETE FROM sessions WHERE last_seen_at < ?", Time.now - 24*60*60]
puts "done."

タスクのテスト

タスクを作成し、ローカルで機能していることを確認したら、次のステップは、Heroku上にアプリケーションをデプロイし、タスクのテストを行うことです。これを行うには、heroku runコマンドを使います。heroku runは、タスクをHeroku上で走らせるためのコマンドです。:

:::term
$ heroku run rake update_feed

Schedulerは、heroku runコマンドがジョブを実行するのに使用するone-off dynosと同一のdynoを使用します。そのため、heroku runコマンドが正常に動作している場合、Schedulerでも同様に正常動作することとなります。

ジョブのスケジュール

ジョブを実行する頻度と時間をスケジュールするには、My Apps上で、対象のアプリを選択し、Schedulerのダッシュボードを開けて下さい。その後、"General Info"をクリックし、アドオンのドロップダウンから"Scheduler"を選択して下さい。ダッシュボードはコマンドからも起動させることが可能です。:

:::term
$ heroku addons:open scheduler

Schedulerのダッシュボード上で、"Add Job..."をクリックして下さい。タスクを入力し、頻度、dynoサイズ (1X か 2X)、次回の実行時間を選択します。

次回の実行時間は、UTCの時間帯で入力をお願いします。ジョブを特定のローカル時間でスケジュールしたい場合は、適切なUTCのオフセットを付加して下さい。

例えば、rake update_feedというジョブを追加するとした場合、ジョブの実行を毎時30分に実行するためには、"Hourly"と":30"を選択します。また、毎日夜中にリマインダーを送るrake send_remindersというジョブを追加するとした場合、"Daily"と"00:00"を選択して下さい。

コマンドを明示する代わりにプロセスタイプを明示して下さい。コマンドはプロセスタイプと関連し、与えられたパラメータで実行されます。詳細はone-off dynosのsyntaxの項を参照して下さい。

アウトプットの検査

スケジュール化されたジョブのログは、logsscheduler.Xのプロセスとして登録されます。:

:::term
$ heroku logs --ps scheduler.1
2011-02-04T14:10:16-08:00 heroku[scheduler.1]: State changed from created to starting
2011-02-04T14:10:16-08:00 app[scheduler.1]: Starting process with command `bin/clean_sessions`
2011-02-04T14:10:19-08:00 app[scheduler.1]: Deleting stale sessions...
2011-02-04T14:10:27-08:00 app[scheduler.1]: done.
2011-02-04T14:10:28-08:00 heroku[scheduler.1]: State changed from up to complete

スケジュール化されたdynoは、heroku psコマンドで確認することが可能です。:

:::term
$ heroku ps
=== scheduler: `bin/clean_sessions`
scheduler.1: complete for 5m

=== web: `bundle exec thin start -p $PORT -e production`
web.1: idle for 3h

長時間の実行を要するジョブ

スケジュール化されたジョブは、短時間で実行されるタスクを想定しています。時間を要するタスクは、バックグラウンドのjob queueに入れられます。数分以上の時間を要するタスクを実行するには、worker dynoを使用するべきです。

ジョブの暴走を防ぐために、ジョブが頻度以上に時間を要する場合、強制的に終了されます。例えば、10分毎に実行されるジョブは、実行後、10分が経過した時点で強制終了されます。

既知の問題と代替案

Schedulerは、ベストエフォートのサービスです。ジョブがスケジュールされた時間に実行される保証はありません。全く実行されない場合もあります。Schedulerは、スケジュールされたプロセスが時折スキップされてしまう事象を既知の問題として認識しています。

HerokuのSchedulerへの代替として、実行時間をカスタムしたプロセスを実行することが考えられます。この機能は、プロセスをスケジュールする作業に、より多くの制御とビジビリティを提供します。また、スケジュール化されたジョブがクリティカルなコンポーネントである本番環境のデプロイに適しています。詳細な情報はこの記事を参照して下さい。

Clone this wiki locally