使用Elastic Job的時候報“Job conflict with register center”,如何處理?

程式猿DD發表於2021-07-30

昨天,有群友反應根據之前這篇《使用Elastic Job實現定時任務》文章編寫測試定時任務的時候,報了類似下面的這個錯誤:

Caused by: org.apache.shardingsphere.elasticjob.infra.exception.JobConfigurationException: Job conflict with register center. The job 'my-simple-job' in register center's class is 'com.didispace.chapter72.MySimpleJob', your job class is 'com.didispace.chapter74.MySimpleJob'
	at org.apache.shardingsphere.elasticjob.lite.internal.config.ConfigurationService.checkConflictJob(ConfigurationService.java:86) ~[elasticjob-lite-core-3.0.0.jar:3.0.0]
	at org.apache.shardingsphere.elasticjob.lite.internal.config.ConfigurationService.setUpJobConfiguration(ConfigurationService.java:70) ~[elasticjob-lite-core-3.0.0.jar:3.0.0]
	at org.apache.shardingsphere.elasticjob.lite.internal.setup.SetUpFacade.setUpJobConfiguration(SetUpFacade.java:66) ~[elasticjob-lite-core-3.0.0.jar:3.0.0]
	at org.apache.shardingsphere.elasticjob.lite.internal.schedule.JobScheduler.<init>(JobScheduler.java:84) ~[elasticjob-lite-core-3.0.0.jar:3.0.0]
	at org.apache.shardingsphere.elasticjob.lite.api.bootstrap.impl.ScheduleJobBootstrap.<init>(ScheduleJobBootstrap.java:36) ~[elasticjob-lite-core-3.0.0.jar:3.0.0]
	at org.apache.shardingsphere.elasticjob.lite.spring.boot.job.ElasticJobBootstrapConfiguration.registerClassedJob(ElasticJobBootstrapConfiguration.java:101) ~[elasticjob-lite-spring-boot-starter-3.0.0.jar:3.0.0]
	at org.apache.shardingsphere.elasticjob.lite.spring.boot.job.ElasticJobBootstrapConfiguration.constructJobBootstraps(ElasticJobBootstrapConfiguration.java:84) ~[elasticjob-lite-spring-boot-starter-3.0.0.jar:3.0.0]
	at org.apache.shardingsphere.elasticjob.lite.spring.boot.job.ElasticJobBootstrapConfiguration.createJobBootstrapBeans(ElasticJobBootstrapConfiguration.java:57) ~[elasticjob-lite-spring-boot-starter-3.0.0.jar:3.0.0]
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_151]
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_151]
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_151]
	at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_151]
	at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor$LifecycleElement.invoke(InitDestroyAnnotationBeanPostProcessor.java:389) ~[spring-beans-5.3.8.jar:5.3.8]
	at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor$LifecycleMetadata.invokeInitMethods(InitDestroyAnnotationBeanPostProcessor.java:333) ~[spring-beans-5.3.8.jar:5.3.8]
	at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor.postProcessBeforeInitialization(InitDestroyAnnotationBeanPostProcessor.java:157) ~[spring-beans-5.3.8.jar:5.3.8]
	... 17 common frames omitted

根據錯誤訊息Job conflict with register center. The job 'my-simple-job' in register center's,初步判斷是ZooKeeper中儲存的任務配置出現衝突:任務名一樣,但實現類不同。

經過一番交流,原來他是使用公司測試環境的ZooKeeper來寫的例子做測試,同時之前有同事(也是DD的讀者)也寫過類似的任務,因為配置的任務名稱是拷貝的,所以出現了任務名稱相對,但實現類不同的情況。

實際上,如果我們在一個大一些的團隊做開發的時候,只要存在多系統的話,那麼定時任務的重名其實是很有可能發生。比如:很多應用都可能存在一些定時清理某些資源的任務,就很可能起一樣的名字,然後註冊到同一個ZooKeeper,最後出現衝突。 那麼有什麼好辦法來解決這個問題嗎?

方法一:任務建立的統一管理

最原始的處理方法,就是集中的管理任務建立流程,比如:可以開一個Wiki頁面,所有任務在這個頁面上登記,每個人登記的時候,可以查一下想起的名字是否已經存在。如果存在了就再想一個名字,並做好登記。

這種方法很簡單,也很好理解。但存在的問題是,當任務非常非常多的時候,這個頁面內容就很大,維護起來也是非常麻煩的。

方法二:巧用Elastic Job的namespace屬性來隔離任務名稱

回憶一下之前第一篇寫定時任務的時候,關於註冊中心的配置是不是有下面兩項:

elasticjob.reg-center.server-lists=localhost:2181
elasticjob.reg-center.namespace=didispace

第一個elasticjob.reg-center.server-lists不多說,就是ZooKeeper的訪問地址。這裡要重點講的就是第二個引數elasticjob.reg-center.namespace

其實在ZooKeeper中註冊任務的時候,真正衝突的並不純粹是因為任務名稱,而是namespace + 任務名稱,全部一樣,才會出現問題。

所以,我們只需要把每個應用建立的任務都隔離在自己獨立的namespace裡,那麼是不是就不會和其他應用出現衝突了呢?

最後,我給出了下面這樣的建議:

spring.application.name=chapter74

elasticjob.reg-center.server-lists=localhost:2181
elasticjob.reg-center.namespace=${spring.application.name}

即:將定時任務服務的elasticjob.reg-center.namespace設定為當前Spring Boot應用的名稱一致spring.application.name

通常,我們在規劃各個Spring Boot應用的時候,都會做好唯一性的規劃,這樣未來註冊到Eureka、Nacos等註冊中心的時候,也可以保證唯一。

利用好這個唯一引數,也可以方便的幫我們把各個應用的定時任務也都隔離出來,也就解決了文章開頭,我們所說的場景了。

本系列教程《Spring Boot 2.x基礎教程》點選直達!,歡迎收藏與轉發!如果學習過程中如遇困難?可以加入我們Spring技術交流群,參與交流與討論,更好的學習與進步!

程式碼示例

本文的完整工程可以檢視下面倉庫中的chapter7-4目錄:

如果您覺得本文不錯,歡迎Star支援,您的關注是我堅持的動力!

歡迎關注我的公眾號:程式猿DD,分享外面看不到的乾貨與思考!

相關文章