某些情況下,我們除了提供web界面給使用者,還需要運作一些背景任務。這些任務可能是由使用者觸發的(比如使用者送出了一個請求,而這種請求很特殊,例如從github克隆一個項目并執行建構,至少需要幾分鐘才能執行完成,這種情況不适合阻塞的方式讓浏覽器等待結果傳回);也可能是一些正常性的系統任務(比如将日志進行歸檔,轉移到統一的地方進行備份)。前者一般是引入消息隊列,使用者的請求隻是增加了一條待建構的消息到消息隊列,然後有一個專門的訂閱者讀取消息,排程分發執行這個任務。後者最簡單的方式便是crontab,但缺點是每個機器需要單獨進行設定,不易維護;當然也可以通過一個統一的排程器,分發任務到多個任務節點的方式來執行。
這裡我們采用的方案是有一個單獨的daemon程序,讀取消息隊列,得到前端寫入的待建構的消息,fork程序執行Ant,完成建構後(成功或失敗)将狀态寫入資料庫,前端采用定期查詢的方式以便獲知任務是否結束。這樣daemon程序的邏輯相對簡單,建構的過程都是發生在其他程序空間的,不會對daemon程序産生影響。
這裡是真正的daemon程序執行的代碼。目前的邏輯比較簡單,就是定期擷取前端寫入的待建構的消息,建立程序執行一次建構任務。
<code>_runTask()</code>其實就是調用一個新的PHP程序,執行特定的action。我們在這個action再去fork程序執行<code>Ant</code>或者<code>Gradle</code>。
這裡daemon程序處理的signal比較簡單,主要就是需要退出和需要wait子程序結束的資訊,以便OS清理其留在程序表中的資訊。但是<code>pcntl_signal_dispatch()</code>有個問題,有可能兩個接近同時退出的子程序,會導緻可能當時隻發了一個SIGCHLD的信号,另一個信号下一次dispatch才會發出,是以隻能通過循環來wait。