All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.jboot.schedule.JbootDistributedRunnable Maven / Gradle / Ivy

/**
 * Copyright (c) 2015-2018, Michael Yang 杨福海 ([email protected]).
 * 

* Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at *

* http://www.apache.org/licenses/LICENSE-2.0 *

* Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package io.jboot.schedule; import com.jfinal.log.Log; import io.jboot.Jboot; import io.jboot.component.redis.JbootRedis; /** * @author Michael Yang 杨福海 ([email protected]) * @version V1.0 * @Title: 分布式任务 * @Description: 在分布式应用中,处理分布式应用,基于redis。 * 特点: 1、简单,无需依赖数据库。 * 2、高可用,不存在单点故障 * 3、一致性,在集群环境中,只有一个任务在执行。 * 4、Failover,支持故障转移 * @Package io.jboot.schedule */ public class JbootDistributedRunnable implements Runnable { private static final Log LOG = Log.getLog(JbootDistributedRunnable.class); private JbootRedis redis; private int expire = 50 * 1000; // 单位毫秒 private String key; private Runnable runnable; public JbootDistributedRunnable() { this.redis = Jboot.me().getRedis(); this.key = "jbootRunnable:" + this.getClass().getName(); if (redis == null) { LOG.warn("redis is null, " + "can not use @EnableDistributedRunnable in your Class[" + this.getClass().getName() + "], " + "or config redis info in jboot.properties"); } } public JbootDistributedRunnable(Runnable runnable) { this.runnable = runnable; this.key = "jbootRunnable:" + runnable.getClass().getName(); this.redis = Jboot.me().getRedis(); if (redis == null) { LOG.warn("redis is null, " + "can not use @EnableDistributedRunnable in your Class[" + runnable.getClass().getName() + "], " + "or config redis info in jboot.properties"); } } public JbootDistributedRunnable(Runnable runnable, int expire) { this.expire = (expire - 1) * 1000; this.runnable = runnable; this.key = "jbootRunnable:" + runnable.getClass().getName(); this.redis = Jboot.me().getRedis(); if (redis == null) { LOG.warn("redis is null, " + "can not use @EnableDistributedRunnable in your Class[" + runnable.getClass().getName() + "], " + "or config redis info in jboot.properties"); } } @Override public void run() { if (redis == null) { return; } Long result = null; for (int i = 0; i < 5; i++) { Long setTimeMillis = System.currentTimeMillis(); result = redis.setnx(key, setTimeMillis); //error if (result == null) { quietSleep(); } //setnx fail else if (result == 0) { Long saveTimeMillis = redis.get(key); if (saveTimeMillis == null) { reset(); } long ttl = System.currentTimeMillis() - saveTimeMillis; if (ttl > expire) { //防止死锁 reset(); } // 休息 2 秒钟,重新去抢,因为可能别的应用执行失败了 quietSleep(); } //set success else if (result == 1) { break; } } //抢了5次都抢不到,证明已经被别的应用抢走了 if (result == null || result == 0) { return; } try { if (runnable != null) { runnable.run(); } else { boolean runSuccess = execute(); //run()执行失败,让别的分布式应用APP去执行 //如果run()执行的时间很长(超过30秒),那么别的分布式应用可能也抢不到了,只能等待下次轮休 //作用:故障转移 if (!runSuccess) { reset(); } } } // 如果 run() 执行异常,让别的分布式应用APP去执行 // 作用:故障转移 catch (Throwable ex) { LOG.error(ex.toString(), ex); reset(); } } /** * 重置分布式的key */ private void reset() { redis.del(key); } public void quietSleep() { int millis = 2000; if (this.expire <= 2000) { millis = 100; } else if (this.expire <= 5000) { millis = 500; } else if (this.expire <= 300000) { millis = 1000; } try { Thread.sleep(millis); } catch (InterruptedException e) { e.printStackTrace(); } } //for override public boolean execute() { return true; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy