概要
HTTPリクエストとは関係なく処理を行ないたいときに、非同期ジョブ機能がある。(もちろんHTTPリクエストをトリガにして実行することもできる)
準備
play.jobs.job
クラスを継承したクラスを用意する。(javaのバージョンが許せば無名クラスでも構わない)
public void doJob()
メソッドを実装し、行ないたい処理を書く。
処理結果をTクラスで返したいときは、play.jobs.job<T>
を継承し、public T doJobWithResult()
メソッドを実装する。
実行する
すぐに実行
インスタンスを生成し、now()
, in()
, afterRequest()
のいずれかのメソッドを実行する。
now()
は、即時実行。in(int)
は、遅延実行。秒で指定する。in(String)
も、遅延実行。こちらは@Every
と同じ書式。afterRequest()
は、HTTPリクエスト中に意味を持つ。現在実行中のアクションが終了してから実行する。
例えば、JPAでsave()
、コミット後にジョブを実行したいときに有効。(play1.3から実装された)
run
メソッドというのも存在するが使用してはいけない。面倒でもnow()
メソッドを使うこと。
いずれのメソッドも、Promise
オブジェクトを戻り値に持つので、play.mvc.Controller.await(int)
を用いてジョブの終了まで、リクエストをサスペンド状態にすることができる。サスペンド状態にすると、コネクションが解放されるので、次のリクエストを処理することができる。
応答に長時間かかるリクエストであっても、コネクションを占有しないで済むとされる。
実行完了まで待つ方法
Promise job = new MyJob().now();
job.get();
job.get()
でジョブ終了まで待つ。Promise<V>
だったら、V
が返却される。
アプリケーション開始時に実行
ジョブクラスに対し、@OnApplicationStart
アノテーションを付与すると、アプリケーション開始時にジョブが実行される。処理結果は残らない。
アノテーションのasync
プロパティはデフォルトはfalse
になっている。async=false
の場合、ジョブ処理が終了するまでアプリケーションは開始しない。
逆に、async=true
に設定すると、バックグラウンドで動作する。
細かいこと
afterApplicationStart()
イベント内より実行される。- 起動時にインスタンスが一度だけ生成され、スケジュール管理に残り続けるので勝手に消滅しない。
- DEVモードでは最初のリクエストを受けたときに実行。
- PRODモードではサービス起動時に実行。
アプリケーション終了時に実行
ジョブクラスに対し、@OnApplicationStop
アノテーションを付与すると、アプリケーション終了時に実行される。play.Play.stop()
が実行されたときなので必ず実行されるとは限らない。
onApplicationStop()
イベント内より実行される。
インスタンスは終了時に生成される。
一定間隔で実行
ジョブクラスに対し、@Every
アノテーションを付与すると、引数に指定した間隔でジョブが実行される。
単位 | 接尾辞 | 例(意味) |
---|---|---|
日 | d | 3d (3日ごと) |
時間 | h | 1h (1時間ごと) |
分 | mn | 5mn (5分ごと) |
秒 | s | 15s (15秒ごと) |
引数に上記の間隔文字列ではなく、”cron.hoge
” と指定すると、application.conf [cron.hoge]
に設定した値を参照する。”never”とすると周期実行されないので、アプリケーションIDによって動作のON/OFFを分けることができる。
@Every("cron.hoge")
public class MyJob extends Job { ...
# %prodの時だけ実行する
cron.hoge=never
%prod.cron.hoge=3h
インスタンスは起動時に一度だけ生成され、アプリケーション実行中はずっと残りつづける。
定時に実行
ジョブクラスに対し、@On
アノテーションを付与すると、引数に指定した時間に実行される。引数はcron書式に準拠する。
day-of-week
と a day-of-month
については未実装なのでサポートされない。
例えば、@On("0 0 16 * * MON-FRI")
のような設定をするとエラーになる。@On("0 0 16 * * ?")
ならOK。
@Every
と同じく、”cron.hoge
” のように指定すると、application.conf [cron.hoge]
の設定を参照する。””空文字のときは定期実行されないので、アプリケーションIDによって動作のON/OFFを分けることができる。
@On("cron.hoge")
public class MyJob extends Job { ...
# %prodのときだけ実行する
cron.hoge=
%prod.cron.hoge=0 0 16 * * ?
おまけ
インスタンスは起動時に一度だけ生成され、アプリケーション実行中はずっと残りつづける。
定期ジョブの実行は、java.util.concurrent.ScheduledThreadPoolExecutor
クラスで実現している。
sardineの日記 – scheduleAtFixedRate() の正確さ ここの情報をみると、あまり時刻に正確さを期待してはいけないのかもしれない。
いずれの方法でのジョブ実行もplay.jobs.Job.call()
からの呼出となる。
そこでは、before
, filter
, after
といった処理が適宜呼び出されるようになっている。DBへのトランザクション開始もfilter
内で解決されているようだ。
自前でトランザクション管理する際は、ジョブを記述しているクラスに対して@NoTransaction
アノテーションを付ける。
@NoTransaction
public class MyJob extends Job { ...