W3Cschool
恭喜您成為首批注冊用戶
獲得88經(jīng)驗(yàn)值獎(jiǎng)勵(lì)
計(jì)算機(jī)科學(xué)中的任何問題都可以用另外的間接層解決,但是這通常會引發(fā)另一個(gè)問題。 -- David Wheeler
在 [1.31]-新型計(jì)劃任務(wù):以接口形式實(shí)現(xiàn)的計(jì)劃任務(wù) 一章中,我們討論了PhalApi中對計(jì)劃任務(wù)的設(shè)計(jì)和底層實(shí)現(xiàn)。
但對于很多應(yīng)用,很多項(xiàng)目,或者很多同學(xué)來說,仍然比較廣泛,不能直接使用。
這一章則專門為此而進(jìn)行演進(jìn),并提供最終可用的計(jì)劃任務(wù)調(diào)度,同時(shí)我們也會闡明如何進(jìn)行擴(kuò)展定制。
也就是說,這一章將提供Task擴(kuò)展類庫的統(tǒng)一調(diào)度方式,以便在啟動crontab任務(wù)后,可以通過數(shù)據(jù)庫簡單配置,即可執(zhí)行各種任務(wù)。
出于對業(yè)務(wù)的考慮,我們首先需要明確此crontab調(diào)度方式所支持的功能,它應(yīng)該包括但不限于:
在原來的時(shí)序圖基礎(chǔ)上,我們可以進(jìn)行演進(jìn)的設(shè)計(jì),追加了統(tǒng)一的調(diào)度后如下所示:
通過上面詳細(xì)的時(shí)序圖,我們可以發(fā)現(xiàn)里面的設(shè)計(jì)是出于這樣的分層考慮:
序號 | 層 | 關(guān)鍵操作 | 說明 | 如何使用 |
---|---|---|---|---|
1 | 啟動腳本 | crontab.php | 操作crontab執(zhí)行的腳本 | 客戶端可以進(jìn)行必要的初始化工作 |
2 | 進(jìn)程級 | Task_Progress::run() | 根據(jù)進(jìn)程配置的數(shù)據(jù)庫表,進(jìn)行循環(huán)調(diào)度 | 不需要改動,直接使用 |
3 | 觸發(fā)器 | Task_Trigger::fire() | 進(jìn)行計(jì)劃任務(wù)調(diào)度的上下文環(huán)境,用于指定runner和mq類型 | 客戶端也可進(jìn)行定制擴(kuò)展,進(jìn)行必要的操作 |
4 | MQ消費(fèi)與調(diào)度 | Task_MQ::pop()和Task_Runner::go() | 不斷消費(fèi)MQ隊(duì)列,并依次進(jìn)行調(diào)度 | 不需要改動,直接使用,也可擴(kuò)展 |
5 | 計(jì)劃任務(wù)服務(wù) | PhalApi_Api::doSth() | 執(zhí)行計(jì)劃任務(wù)服務(wù) | 由客戶端按接口形式實(shí)現(xiàn) |
雖然上面的層級,初看起來有點(diǎn)多,但我們再次驗(yàn)證了計(jì)算機(jī)那個(gè)偉大的定論:計(jì)算機(jī)的任何問題都可以通過一個(gè)中間層來解決。
由此看出,上面的層級其實(shí)相當(dāng)于:
客戶端初始化 --> 直接使用 --> 自由組合與操作 --> 直接使用 --> 任務(wù)服務(wù)實(shí)現(xiàn)
CREATE TABLE `phalapi_task_progress` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`title` varchar(200) DEFAULT '' COMMENT '任務(wù)標(biāo)題',
`trigger_class` varchar(50) DEFAULT '' COMMENT '觸發(fā)器類名',
`fire_params` varchar(255) DEFAULT '' COMMENT '需要傳遞的參數(shù),格式自定',
`interval_time` int(11) DEFAULT '0' COMMENT '執(zhí)行間隔,單位:秒',
`enable` tinyint(1) DEFAULT '1' COMMENT '是否啟動,1啟動,0禁止',
`result` varchar(255) DEFAULT '' COMMENT '運(yùn)行的結(jié)果,以json格式保存',
`state` tinyint(1) DEFAULT '0' COMMENT '進(jìn)程狀態(tài),0空閑,1運(yùn)行中,-1異常退出',
`last_fire_time` int(11) DEFAULT '0' COMMENT '上一次運(yùn)行時(shí)間',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;
對此表的關(guān)鍵字段說明如下:
字段 | 說明 | 示例 |
---|---|---|
trigger_class | 觸發(fā)器的類名 | 須實(shí)現(xiàn)Task_Progress_Trigger::fire($params)接口 |
fire_params | 觸發(fā)器的參數(shù) | 加傳給Task_Progress_Trigger::fire()函數(shù)的參數(shù),格式為:service&MQ類名&runner類名 |
interval_time | 執(zhí)行間隔 | 單位為秒 |
enable | 是否啟動 | 此字段禁止時(shí),將不再執(zhí)行 |
state | 進(jìn)程狀態(tài) | 當(dāng)此狀態(tài)一直為異常或者運(yùn)行且超過1天時(shí),系統(tǒng)會進(jìn)行修復(fù),即重置為空閑狀態(tài) |
其中,對于fire_params參數(shù),MQ類名和runner類名可選,以下是一些示例:
//示例1:完整的配置
//fire_params=Task_Demo.DoSth&Task_MQ_DB&Task_Runner_Local
$mq = new Task_MQ_DB();
$runner = new Task_Runner_Local($mq);
$runner->go('Task_Demo.DoSth');
//示例2:使用默認(rèn)的Runner
//fire_params=Task_Demo.DoSth&Task_MQ_DB
$mq = new Task_MQ_DB();
$runner = new Task_Runner_Local($mq); //默認(rèn)使用本地Runner
$runner->go('Task_Demo.DoSth');
//示例3:使用默認(rèn)的MQ和默認(rèn)的Runner
//fire_params=Task_Demo.DoSth
$mq = new Task_MQ_Redis(); //默認(rèn)使用redis的MQ
$runner = new Task_Runner_Local($mq); //默認(rèn)使用本地Runner
$runner->go('Task_Demo.DoSth');
//示例4:使用自定義的MQ和Runner
//fire_params=Task_Demo.DoSth&My_MQ&My_Runner
class My_MQ implements Task_MQ {
// ...
}
class My_Runner extends Task_Runner {
// ...
}
$mq = new My_MQ();
$runner = new My_Runner($mq);
$runner->go('Task_Demo.DoSth');
最終的效果就是,我們通過這樣兩行簡單的代碼,即可實(shí)現(xiàn)一系列復(fù)雜的任務(wù)調(diào)度:
$progress = new Task_Progress();
$progress->run();
讓我們來看下這樣設(shè)計(jì)的運(yùn)行效果吧!看下這兩行代碼背后所產(chǎn)生的魔力。
首先,我們先添加兩條計(jì)劃任務(wù):
INSERT INTO `phalapi_task_progress` VALUES ('1', 'test demo', 'Task_Progress_Trigger_Common', 'Task_Demo.DoSth&Task_MQ_File&Task_Runner_Local', '300', '1', '', '0', '0');
INSERT INTO `phalapi_task_progress` VALUES ('2', 'test ok', 'Task_Progress_Trigger_Common', 'Default.Index&Task_MQ_DB&Task_Runner_Local', '100', '1', '', '0', '0');
然后,偽造一些MQ:
INSERT INTO `phalapi_task_mq_0` VALUES ('8', 'Default.Index', '', '0', '');
最后,生成單元測試:
<?php
class PhpUnderControl_TaskProgress_Test extends PHPUnit_Framework_TestCase
{
public $taskProgress;
protected function setUp()
{
parent::setUp();
$this->taskProgress = new Task_Progress();
}
/**
* @group testRun
*/
public function testRun()
{
$rs = $this->taskProgress->run();
}
}
并執(zhí)行之:
$ phpunit ./Task_Progress_Test.php
[1 - 0.06666s]SELECT id, title FROM phalapi_task_progress WHERE (state != ?) AND (last_fire_time < ?) AND (enable = ?) ORDER BY last_fire_time ASC; -- 0, 1431965153, 1<br>
[2 - 0.07002s]SELECT id, title, trigger_class, fire_params FROM phalapi_task_progress WHERE (state = 0) AND (interval_time + last_fire_time < ?) AND (enable = ?); -- 1432051553, 1<br>
[3 - 0.06549s]SELECT enable, state FROM phalapi_task_progress WHERE (id = '1');<br>
[4 - 0.07432s]UPDATE phalapi_task_progress SET state = 1 WHERE (id = '1');<br>
[5 - 0.06469s]UPDATE phalapi_task_progress SET result = '{\"total\":0,\"fail\":0}', state = 0, last_fire_time = 1432051553 WHERE (id = '1');<br>
[6 - 0.06746s]SELECT enable, state FROM phalapi_task_progress WHERE (id = '2');<br>
[7 - 0.07043s]UPDATE phalapi_task_progress SET state = 1 WHERE (id = '2');<br>
[8 - 0.06673s]SELECT id, params FROM phalapi_task_mq_0 WHERE (service = 'Default.Index') ORDER BY id ASC LIMIT 0,10;<br>
[9 - 0.48185s]DELETE FROM phalapi_task_mq_0 WHERE (id IN ('8'));<br>
[10 - 0.06514s]SELECT id, params FROM phalapi_task_mq_0 WHERE (service = 'Default.Index') ORDER BY id ASC LIMIT 0,10;<br>
[11 - 0.50694s]UPDATE phalapi_task_progress SET result = '{\"total\":1,\"fail\":0}', state = 0, last_fire_time = 1432051553 WHERE (id = '2');<br>
Time: 1.98 seconds, Memory: 6.50Mb
OK (1 test, 0 assertions)
查看對比一下數(shù)據(jù)庫,目前發(fā)現(xiàn)運(yùn)行良好!
提交代碼,保存文檔,收工睡覺!
得益于前期良好的設(shè)計(jì)以及底層支持,我們發(fā)現(xiàn),在提供這樣一種統(tǒng)一的調(diào)度方式是非常方便的。
不僅如此,如果你明白了其中的設(shè)計(jì),需要進(jìn)行定制和擴(kuò)展也是非常方便的。也就是說,我們不僅提供了一種具體實(shí)際可用的方式,也提供了廣闊自由的擴(kuò)展空間。具體與抽象,兩者仍可得。
然而,這一切不僅依賴于良好的設(shè)計(jì),還依賴于測試驅(qū)動開發(fā)下的浮現(xiàn)式設(shè)計(jì)。
Copyright©2021 w3cschool編程獅|閩ICP備15016281號-3|閩公網(wǎng)安備35020302033924號
違法和不良信息舉報(bào)電話:173-0602-2364|舉報(bào)郵箱:jubao@eeedong.com
掃描二維碼
下載編程獅App
編程獅公眾號
聯(lián)系方式:
更多建議: