09.異步Jobs
因爲play是一個web應用程序,因此許多應用程序邏輯都是由控制器返回給http請求的。
但有些時候,我們需要在http請求外執行一些應用邏輯。比如非常有用的初始化任務,維護任務或運行不能被http請求池中斷的長時運行的任務等等。
Jobs可以被框架全面進行管理。意思是play負責管理所有的數據庫連接原料stuff,JPA實體管理器負責管理數據同步和事務管理。要想創建一個job,只需要繼承play.jobs.Job即可。
package jobs;
import play.jobs.*;
public class MyJob extends Job {
public voiddoJob() {
//在這兒執行某些邏輯
}
}
有些時候需要任務返回結果,這時就需要重載doJobWithResult()方法。
package jobs;
import play.jobs.*;
public class MyJob extends Job<String> {
public String doJobWithResult() {
//在這兒執行某些邏輯
returnresult;
}
}
本示例僅使用了String作爲返回類型,當然可以返回任何對象類型。
引導程序任務會在play應用啓動時執行。要想實現該任務,只需要在你的任務上添加@OnApplicationStart註釋:
importplay.jobs.*;
@OnApplicationStart
public classBootstrap extends Job {
public void doJob() {
if(Page.count() == 0) {
new Page("root").save();
Logger.info("A root page hasbeen created.");
}
}
}
注意:在這裏不需要返回結果,即使這樣做了,結果也會丟失。
默認情況下,所有標識爲@OnApplicationStart的任務都將以隊列方式執行。當所有的job執行結束後,應用程序才正式啓動並開始處理請求。
如果你打算讓你的任務在應用程序啓動時執行,但你又想立即管理進行請求處理,那麼可以使用@OnApplicationStart(async=true)註釋。然後,你的job將在後臺啓動。
警告!
當運行於DEV模式時,應用程序將在第一個請求到達時才啓動。此外,在DEV模式時,在需要的時候,應用程序會自動重啓。
當運行於PROD模式時,應用程序將和服務器一起同步啓動。
預定義任務由框架週期性執行。你可以使用@Every註釋要求play在一個特定的週期內運行job。
importplay.jobs.*;
@Every("1h")
public classBootstrap extends Job {
public void doJob() {
List<User> newUsers =User.find("newAccount = true").fetch();
for(User user : newUsers) {
Notifier.sayWelcome(user);
}
}
}
如果@Every註釋還不足以滿足需要,你可使用帶有CRON表達式的@On註釋來運行你的job。
importplay.jobs.*;
/** Fire at 12pm(noon) every day **/
@On("0 0 12 ** ?")
public classBootstrap extends Job {
public void doJob() {
Logger.info("Maintenance job...");
...
}
}
小建議
我們是使用Quartzlibrary來解析CRON表達式的。
你不能返回結果,即使這樣做了,結果也會被丟棄。
觸發任務job
調用Job實例的now()方法可以在任何時候觸發job來執行一段特定的任務。這個時候,job將以非阻塞方式立即執行。
public static voidencodeVideo(Long videoId) {
new VideoEncoder(videoId).now();
renderText("Encoding started");
}
調用job的now()方法以返回一個Promise值。
停止應用程序
使用@OnApplicationStop註釋可以在應用程序關閉時執行某些操作。
import play.jobs.*;
@OnApplicationStop
public class Bootstrap extends Job {
public voiddoJob() {
Fixture.deleteAll();
}
}