elastic-job動(dòng)態(tài)添加定時(shí)任務(wù)

在elastic-job的使用過(guò)程中,我們會(huì)遇到動(dòng)態(tài)添加定時(shí)任務(wù)的時(shí)候,但是官網(wǎng)上面并沒(méi)有對(duì)這塊內(nèi)容進(jìn)行說(shuō)明秧骑。按照我的理解以及官網(wǎng)上面elastic-job的框架圖,ej的定時(shí)任務(wù)其實(shí)是存儲(chǔ)在zookeeper的一個(gè)個(gè)節(jié)點(diǎn)上面扣囊,所以通過(guò)給zookeeper添加對(duì)應(yīng)的節(jié)點(diǎn)即可完成定時(shí)任務(wù)的添加動(dòng)作乎折。

下面上代碼:

import java.text.SimpleDateFormat;
import java.util.Date;

import com.dangdang.ddframe.job.api.ShardingContext;
import com.dangdang.ddframe.job.api.simple.SimpleJob;
import com.dangdang.ddframe.job.config.JobCoreConfiguration;
import com.dangdang.ddframe.job.config.simple.SimpleJobConfiguration;
import com.dangdang.ddframe.job.exception.JobSystemException;
import com.dangdang.ddframe.job.lite.api.JobScheduler;
import com.dangdang.ddframe.job.lite.config.LiteJobConfiguration;
import com.dangdang.ddframe.job.reg.zookeeper.ZookeeperRegistryCenter;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class DynamicAddJob implements SimpleJob{
    private static final String CRON_DATE_FORMAT = "ss mm HH dd MM ? yyyy";

    /***
     * @param date 時(shí)間
     * @return cron類型的日期
     */
    public static String getCron(final Date date) {
        SimpleDateFormat sdf = new SimpleDateFormat(CRON_DATE_FORMAT);
        String formatTimeStr = "";
        if (date != null) {
            formatTimeStr = sdf.format(date);
        }
        return formatTimeStr;
    }


    public static void main(String[] args){
        ApplicationContext context = new ClassPathXmlApplicationContext("classpath:spring/applicationContext-job.xml");
        ZookeeperRegistryCenter zookeeperRegistryCenter = context.getBean(ZookeeperRegistryCenter.class);
        long now = System.currentTimeMillis();
        for (int i = 0; i < 100; i++) {
            String cron = getCron(new Date(now + (i + 1) * 50000));
            JobCoreConfiguration coreConfig = JobCoreConfiguration.newBuilder("dynamicDemoJob-" + i, cron, 2).build();
            SimpleJobConfiguration simpleJobConfig = new SimpleJobConfiguration(coreConfig, DynamicAddJob.class.getCanonicalName());
            JobScheduler jobScheduler = new JobScheduler(zookeeperRegistryCenter, LiteJobConfiguration.newBuilder(simpleJobConfig).build());
            try {
                jobScheduler.init();
            }catch (JobSystemException e){
                e.printStackTrace();
            }
        }
    }

    @Override
    public void execute(ShardingContext shardingContext) {
        switch (shardingContext.getShardingItem()){
            case 0:
                System.out.println("doing sharding 0...job name is "+shardingContext.getJobName());
                // do something by sharding item 0
                break;
            case 1:
                System.out.println("doing sharding 1...job name is "+shardingContext.getJobName());
                // do something by sharding item 1
                break;
        }
    }
}

這里用到比較重要的一個(gè)類是JobScheduler,這是lite-core里面一個(gè)比較核心的類侵歇,這個(gè)類其實(shí)就是我們的job骂澄,他的構(gòu)造方法包含以下參數(shù):

  • CoordinatorRegistryCenter regCenter:注冊(cè)中心,這里是zookeeper
  • LiteJobConfiguration liteJobConfig:定時(shí)任務(wù)的配置信息

這里可以看一下LiteJobConfiguration這個(gè)類惕虑,采用了設(shè)計(jì)模式中的建造者模式進(jìn)行構(gòu)建坟冲。可能看著會(huì)比較摸不著頭腦溃蔫,里面的Builder跟平時(shí)的不太一樣健提,這里我們需要知道的是ej的源碼采用了lombok這個(gè)代碼簡(jiǎn)化的工具,只需要通過(guò)注解的形式就能將我們平時(shí)所需要的get/set和構(gòu)造器的內(nèi)容在編譯時(shí)創(chuàng)建出來(lái)伟叛,不需要在代碼中體現(xiàn)私痹,能夠大大簡(jiǎn)化我們的代碼。

另外還遇到一個(gè)坑。這段代碼不能重復(fù)使用紊遵,第一次跑的時(shí)候沒(méi)問(wèn)題账千,過(guò)段時(shí)間再次跑這個(gè)代碼時(shí),會(huì)在init()處報(bào)錯(cuò)暗膜,原因是我們新建的job根本不能被fire匀奏,我跟了進(jìn)去。發(fā)現(xiàn)学搜,job的cron表達(dá)式表示的時(shí)間還是以前的時(shí)間攒射,這就奇怪了,明明我這邊配置了一個(gè)新的時(shí)間恒水。通過(guò)debug会放,進(jìn)入init方法中,發(fā)現(xiàn)他會(huì)更新job信息钉凌,而更新時(shí)咧最,會(huì)去zk上面load配置信息,而zk的znode節(jié)點(diǎn)是老的節(jié)點(diǎn)御雕,上面存儲(chǔ)的配置信息也是老的矢沿,所以這塊的cron表達(dá)式也是舊的時(shí)間,根本不會(huì)被執(zhí)行酸纲,下面貼出源碼捣鲸,供大家參考。

init()源碼:

    /**
     * 初始化作業(yè).
     */
    public void init() {
        LiteJobConfiguration liteJobConfigFromRegCenter = schedulerFacade.updateJobConfiguration(liteJobConfig);
        JobRegistry.getInstance().setCurrentShardingTotalCount(liteJobConfigFromRegCenter.getJobName(), liteJobConfigFromRegCenter.getTypeConfig().getCoreConfig().getShardingTotalCount());
        JobScheduleController jobScheduleController = new JobScheduleController(createScheduler(), createJobDetail(liteJobConfigFromRegCenter.getTypeConfig().getJobClass()), liteJobConfigFromRegCenter.getJobName());
        JobRegistry.getInstance().registerJob(liteJobConfigFromRegCenter.getJobName(), jobScheduleController, regCenter);
        schedulerFacade.registerStartUpInfo(!liteJobConfigFromRegCenter.isDisabled());
        jobScheduleController.scheduleJob(liteJobConfigFromRegCenter.getTypeConfig().getCoreConfig().getCron());
    }

updateJobConfiguration()的源碼如下:

    /**
     * 更新作業(yè)配置.
     *
     * @param liteJobConfig 作業(yè)配置
     * @return 更新后的作業(yè)配置
     */
    public LiteJobConfiguration updateJobConfiguration(final LiteJobConfiguration liteJobConfig) {
        configService.persist(liteJobConfig);
        return configService.load(false);
    }

load()源碼如下:

    /**
     * 讀取作業(yè)配置.
     * 
     * @param fromCache 是否從緩存中讀取
     * @return 作業(yè)配置
     */
    public LiteJobConfiguration load(final boolean fromCache) {
        String result;
        if (fromCache) {
            result = jobNodeStorage.getJobNodeData(ConfigurationNode.ROOT);
            if (null == result) {
                result = jobNodeStorage.getJobNodeDataDirectly(ConfigurationNode.ROOT);
            }
        } else {
            result = jobNodeStorage.getJobNodeDataDirectly(ConfigurationNode.ROOT);
        }
        return LiteJobConfigurationGsonFactory.fromJson(result);
    }

可以發(fā)現(xiàn)這塊load有兩種闽坡,一種是從緩存(這里的緩存使用Map來(lái)實(shí)現(xiàn)的TreeCache)中獲取getJobNodeData栽惶,一種是從注冊(cè)中心也就是zookeeper中獲取getJobNodeDataDirectly。load的時(shí)候疾嗅,根據(jù)的是zk的路徑外厂,其實(shí)也就是任務(wù)的jobName,所以我們要盡量避免任務(wù)名稱的重復(fù)代承。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末汁蝶,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子论悴,更是在濱河造成了極大的恐慌掖棉,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,490評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件膀估,死亡現(xiàn)場(chǎng)離奇詭異幔亥,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)玖像,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,581評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門紫谷,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)齐饮,“玉大人,你說(shuō)我怎么就攤上這事笤昨∽媲” “怎么了?”我有些...
    開封第一講書人閱讀 165,830評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵瞒窒,是天一觀的道長(zhǎng)捺僻。 經(jīng)常有香客問(wèn)我,道長(zhǎng)崇裁,這世上最難降的妖魔是什么匕坯? 我笑而不...
    開封第一講書人閱讀 58,957評(píng)論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮拔稳,結(jié)果婚禮上葛峻,老公的妹妹穿的比我還像新娘。我一直安慰自己巴比,他們只是感情好术奖,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,974評(píng)論 6 393
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著轻绞,像睡著了一般采记。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上政勃,一...
    開封第一講書人閱讀 51,754評(píng)論 1 307
  • 那天唧龄,我揣著相機(jī)與錄音,去河邊找鬼奸远。 笑死既棺,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的然走。 我是一名探鬼主播援制,決...
    沈念sama閱讀 40,464評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼戏挡,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼芍瑞!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起褐墅,我...
    開封第一講書人閱讀 39,357評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤拆檬,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后妥凳,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體竟贯,經(jīng)...
    沈念sama閱讀 45,847評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,995評(píng)論 3 338
  • 正文 我和宋清朗相戀三年逝钥,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了屑那。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,137評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖持际,靈堂內(nèi)的尸體忽然破棺而出沃琅,到底是詐尸還是另有隱情,我是刑警寧澤蜘欲,帶...
    沈念sama閱讀 35,819評(píng)論 5 346
  • 正文 年R本政府宣布益眉,位于F島的核電站,受9級(jí)特大地震影響姥份,放射性物質(zhì)發(fā)生泄漏郭脂。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,482評(píng)論 3 331
  • 文/蒙蒙 一澈歉、第九天 我趴在偏房一處隱蔽的房頂上張望展鸡。 院中可真熱鬧,春花似錦埃难、人聲如沸娱颊。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,023評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)箱硕。三九已至,卻和暖如春悟衩,著一層夾襖步出監(jiān)牢的瞬間剧罩,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,149評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工座泳, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留惠昔,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,409評(píng)論 3 373
  • 正文 我出身青樓挑势,卻偏偏與公主長(zhǎng)得像镇防,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子潮饱,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,086評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理来氧,服務(wù)發(fā)現(xiàn),斷路器香拉,智...
    卡卡羅2017閱讀 134,672評(píng)論 18 139
  • scheduler定時(shí)調(diào)度系統(tǒng)是大多行業(yè)項(xiàng)目都需要的啦扬,傳統(tǒng)的spring-job模式,個(gè)人感覺(jué)已經(jīng)out了凫碌,因?yàn)榇?..
    安琪拉_4b7e閱讀 2,841評(píng)論 4 6
  • 《分布式任務(wù)調(diào)度平臺(tái)XXL-JOB》 一扑毡、簡(jiǎn)介 1.1 概述 XXL-JOB是一個(gè)輕量級(jí)分布式任務(wù)調(diào)度框架,其核心...
    許雪里閱讀 16,795評(píng)論 3 29
  • 你終于要回來(lái)了盛险! 其實(shí)我知道你對(duì)于回福建的猶豫瞄摊,畢竟不是自個(gè)熟悉的地方勋又。 但是我希望能成為你歸來(lái)的其中一個(gè)哪怕很小...
    GandA閱讀 213評(píng)論 0 1
  • 每次看書的時(shí)候都特喜歡劇情大反轉(zhuǎn)的結(jié)局,特享受那種震撼感换帜。 所有的伏筆在開篇時(shí)早已埋下赐写,所有的結(jié)局在開始時(shí)早已...
    汐情閱讀 414評(píng)論 2 1