說道定時任務,你們立馬會想到Quartz,強大的任務調度引擎和時間規則配置讓咱們只須要專一於業務,並且使用極其方便,但是最近中信雲上就栽了一個大跟頭。java
中信雲有測試環境和正式環境,定時任務框架在測試環境上跑的很溜,可是一更新到正式環境加載初始化就報錯,報錯信息以下:apache
Couldn't generate instance Id! org.quartz.SchedulerException: Couldn't get host name! [See nested exception: java.net.UnknownHostException: iZ2ze6wfyo1q58e7lo99kvZ: iZ2ze6wfyo1q58e7lo99kvZ] at org.quartz.simpl.SimpleInstanceIdGenerator.generateInstanceId(SimpleInstanceIdGenerator.java:36) at org.quartz.impl.StdSchedulerFactory.instantiate(StdSchedulerFactory.java:1184) at org.quartz.impl.StdSchedulerFactory.getScheduler(StdSchedulerFactory.java:1484) at net.luculent.liems.business.bd.util.BdTaskServlet.init(BdTaskServlet.java:36) at javax.servlet.GenericServlet.init(GenericServlet.java:158) at org.apache.catalina.core.StandardWrapper.initServlet(StandardWrapper.java:1282) at org.apache.catalina.core.StandardWrapper.loadServlet(StandardWrapper.java:1195) at org.apache.catalina.core.StandardWrapper.load(StandardWrapper.java:1085) at org.apache.catalina.core.StandardContext.loadOnStartup(StandardContext.java:5318) at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5610) at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:147) at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1572) at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1562) at java.util.concurrent.FutureTask.run(FutureTask.java:262) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615) at java.lang.Thread.run(Thread.java:745)
看到這個報錯後,猜想應該和環境有問題,上網查找解決辦法都是出奇的一致,以爲問題不是大問題,解決辦法以下:api
進入線上環境(centOs6.x): 1, 查看主機名(命令) : hostname 2, 打開hosts文件: vi /etc/hosts 查看是否有亂碼等異常內容 3, 確保有: 127.0.0.1 後跟上面用hostname命令查看到的主機名, 若是沒有則加上 如 : hostname -> USER-1234 則: 127.0.0.1 USER-1234
正式環境上配置後效果立杆見影,報錯沒有了,接下來驗證業務,可是全部全部程序都打不開了,找來日誌發現是受權失敗了,打開剛剛配置的文件app
127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4 iZ2ze6wfyo1q58e7lo99kvZ ::1 localhost localhost.localdomain localhost6 localhost6.localdomain6
發現以前的配置都是帶了域名的,因而我也加了一個域名框架
127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4 iZ2ze6wfyo1q58e7lo99kvZ.localdomain ::1 localhost localhost.localdomain localhost6 localhost6.localdomain6
結果是受權能夠了,可是定時任務又報了相同的錯,因而總結出了我想要的配置和受權的配置起了衝突,我這裏不能改受權,因而只能從定時任務下手了dom
報錯的地方是初始化任務計劃的id,在StdSchedulerFactory裏面找到了這個報錯的這個類ide
if (schedInstId.equals(AUTO_GENERATE_INSTANCE_ID)) { autoId = true; instanceIdGeneratorClass = cfg.getStringProperty( PROP_SCHED_INSTANCE_ID_GENERATOR_CLASS, "org.quartz.simpl.SimpleInstanceIdGenerator"); } else if (schedInstId.equals(SYSTEM_PROPERTY_AS_INSTANCE_ID)) { autoId = true; instanceIdGeneratorClass = "org.quartz.simpl.SystemPropertyInstanceIdGenerator"; }
public class SimpleInstanceIdGenerator implements InstanceIdGenerator { public String generateInstanceId() throws SchedulerException { try { return InetAddress.getLocalHost().getHostName() + System.currentTimeMillis(); } catch (Exception e) { throw new SchedulerException("Couldn't get host name!", e); } } }
public class SystemPropertyInstanceIdGenerator implements InstanceIdGenerator { /** * System property to read the instanceId from */ public static final String SYSTEM_PROPERTY = "org.quartz.scheduler.instanceId"; /** * Returns the cluster wide value for this scheduler instance's id, based on a system property * @return the value of the {@link SystemPropertyInstanceIdGenerator#SYSTEM_PROPERTY system property} * @throws SchedulerException Shouldn't a value be found */ public String generateInstanceId() throws SchedulerException { String property = System.getProperty(SYSTEM_PROPERTY); if(property == null) { throw new SchedulerException("No value for '" + SYSTEM_PROPERTY + "' system property found, please configure your environment accordingly!"); } return property; } }
頓時思路如泉涌,感嘆人家代碼的設計好靈活,就像爲我這個尷尬境遇專門設計的,也才反應過來測試環境是單機的,正式環境是集羣的,測試環境就沒有調用這個方法,因而決定使用SystemPropertyInstanceIdGenerator 來初始化id,找出了配置文件quartz.properties 修改了instanceId爲SYS_PROP測試
org.quartz.scheduler.instanceName = scheduler org.quartz.scheduler.instanceId = SYS_PROP org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool org.quartz.threadPool.threadCount = 10 org.quartz.threadPool.threadPriority = 5 org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread = true org.quartz.jobStore.misfireThreshold = 60000 org.quartz.jobStore.class = org.quartz.impl.jdbcjobstore.JobStoreTX org.quartz.jobStore.driverDelegateClass=org.quartz.impl.jdbcjobstore.PostgreSQLDelegate org.quartz.jobStore.tablePrefix = QRTZ_ org.quartz.jobStore.maxMisfiresToHandleAtATime=10 org.quartz.jobStore.isClustered = true
修改了catalina.sh添加了系統屬性this
JAVA_OPTS="$JAVA_OPTS -Dorg.quartz.scheduler.instanceId=01"
重啓環境,終於實現世界和平了.net
總結:有時候咱們在解決問題徹底沒有思路的時候就須要從源碼入手,這就須要咱們平時多看看一些開源的框架源碼,初期不建議打開代碼一行一行過,能夠經過官方的api文檔來閱讀各個方法做用,經過各類場景代碼來跟蹤調試,在後面咱們會分享Quartz的實現原理,歡迎關注。