发表日期: 2021-04-27 08:59:52 浏览次数:102
邳州企业微信公众号小程序开发公司、邳州企业网页设计方案、邳州做网站开发价格、邳州微信公众号制作运营报价明细表、邳州网站设计公司费用、邳州网站推广大概需要多少钱
邳州,简称“邳”,江苏省徐州市代管县级市, [1-2] 古称良城、邳国、下邳、邳县,位于苏鲁交界,东接新沂市,西连徐州市铜山区、贾汪区,南界睢宁县,北邻山东省兰陵县。 [3] 1992年撤县设市。
邳州历史悠久,境内大墩子文化遗址距今6000年,是江苏文明最早的起源之一。境内有邳州市艾山风景名胜区、沙沟湖水杉公园、国家银杏博览园、小萝卜头纪念馆等旅游景点。邳州的城市精神是“创新、争先、开放、包容”。 [4]
邳州发展的目标是东陇海产业带重要的水陆交通枢纽、新兴工贸城市,京杭运河沿岸具有水乡特色和历史文化底蕴的生态宜居城市。
2019年7月,邳州入选国家知识产权强县工程试点县(区)。2019年,邳州位居全国综合实力百强县市第37位、经济竞争力百强第40位、全国投资潜力百强县市第18位、全国绿色发展百强县市第33位、全国科技创新百强县市第36位、全国新型城镇化质量百强县市第51位。
// Family-2.0$ vim ./Apps/Task/TMyTrigger/PushBase.php<?phpabstract class TMyTrigger_PushBase implements Task_Progress_Trigger {
public function fire($params) {
//取全部待推送的用户
$suser = $this->getWaitTOPushUserORM();
$mq = new Task_MQ_Array();
$runner = new Task_Runner_Local($mq);
$service = $this->getService();
$num = 0;
while (($row = $suser->fetch())) {
$num ++;
$UUID = Domain_User_Helper::userId2UUID($row['user_id']);
$mq->add($service, array('other_UUID' => $UUID, 'app_key' => '***', 'sign' => '***'));
$rs = $runner->go($service);
}
return $num;
}
/**
* 取全部待推送的用户
* @return NotORM
*/
abstract protected function getWaitTOPushUserORM();
/**
* 取服务名称
*/
abstract protected function getService();}复制代码上面是一个抽象触发器基类,它封装了具体的调度过程。具体实现子类只需要实现获取全部待推送的用户,以及获取服务名称这两个抽象方法即可。
下面是每周营养推送的具体实现。主要是实现了筛选初步符合每周推送的用户, 以及指定待执行的接口服务名称。
// Family-2.0$ vim ./Apps/Task/TMyTrigger/WeekPush.php <?phpclass TMyTrigger_WeekPush extends TMyTrigger_PushBase {
protected function getWaitTOPushUserORM() {
return DI()->notorm->suser ->select('user_id')
->where('type', 1)
->where('height > ?', 0)
->where('weight > ?', 0);
}
protected function getService() {
return 'Nutrition_SWeek.Push';
}}复制代码这里待执行的接口服务是Nutrition_SWeek.Push,那这个接口服务又在哪呢?还记得前面实现的每周推送领域业务类Domain_SPush_Week吗?其实此接口服务就是Domain_SPush_Week对应的上层接口类。打开这个接口类的文件,可以看到它需要一个other_UUID必须参数,以及在实现时调用了Domain_SPush_Week领域业务类。正如我们所预料的那样。以下是相应的代码片段。
// Family-2.0$ vim ./Apps/Scale/Api/Nutrition/SWeek.php <?phpclass Api_Nutrition_SWeek extends PhalApi_Api {
public function getRules() {
return array(
'*' => array(
'otherUUID' => array('name' => 'other_UUID', 'require' => true, 'min' => 50, 'max' => 50,),
),
);
}
public function push() {
$rs = array('code' => Common_Def::CODE_OK, 'msg' => '');
$domain = new Domain_SPush_Week();
$rs['code'] = $domain->push($this->otherUUID);
return $rs;
}}复制代码至此,就可以把整个业务流程打通了。那就是说,到此为止,我们已经初步实现了母婴营养称中核心的业务功能。也许这时,你可能觉得已经完成了重要的业务功能,可以暂且休息或者请年假出去旅游了。但也正如你看见的,从用户上报体重数据,到最后推送营养计划,这个过程涉及的业务众多,流程链路长,那么我们如何保证整个系统的稳定性和正确性呢?一个毫无疑问的回答是,单元测试。前面没有过多介绍单元测试,并不是暗示在这里不需要单元测试。恰恰相反,这里更需要单元测试,特别对于计划任务。没有介绍单元测试,是因为避免过多分散读者的注意力,并且已经假设读者对单元测试已经能熟悉应用。
但对于耗时的计划任务又应该如何快速测试呢?在测试时,并不能每次都对全部的用户进行推送。假设推送一次需要1秒,那么推送1200个用户,就需要20分钟。每次执行单元测试都需要20分钟,那简直是在浪费程序员的时间!还记得我们的F.I.R.S.T原则吗?其中一个原则就是要快速。因此,哪怕是进行计划任务的单元测试,我们也要保证它的快速性。对此,我曾有切身的体会。在我曾经刚入职的时候,有一项开发任务就是修改某个计划任务,追加对某个字段的处理。需求很简单,我也很快就修改好了。但由于当时的项目没有单元测试,本地也无法进行自测,需要提交代码并发布到回归环境后方能验证。你知道,人总会有犯错的时候。我第一次修改的代码有问题,得到测试人员的反馈后我进行了调整。再次提交代码,发布到回归环境,并经过漫长的等待(等待计划任务执行到我所编写修改的代码区域)后,被再次告知我遗漏了另一外的修改,那时已经等待了一个多小时……就这样,往来多次调整修改,因为反馈周期长,导致最终项目发布延迟。QA负责人都已经不耐烦地大叫道:“谁改的代码?怎么还不行?!”。如果你是那时的我,肯定会这么想:“要是有立即反馈的单元测试就好了”。而要想针对计划任务编写快速反馈的单元测试,需要掌握一些技巧。
首先,我们要保证单个执行过程的正确性。在上面的每周营养计划推送的场景中,单个执行过程其实就是指Nutrition_SWeek.Push接口服务在业务上的正确性。对于接口类的测试,我们前面已经介绍,这里不再赘述。关键是对计划任务调度过程的验证,也就是第二个重要的技巧。如果前面对一个用户进行推送这单个执行过程是正确的,并得到了充分的测试和验证,那么我们就有理由相信,对于10个、100个、乃至100万个用户进行推送都是能正常工作的。因此,在验证计划任务调度的过程时,我们可以把具体的执行过程进行模拟,不是真正进行推送操作,而是模拟推送。这样,便可大大减少执行的时间,提高单元测试反馈的速度。此外,只需关注对调度过程的验证即可。
例如,对于每周营养计划的触发器类,可以通过重载方法指定一个模拟的接口服务,从而达到模拟单个执行过程的目的。可先定义一个模板的推送接口服务,它什么都不做,只是返回一个模板的结果,如:
class Api_Nutrition_Mock extends PhalAPi_Api {
public function push() {
return array('code' => Common_Def::CODE_OK, 'msg' => '');
}}复制代码随后,在继承TMyTrigger_WeekPush的子类中,返回该模板的接口服务名称,如:
class TMyTrigger_WeekPush_Mock extends TMyTrigger_WeekPush {
protected function getService() {
return 'Nutrition_Mock.Push';
}}
邳州企业微信公众号小程序开发公司、邳州企业网页设计方案、邳州做网站开发价格、邳州微信公众号制作运营报价明细表、邳州网站设计公司费用、邳州网站推广大概需要多少钱