Le redémarrage de quartz planificateur sans avoir une erreur
Contexte
Je suis en train d'utiliser le planificateur quartz de mode de cluster à l'aide de jdbc.
Problème
Avant j'ai commencé avec jdbc en mode cluster je viens de tester le planificateur en général avec la RAM magasin. Qui a fonctionné sans problème et j'ai pu redémarrer le planificateur (classe principale), sans erreurs. Le problème que j'ai maintenant c'est que quand j'ai arrêter l'exécution (ctrl+c) puis de le redémarrer, je reçois toujours le message d'erreur:
org.quartz.ObjectAlreadyExistsException: Unable to store Job : 'MyTestJob', because one already exists with this identification.
Je ne comprends pas ce qui se passe ici. Ne quartz de ne pas soutenir le redémarrage de l'ordonnanceur? Je veux dire, qu'advient-il si il y a un crash, et le planificateur redémarre après la reprise? Est la seule option pour ensuite supprimer les travaux du quartz de la base de données? Peut-être il ya une autre méthode ou quelque chose que j'ai manqué. Je ne me sens pas très à l'aise à l'aide d'une bibliothèque qui n'a pas à composer avec redémarre.
Une autre chose étrange est, que lors de la modification de jdbc mon travail, ne pas se déclencher plus et je viens de voir l'état d'ATTENTE dans la DB. Ce pourrait-il être? Le travail (cron-horaire) a fonctionné sans problème en mode RAM.
Je suis un peu surpris par le niveau de la documentation et les problèmes que je rencontre avec cette simple tâche parce que j'ai entendu le planificateur quartz pour de nombreuses années maintenant, mais jamais trouvé le temps de l'utiliser. Goodle penser que je ne suis pas le seul avec ce problème. J'espère que c'est juste moi et qu'il existe une solution simple à mon problème, sinon, il serait très décevant pour essayer cette bibliothèque pour la première fois dans le 2.2.x version et déjà d'avoir à chercher quelque chose d'autre.
Voici ma configuration:
#============================================================================
# Configure Main Scheduler Properties
#============================================================================
org.quartz.scheduler.skipUpdateCheck = true
org.quartz.scheduler.instanceName = Test-Scheduler
org.quartz.scheduler.instanceId = AUTO
#============================================================================
# Configure ThreadPool
#============================================================================
org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool
org.quartz.threadPool.threadCount = 25
org.quartz.threadPool.threadPriority = 5
#============================================================================
# Configure JobStore
#============================================================================
org.quartz.jobStore.misfireThreshold = 60000
org.quartz.jobStore.class = org.quartz.impl.jdbcjobstore.JobStoreTX
org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.StdJDBCDelegate
org.quartz.jobStore.useProperties = true
org.quartz.jobStore.dataSource = quartzDS
org.quartz.jobStore.tablePrefix = QRTZ_
org.quartz.jobStore.isClustered = true
org.quartz.jobStore.clusterCheckinInterval = 20000
Voici mon code:
SchedulerFactory sf = new StdSchedulerFactory();
Scheduler scheduler = sf.getScheduler();
scheduler.start();
JobDetail jobDetail = newJob(job.getClass())
.withIdentity("test-name", "test-group")
.build();
CronTrigger trigger = newTrigger()
.withIdentity("test-name-trigger", "test-group")
.withSchedule(cronSchedule("0 0/1 * * * ?"))
.build();
scheduler.scheduleJob(jobDetail, trigger);
System.out.println(trigger.getNextFireTime());
MODIFIER
Ce qui est intéressant.
1) en mode RAM fonctionne.
2) jdbc avec le cluster de permettre de ne pas travailler et ne parvient pas (ou presque), silencieusement, même si la journalisation est activée. À la sortie du journal, je vois les suivantes:
19:57:29,913 INFO StdSchedulerFactory:1184 - Using default implementation for ThreadExecutor
19:57:29,936 INFO SchedulerSignalerImpl:61 - Initialized Scheduler Signaller of type: class org.quartz.core.SchedulerSignalerImpl
19:57:29,936 INFO QuartzScheduler:240 - Quartz Scheduler v.2.2.1 created.
19:57:29,938 INFO JobStoreTX:667 - Using db table-based data access locking (synchronization).
19:57:29,940 INFO JobStoreTX:59 - JobStoreTX initialized.
19:57:29,941 INFO QuartzScheduler:305 - Scheduler meta-data: Quartz Scheduler (v2.2.1) 'Test-Scheduler' with instanceId 'Michael-PC1405447049916'
Scheduler class: 'org.quartz.core.QuartzScheduler' - running locally.
NOT STARTED.
Currently in standby mode.
Number of jobs executed: 0
Using thread pool 'org.quartz.simpl.SimpleThreadPool' - with 25 threads.
Using job-store 'org.quartz.impl.jdbcjobstore.JobStoreTX' - which supports persistence. and is clustered.
19:57:29,941 INFO StdSchedulerFactory:1339 - Quartz scheduler 'Test-Scheduler' initialized from default resource file in Quartz package: 'quartz.properties'
19:57:29,941 INFO StdSchedulerFactory:1343 - Quartz scheduler version: 2.2.1
19:57:29,995 INFO AbstractPoolBackedDataSource:462 - Initializing c3p0 pool... com.mchange.v2.c3p0.ComboPooledDataSource [ acquireIncrement -> 3, acquireRetryAttempts -> 30, acquireRetryDelay -> 1000, autoCommitOnClose -> false, automaticTestTable -> null, breakAfterAcquireFailure -> false, checkoutTimeout -> 0, connectionCustomizerClassName -> null, connectionTesterClassName -> com.mchange.v2.c3p0.impl.DefaultConnectionTester, dataSourceName -> 1hgeby993gf1xpdmdc44s|7ec4d0, debugUnreturnedConnectionStackTraces -> false, description -> null, driverClass -> com.mysql.jdbc.Driver, factoryClassLocation -> null, forceIgnoreUnresolvedTransactions -> false, identityToken -> 1hgeby993gf1xpdmdc44s|7ec4d0, idleConnectionTestPeriod -> 50, initialPoolSize -> 3, jdbcUrl -> jdbc:mysql://localhost:3306/scheduler, maxAdministrativeTaskTime -> 0, maxConnectionAge -> 0, maxIdleTime -> 0, maxIdleTimeExcessConnections -> 0, maxPoolSize -> 5, maxStatements -> 0, maxStatementsPerConnection -> 120, minPoolSize -> 1, numHelperThreads -> 3, numThreadsAwaitingCheckoutDefaultUser -> 0, preferredTestQuery -> SELECT 1 FROM QRTZ_JOB_DETAILS, properties -> {user=******, password=******}, propertyCycle -> 0, testConnectionOnCheckin -> true, testConnectionOnCheckout -> false, unreturnedConnectionTimeout -> 0, usesTraditionalReflectiveProxies -> false ]
19:57:30,243 DEBUG StdRowLockSemaphore:107 - Lock 'TRIGGER_ACCESS' is desired by: main
19:57:30,262 DEBUG StdRowLockSemaphore:92 - Lock 'TRIGGER_ACCESS' is being obtained: main
19:58:21,328 DEBUG StdRowLockSemaphore:141 - Lock 'TRIGGER_ACCESS' was not obtained by: main - will try again.
19:58:22,329 DEBUG StdRowLockSemaphore:92 - Lock 'TRIGGER_ACCESS' is being obtained: main
19:59:13,389 DEBUG StdRowLockSemaphore:141 - Lock 'TRIGGER_ACCESS' was not obtained by: main - will try again.
19:59:14,389 DEBUG StdRowLockSemaphore:92 - Lock 'TRIGGER_ACCESS' is being obtained: main
Bien, juste que comme j'étais sur le point d'activer le mode cluster encore une fois, j'ai vu de l'exception:
Exception in thread "main" org.quartz.impl.jdbcjobstore.LockException: Failure obtaining db row lock: Lock wait timeout exceeded; try restarting transaction [See nested exception: java.sql.SQLException: Lock wait timeout exceeded; try restarting transaction]
at org.quartz.impl.jdbcjobstore.StdRowLockSemaphore.executeSQL(StdRowLockSemaphore.java:157)
at org.quartz.impl.jdbcjobstore.DBSemaphore.obtainLock(DBSemaphore.java:113)
at org.quartz.impl.jdbcjobstore.JobStoreSupport.executeInNonManagedTXLock(JobStoreSupport.java:3780)
at org.quartz.impl.jdbcjobstore.JobStoreTX.executeInLock(JobStoreTX.java:93)
at org.quartz.impl.jdbcjobstore.JobStoreSupport.clearAllSchedulingData(JobStoreSupport.java:1956)
at org.quartz.core.QuartzScheduler.clear(QuartzScheduler.java:1572)
at org.quartz.impl.StdScheduler.clear(StdScheduler.java:239)
at com.scs.core.cron.TaskRunner.main(TaskRunner.java:52)
3) Dans jdbc mode avec le regroupement désactivé il ne fonctionne pas non plus, mais j'obtiens une exception:
20:04:15,993 DEBUG SimpleSemaphore:132 - Lock 'TRIGGER_ACCESS' retuned by: main
20:04:15,993 DEBUG JobStoreTX:703 - JobStore background threads started (as scheduler was started).
20:04:15,994 INFO QuartzScheduler:575 - Scheduler Test-Scheduler_$_NON_CLUSTERED started.
20:04:15,994 DEBUG JobStoreTX:3933 - MisfireHandler: scanning for misfires...
20:04:16,000 DEBUG JobStoreTX:3182 - Found 0 triggers that missed their scheduled fire-time.
20:04:16,004 DEBUG QuartzSchedulerThread:276 - batch acquisition of 0 triggers
20:04:16,008 DEBUG SimpleSemaphore:81 - Lock 'TRIGGER_ACCESS' is desired by: main
20:04:16,008 DEBUG SimpleSemaphore:88 - Lock 'TRIGGER_ACCESS' is being obtained: main
20:04:16,008 DEBUG SimpleSemaphore:105 - Lock 'TRIGGER_ACCESS' given to: main
20:04:16,052 DEBUG SimpleSemaphore:132 - Lock 'TRIGGER_ACCESS' retuned by: main
Found job: class to.test.cron.ImportProducts
Tue Jul 15 20:05:00 CEST 2014
isStarted=true
isShutdown=false
isInStandbyMode=false
20:04:16,058 DEBUG QuartzSchedulerThread:276 - batch acquisition of 0 triggers
20:04:42,961 ERROR ErrorLogger:2425 - An error occurred while scanning for the next triggers to fire.
org.quartz.JobPersistenceException: Couldn't acquire next trigger: to.test.cron.ImportProducts [See nested exception: java.lang.ClassNotFoundException: to.test.cron.ImportProducts]
at org.quartz.impl.jdbcjobstore.JobStoreSupport.acquireNextTrigger(JobStoreSupport.java:2848)
at org.quartz.impl.jdbcjobstore.JobStoreSupport$40.execute(JobStoreSupport.java:2759)
at org.quartz.impl.jdbcjobstore.JobStoreSupport$40.execute(JobStoreSupport.java:2757)
at org.quartz.impl.jdbcjobstore.JobStoreSupport.executeInNonManagedTXLock(JobStoreSupport.java:3787)
at org.quartz.impl.jdbcjobstore.JobStoreSupport.acquireNextTriggers(JobStoreSupport.java:2756)
at org.quartz.core.QuartzSchedulerThread.run(QuartzSchedulerThread.java:272)
Caused by: java.lang.ClassNotFoundException: to.test.cron.ImportProducts
at java.net.URLClassLoader$1.run(Unknown Source)
at java.net.URLClassLoader$1.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(Unknown Source)
at java.lang.ClassLoader.loadClass(Unknown Source)
at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source)
at java.lang.ClassLoader.loadClass(Unknown Source)
at org.quartz.simpl.InitThreadContextClassLoadHelper.loadClass(InitThreadContextClassLoadHelper.java:72)
at org.quartz.simpl.CascadingClassLoadHelper.loadClass(CascadingClassLoadHelper.java:114)
at org.quartz.simpl.CascadingClassLoadHelper.loadClass(CascadingClassLoadHelper.java:138)
at org.quartz.impl.jdbcjobstore.StdJDBCDelegate.selectJobDetail(StdJDBCDelegate.java:852)
at org.quartz.impl.jdbcjobstore.JobStoreSupport.acquireNextTrigger(JobStoreSupport.java:2816)
... 5 more
Je n'arrive pas à comprendre pourquoi je reçois 3 complètement différents comportements dans les 3 nationalités différentes modes. Surley si la classe peut être trouvé dans la RAM-mode, pourquoi ne devrait-on pas trouver dans jdbc mode? Et pourquoi n'est-il pas d'être connecté en mode cluster? La classe est en fait dans un osgi-module de type. Peut que provoquer un problème (jdbc-mode)? Est-ce que je peux faire, alors que la classe peut être trouvé, comme un passage du chargeur de classe etc à quartz?
Je suis assez perdu maintenant et vraiment reconnaissant de toute aide. Il serait dommage d'avoir à revenir à la norme des tâches cron, surtout que le quartz a tellement plus à offrir.
Merci d'avance pour toute aide,
Michael
OriginalL'auteur michaeldd | 2014-07-14
Vous devez vous connecter pour publier un commentaire.
Il s'agit d'un "problème" avec un travail persistant en magasin. Votre demande apparemment essaie d'ajouter une tâche qui existe déjà dans le travail de magasin, car il a déjà été ajouté à votre application dans le passé. Vous avez deux options:
Vous effacez le contenu de votre travail en magasin lors de l'initialisation de votre application avant de tenter de créer des emplois ou de déclencheurs. Depuis Quartz 2.x, il existe une nouvelle méthode de Planificateur.clear() que vous pouvez utiliser.
Vous de modifier le code de votre application à composer avec le fait que le travail/de déclenchement que vous essayez d'ajouter peut-être déjà présent dans le travail de magasin. S'il est présent, il vous suffit de mettre à jour le travail/déclencher, si nécessaire, ou d'ignorer le travail/déclencheur complètement.
Quand vous pensez à elle, ce Quartz comportement fait réellement sens, parce que les emplois ou de déclencheurs dans l'emploi peut être modifié à partir de l'extérieur de votre demande (par exemple, par des systèmes externes à l'aide de Quartz à distance Api).
Vous pouvez également regarder dans le XMLSchedulingDataProcessorPlugin qui vous permet d'externaliser l'emploi et de déclencher des définitions à partir de votre application dans un fichier XML/ressources et il peut à l'emploi/déclenchement de conflits de nom. Cette l'article fournit un exemple de la structure du fichier XML.
Espère que cette aide.
Je voudrais tout d'abord double-vérifier que le planificateur a en fait été commencé (c'est à dire le Planificateur.isStarted() renvoie la valeur true). Si cela ne résout pas le problème, vous devez activer la journalisation pour le 'org.quartz' catégorie dans votre application de configuration de la journalisation. Si ce n'est pas de vous dire quoi que ce soit, vous devez déboguer le QuartzSchedulerThread pour voir ce qui se passe.
Ok, on dirait que je vais avoir à creuser plus loin: isStarted=true, isShutdown=false, isInStandbyMode=false
Sujet 3), il semble que si le travail de la classe n'a pas pu être chargé par le Quartz. Est le Quartz API chargé par le même chargeur de classe qui se charge de vos catégories d'emplois? Ces erreurs se produisent généralement lorsque le Quartz de l'API est chargé par un partage de serveur d'applications chargeur de classe (par exemple, le Tomcat Commune du chargeur de classe) qui ne voit pas les catégories d'emplois regroupés dans une application déployée (par exemple, dans WEB-INF/classes, WEB-INF/lib). Quartz fournit un support pour plusieurs stratégies quand il s'agit de charger des classes e.g les détails de la tâche) - voir org.quartz.scheduler.classLoadHelper.class Quartz de la propriété.
Pas de problème. Nous utilisons notre propre produit pour le faire 🙂 Merci de vérifier QuartzDesk (www.quartzdesk.com). Même le Lite (gratuit) edition vous permet d'ad-hoc exécuter des travaux hors de leur cadre d'un horaire régulier.
OriginalL'auteur Jan Moravec