增强的单据通esb插件任务调度策略及配置

来源:互联网 发布:php中空对象的if 判断 编辑:程序博客网 时间:2024/05/19 02:03

1.缘起

基于hotfox的程序,到v3.2止只支持2种后台任务调度方式:
(1)每间隔:适用于指定一段时间重复执行的任务,如每小时执行一次
(2)每天执行一次:需要指定执行的时间,精确到分钟,如02:30.

近期的2个项目分别提出了超出上述能力的需求,这些需求的含义描述如下:
  • 要求每N周执行一次,可指定一周的哪天的什么时间,如每2周的周三19:00执行一次
  • 要求每月执行一次,可指定哪天和时间点,如每月1号的20:00执行一次.

增强后实现了对以下调度策略的支持:

ID

名称

参数

 参数说明

上次活动标记

示例及说明

1

每间隔

间隔时间

 

间隔时间单位:秒

 

 1,0,60

表示间隔60秒

2

每天执行

 执行时间(HHMM),到期检查间隔


 YYYYMMDD

 2,0,200,60

每天2:00执行,到期检测间隔60秒

3

 按周调度

 周数,星期几,执行时间(HHMM),到期检查间隔

 星期几,执行时间可选

YY YYMMDD

 3,0,2,1,200,60

每2周的周一的2:00执行,到期检查间隔60秒

4

 按月调度

 每月N号,执行时间(HHMM),到期检查间隔

 执行时间可选

 YYYYMM

 4,0,(1),(2200),60

每月1号22:00执行,到期检查间隔60秒


  策略定义格式:策略ID,属性,参数
 策略属性:保留,如可用于指定一次性任务。
记录上次活动的时间标记可以在服务重起启动时能正确地接续,避免任务重做或漏做。
标记的时间是任务开始执行的时间(而非任务结束的时间,这对每天执行运行时间跨天的情况存在语义上的差异).

2.配置说明

以下以esb插件为例说明如何配置后台任务的调度策略:

      <ScheduleStrategy>            <strategy>4,0,(1),(2200),60</strategy>               <last_time_tag>201308</last_time_tag>             </ScheduleStrategy>                     <Schedule Type="0">            <Interval>6</Interval>        </Schedule>
           
<ScheduleStrategy>是新的策略定义节点,<Schedule>是原有的策略定义.
优先采用<ScheduleStrategy>定义,只有在没有<ScheduleStrategy>时才检查<Schedule>.
上述<ScheduleStrategy>配置中,<strategy>为策略定义,<last_time_tag>为任务上次执行的时间标记.
<strategy>4,0,(1),(2200),60</strategy>  
表示:
该任务采用每月1号22:00执行一次.到期检查间隔为60秒.
其中,"(1)"和"(2200)"参数中使用括号是考虑对每月某几天或某天的几个时间点执行.

3.实现说明

实现方法考虑以下特性:
(1)必须兼容现有部署运行的系统
(2)既然无法一劳永逸适应所有的可能,模块应该方便应需求驱动进行扩展.


3.1hotfox

增强依赖对hotfox关于后台任务(DeamonTask,DeamonTaskManager)接口的改变,新的IDeamonTask接口增加了以下方法:
typedef int (*OnTaskDoneFunc)(void *arg,const char *tag); ///< 任务结束回调struct IDeamonTask {public:    ///< 取任务的调度策略    virtual IScheduleStrategy* get_strategy() = 0;    ///< 指定任务的调度策略    virtual void set_strategy(IScheduleStrategy *strategy) = 0;    ///< 设置按周调度策略    virtual int set_week_strategy(unsigned short week_num,unsigned short week_day,unsigned short start_time,unsigned short interval=60,unsigned long last_day=0) = 0;    ///< 获取任务ID    virtual unsigned long get_id() const = 0;    ///< 设置回调函数    virtual void set_done_cb(OnTaskDoneFunc func,void *arg=0) = 0;    ///< 获取回调函数    virtual OnTaskDoneFunc get_done_cb() = 0;    ///< 获取回调参数    virtual void* get_done_cb_arg() = 0;};
OnTaskDoneFunc回调函数的用途是在任务执行成功后修改上次任务时间标记.
该标记可能保存在本地配置文件中,也可以集中保存在数据库中.这由具体的应用体系来决定。
set_week_strategy提供内置的按周调度的策略设置方法.
get_id返回任务ID,该ID没有全局意义.仅用于执行回调修改上次任务时间标记时能正确匹配。

按周调度作为内置功能提供,按月调度采用框架外实现.目的一是作为以后扩展的示例,二是避免每增加新的调度策略需要框架修改.


主要实现修改内容:

3.2 esb_task.h

class c_esb_scan_rule_week : public i_esb_scan_rule {public:    short week_num_;    short wday_;    long l_time_;    short n_interval_;    unsigned long last_day_;public:    c_esb_scan_rule_week():n_interval_(60),last_day_(0) {    }    virtual int ReadConfig(INode* parentNode) { return 0;}    virtual void settaskinfo(IDeamonTask* task);    bool tg_flag() const { return true;}};class c_esb_scan_rule_month : public i_esb_scan_rule {public:    short n_day_;    long l_time_;    short n_interval_;    unsigned long last_month_;public:    c_esb_scan_rule_month():n_interval_(60),last_month_(0) {    }    virtual int ReadConfig(INode* parentNode) { return 0;}    virtual void settaskinfo(IDeamonTask* task);    bool tg_flag() const { return true;}};

3.3 esb_task.cpp

i_esb_scan_rule* c_esb_scan_rule_factory::new_rule(INode* parentNode) {    INode* subnode  = parentNode->GetChildNodes()->GetChildNode("strategy"); ///< 策略描述串    if (subnode==NULL)        return NULL;    string ss = (string)*subnode;    i_esb_scan_rule* rule = 0;    CStrategyStringParser ssp;    ssp.set_ss(ss.c_str());    int type = ssp.get_type();    subnode = parentNode->GetChildNodes()->GetChildNode("last_time_tag"); ///< 最近一次任务时间标记    if (type!=1&&subnode==NULL) ///< 每间隔调度策略目前不记录上次执行时间标记(影响性能,并且不必要)        return NULL;    string tg = (string)*subnode;    ssp.get_prop();    char *buffer = 0;    switch(type) {            case 1: {                c_esb_scan_rule_time *c_rule = new c_esb_scan_rule_time;                ssp.get_next_item(&buffer);                c_rule->l_interval_ = atol(buffer);                delete []buffer;                rule = c_rule;                    break;                    }            case 2:  {                c_esb_scan_rule_date *c_rule = new c_esb_scan_rule_date;                ssp.get_next_item(&buffer);                c_rule->l_time_ = atoi(buffer);                delete []buffer;                if (ssp.get_next_item(&buffer)) {                    c_rule->n_interval_ = atoi(buffer);                    delete []buffer;                }                c_rule->last_day_ = atol(tg.c_str());                rule = c_rule;                break;                     }            case 3: {                c_esb_scan_rule_week *c_rule = new c_esb_scan_rule_week;                c_rule->week_num_ = atoi(buffer);                delete []buffer;                                if (ssp.get_next_item(&buffer)) {                    c_rule->wday_ = atoi(buffer);                    delete []buffer;                }                if (ssp.get_next_item(&buffer)) {                    c_rule->l_time_ = atol(buffer);                    delete []buffer;                }                if (ssp.get_next_item(&buffer)) {                    c_rule->n_interval_ = atoi(buffer);                    delete []buffer;                }                c_rule->last_day_ = atol(tg.c_str());                rule = c_rule;                break;                    }            case 4: {                c_esb_scan_rule_month *c_rule = new c_esb_scan_rule_month;                char *buffer = 0;                ssp.get_next_item(&buffer);                c_rule->n_day_ = atol(buffer);                delete []buffer;                if (ssp.get_next_item(&buffer)!=-1) {                    c_rule->l_time_ = atoi(buffer);                    delete []buffer;                }                if (ssp.get_next_item(&buffer)) {                    c_rule->n_interval_ = atoi(buffer);                    delete []buffer;                }                c_rule->last_month_ = atol(tg.c_str());                rule = c_rule;                break;                    }            default:                return 0;    }    return rule;}void c_esb_scan_rule_week::settaskinfo(IDeamonTask* task) {    task->set_week_strategy(week_num_,wday_,l_time_,n_interval_,last_day_);}void c_esb_scan_rule_month::settaskinfo(IDeamonTask* task) {    CMonthStrategy *stg = new CMonthStrategy;    stg->last_month_ = last_month_;    stg->active_day_ = n_day_;    stg->start_time_ = l_time_;    stg->interval_ = n_interval_;    task->set_strategy(stg);}

3.4 esb.cpp

int esbPlugin::ReadPrivateConfig()        nodelist_sheet = parentNode->GetChildNodes()->GetChildNodes("ScanTask");        count = nodelist_sheet->Count();        for(i=0;i<count;i++){            INode *subnode = nodelist_sheet->GetChildNode(i);            c_esb_task* task = new c_esb_task();            task->set_id(i+1); ///< 设置任务ID            vec_tasklist.push_back(task);            ret = task->ReadConfig(subnode);            if(ret){                config_->Close();                ACE_ERROR_RETURN((LM_ERROR,"esb:open config::Tasks::SheetFileScanTask[%s] 返回值=[%d].\n",cf_.c_str(),ret),-1);            }        }        int esbPlugin::RegisterTask() {    vector<c_esb_task*>::iterator iter = vec_tasklist.begin();    for(; iter != vec_tasklist.end(); iter++)    {        c_esb_task* esbtask = *iter;        IDeamonTask *task = deamon_mgr_->add(OnTaskTranslate1,"esbPlugin::OnTaskTranslate1",esbtask);        esbtask->settaskinfo(task);                if (esbtask->c_rule_->tg_flag()) {            task->set_done_cb(::OnTaskDoneProc,(void*)esbtask->id_); ///< 设置任务结束回调函数        }    }    return 0;}////////////////////////////////////////////////////////////////////////////////int OnTaskDoneProc(void *arg,const char *tag) {    return esbPlugin_Singleton::instance()->OnTaskDoneProc(arg,tag);}////////////////////////////////////////////////////////////////////////////////int esbPlugin::OnTaskDoneProc(void *arg,const char *tag) {    AUTO_CLOSE_CONFIG(config_);    int t_id = (int)arg;    if (config_->Open(cf_.c_str())) {        return -1;    }    INode *root = config_->GetChildNodes()->GetChildNode("config");    INode *node,*attr;    INode *task_list_node = root->GetChildNodes()->GetChildNode("Tasks");    if (task_list_node==0)        return -1;    INodeList *nl = task_list_node->GetChildNodes()->GetChildNodes("ScanTask");    int task_num = nl->Count();    for (int i=0;i<task_num;i++) {        INode *subnode = nl->GetChildNode(i);        if (t_id==(i+1)) {            INode *stg_node = subnode->GetChildNodes()->GetChildNode("ScheduleStrategy");            if (stg_node==0)                return 0;            INode *last_time_tag_node = stg_node->GetChildNodes()->GetChildNode("last_time_tag");            last_time_tag_node->operator=((char*)tag);            config_->Save();            break;        }    }    nl->Release();    config_->Close();    return 0;}

3.5 工程

.增加:quartz_month_strategy,quartz_strategy_parser(.cpp,.h文件)

4.HOWTOD

4.1如何使用已实现的调度策略


4.2如何增加新的调度策略


5.TODO