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

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



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值