Quartz Scheduler
Quartz is a richly featured, open source job scheduling library that can be integrated within virtually any Java application - from the smallest stand-alone application to the largest e-commerce system.
Status of the build:
Quartz is a richly featured, open source job scheduling library that can be integrated within virtually any Java application - from the smallest stand-alone application to the largest e-commerce system.
Status of the build:
The method initDocumentParser() in the XMLSchedulingDataProcessor.java does not forbid DTDs, which allows a context-dependend attacker to perfom an XXE. The vulnerability is confirmed working in version 2.2.3.
I reported this issue to the MITRE cooperation already which assigned the identifier CVE-2019-13990 to this vulnerability. Please confirm the existence of this vulnerability so that the CVE-entry can be completed and published.
The OWASP Foundation provides an XXE Prevention CheatSheet that explains in detail the steps to prevent this security issue.
Credits to Andreas Schoedl for working out the relevant code section affected by this issue.
QuartzSchedulerThread will do as below: for (TriggerKey triggerKey: misfiredTriggers) { OperableTrigger trig = retrieveTrigger(conn, triggerKey); if (trig == null) { continue; }
retrieveTrigger should return null instead of Exception this caused other triggers to be blocked
stalehttp://www.quartz-scheduler.org/documentation/faq.html
What is Quartz? ... Quartz is fault-tolerant ...
But there is a problem with it in some cases.
Reproduced with Quartz 2.2.1 and 2.2.3 (didn't check other versions)
JVM crashes during a job execution (or was stopped for maintenance during a job execution)
Downtime is much bigger than trigger's interval (e.g. > 2 minutes)
Important Quartz tables are TRIGGERS and FIRED_TRIGGERS and theirs states directly after JVM crashed are:
| TRIGGER_NAME | TRIGGER_GROUP | JOB_NAME | JOB_GROUP | NEXT_FIRE_TIME | PREV_FIRE_TIME | TRIGGER_STATE | TRIGGER_TYPE | START_TIME | MISFIRE_INSTR | SCHED_NAME | |-------------:|--------------:|---------:|----------:|---------------:|---------------:|--------------:|-------------:|--------------:|--------------:|-----------:| | test | TestJob | test | TestJob | 1481618100000 | 1481618040000 | BLOCKED | SIMPLE | 1481555640000 | 0 | scheduler |
| ENTRY_ID | TRIGGER_NAME | TRIGGER_GROUP | INSTANCE_NAME | FIRED_TIME | STATE | JOB_NAME | JOB_GROUP | REQUESTS_RECOVERY | SCHED_TIME | IS_NONCONCURRENT | SCHED_NAME | |---------------------------:|-------------:|--------------:|--------------:|--------------:|----------:|---------:|----------:|------------------:|--------------:|-----------------:|-----------:| | NON_CLUSTERED1481617513489 | test | TestJob | NON_CLUSTERED | 1481618049269 | EXECUTING | test | TestJob | 0 | 1481618040000 | 1 | scheduler |
Below are SQL statements for recoverJobs procedure on scheduler.start() and states of TRIGGERS and FIRED_TRIGGERS tables
UPDATE TRIGGERS SET TRIGGER_STATE = 'WAITING'
WHERE SCHED_NAME = 'scheduler' AND (TRIGGER_STATE = 'ACQUIRED' OR TRIGGER_STATE = 'BLOCKED')
-> trigger has updated from BLOCKED to WAITING
UPDATE TRIGGERS SET TRIGGER_STATE = 'PAUSED' WHERE SCHED_NAME = 'scheduler' AND (TRIGGER_STATE = 'PAUSED_BLOCKED' OR TRIGGER_STATE = 'PAUSED_BLOCKED')
// not important
SELECT TRIGGER_NAME, TRIGGER_GROUP FROM TRIGGERS
WHERE SCHED_NAME = 'scheduler' AND NOT (MISFIRE_INSTR = -1) AND NEXT_FIRE_TIME < 1481618263782 AND TRIGGER_STATE = 'WAITING'
ORDER BY NEXT_FIRE_TIME ASC, PRIORITY DESC
-> trigger has been selected as misfired in WAITING state
SELECT * FROM TRIGGERS WHERE SCHED_NAME = 'scheduler' AND TRIGGER_NAME = 'test' AND TRIGGER_GROUP = 'TestJob'
SELECT * FROM SIMPLE_TRIGGERS WHERE SCHED_NAME = 'scheduler' AND TRIGGER_NAME = 'test' AND TRIGGER_GROUP = 'TestJob'
SELECT TRIGGER_NAME FROM TRIGGERS WHERE SCHED_NAME = 'scheduler' AND TRIGGER_NAME = 'test' AND TRIGGER_GROUP = 'TestJob'
SELECT TRIGGER_GROUP FROM PAUSED_TRIGGER_GRPS WHERE SCHED_NAME = 'scheduler' AND TRIGGER_GROUP = 'TestJob'
SELECT TRIGGER_GROUP FROM PAUSED_TRIGGER_GRPS WHERE SCHED_NAME = 'scheduler' AND TRIGGER_GROUP = '_$_ALL_GROUPS_PAUSED_$_'
SELECT * FROM JOB_DETAILS WHERE SCHED_NAME = 'scheduler' AND JOB_NAME = 'test' AND JOB_GROUP = 'TestJob'
// not very important, assume it collects information about misfired trigger and there job
SELECT * FROM FIRED_TRIGGERS
WHERE SCHED_NAME = 'scheduler' AND JOB_NAME = 'test' AND JOB_GROUP = 'TestJob'
-> fired trigger has been selected for misfired trigger
UPDATE TRIGGERS SET JOB_NAME = 'test', JOB_GROUP = 'TestJob', DESCRIPTION = NULL, NEXT_FIRE_TIME = 1481618340000, PREV_FIRE_TIME = 1481618040000,
TRIGGER_STATE = 'BLOCKED', -- !!!! IMPORTANT !!!!
TRIGGER_TYPE = 'SIMPLE', START_TIME = 1481555640000, END_TIME = 0, CALENDAR_NAME = NULL, MISFIRE_INSTR = 0, PRIORITY = 5, JOB_DATA = '<byte[]>'
WHERE SCHED_NAME = 'scheduler' AND TRIGGER_NAME = 'test' AND TRIGGER_GROUP = 'TestJob'
-> (IMPORTANT) trigger which is misfired and fired (because in execution on JVM crash/stop) at the same time
has been updated to BLOCKED state on scheduler start
UPDATE SIMPLE_TRIGGERS SET REPEAT_COUNT = -1, REPEAT_INTERVAL = 60000, TIMES_TRIGGERED = 1045 WHERE SCHED_NAME = 'scheduler' AND TRIGGER_NAME = 'test' AND TRIGGER_GROUP = 'TestJob'
// not important
SELECT * FROM FIRED_TRIGGERS WHERE SCHED_NAME = 'scheduler' AND INSTANCE_NAME = 'NON_CLUSTERED' AND REQUESTS_RECOVERY = 1
// not important, assume handling triggers requested recovery
SELECT TRIGGER_NAME, TRIGGER_GROUP FROM TRIGGERS WHERE SCHED_NAME = 'scheduler' AND TRIGGER_STATE = 'COMPLETE'
// not important, assume select to remove stale triggers
DELETE FROM FIRED_TRIGGERS WHERE SCHED_NAME = 'scheduler'
-> fired triggers are removed
| TRIGGER_NAME | TRIGGER_GROUP | JOB_NAME | JOB_GROUP | NEXT_FIRE_TIME | PREV_FIRE_TIME | TRIGGER_STATE | TRIGGER_TYPE | START_TIME | MISFIRE_INSTR | SCHED_NAME | |-------------:|--------------:|---------:|----------:|---------------:|---------------:|--------------:|-------------:|--------------:|--------------:|-----------:| | test | TestJob | test | TestJob | 1481618100000 | 1481618040000 | BLOCKED | SIMPLE | 1481555640000 | 0 | scheduler |
No rows
Job has repeat trigger but in BLOCKED state, trigger will not fired, job will not executed at least until JVM is not restarted again
Below are SQL statements for recoverJobs procedure on scheduler.start() and states of TRIGGERS and FIRED_TRIGGERS tables
UPDATE TRIGGERS SET TRIGGER_STATE = 'WAITING'
WHERE SCHED_NAME = 'scheduler' AND (TRIGGER_STATE = 'ACQUIRED' OR TRIGGER_STATE = 'BLOCKED')
-> TRIGGER has updated from BLOCKED to WAITING
UPDATE TRIGGERS SET TRIGGER_STATE = 'PAUSED' WHERE SCHED_NAME = 'scheduler' AND (TRIGGER_STATE = 'PAUSED_BLOCKED' OR TRIGGER_STATE = 'PAUSED_BLOCKED')
// not important
SELECT TRIGGER_NAME, TRIGGER_GROUP FROM TRIGGERS
WHERE SCHED_NAME = 'scheduler' AND NOT (MISFIRE_INSTR = -1) AND NEXT_FIRE_TIME < 1481621819212 AND TRIGGER_STATE = 'WAITING'
ORDER BY NEXT_FIRE_TIME ASC, PRIORITY DESC
-> trigger has been selected as misfired in WAITING state
SELECT * FROM TRIGGERS WHERE SCHED_NAME = 'scheduler' AND TRIGGER_NAME = 'test' AND TRIGGER_GROUP = 'TestJob'
SELECT * FROM SIMPLE_TRIGGERS WHERE SCHED_NAME = 'scheduler' AND TRIGGER_NAME = 'test' AND TRIGGER_GROUP = 'TestJob'
SELECT TRIGGER_NAME FROM TRIGGERS WHERE SCHED_NAME = 'scheduler' AND TRIGGER_NAME = 'test' AND TRIGGER_GROUP = 'TestJob'
SELECT TRIGGER_GROUP FROM PAUSED_TRIGGER_GRPS WHERE SCHED_NAME = 'scheduler' AND TRIGGER_GROUP = 'TestJob'
SELECT TRIGGER_GROUP FROM PAUSED_TRIGGER_GRPS WHERE SCHED_NAME = 'scheduler' AND TRIGGER_GROUP = '_$_ALL_GROUPS_PAUSED_$_'
SELECT * FROM JOB_DETAILS WHERE SCHED_NAME = 'scheduler' AND JOB_NAME = 'test' AND JOB_GROUP = 'TestJob'
// not very important, assume it collects information about misfired trigger and there job
SELECT * FROM FIRED_TRIGGERS
WHERE SCHED_NAME = 'scheduler' AND JOB_NAME = 'test' AND JOB_GROUP = 'TestJob'
-> fired trigger has been selected for misfired trigger
UPDATE TRIGGERS SET JOB_NAME = 'test', JOB_GROUP = 'TestJob', DESCRIPTION = NULL, NEXT_FIRE_TIME = 1481621880000, PREV_FIRE_TIME = 1481618040000,
TRIGGER_STATE = 'WAITING', -- !!! OK without fired trigger !!!
TRIGGER_TYPE = 'SIMPLE', START_TIME = 1481555640000, END_TIME = 0, CALENDAR_NAME = NULL, MISFIRE_INSTR = 0, PRIORITY = 5, JOB_DATA = '<byte[]>'
WHERE SCHED_NAME = 'scheduler' AND TRIGGER_NAME = 'test' AND TRIGGER_GROUP = 'TestJob'
-> now it is OK because there is not fired trigger
UPDATE SIMPLE_TRIGGERS SET REPEAT_COUNT = -1, REPEAT_INTERVAL = 60000, TIMES_TRIGGERED = 1104 WHERE SCHED_NAME = 'scheduler' AND TRIGGER_NAME = 'test' AND TRIGGER_GROUP = 'TestJob'
SELECT * FROM FIRED_TRIGGERS WHERE SCHED_NAME = 'scheduler' AND INSTANCE_NAME = 'NON_CLUSTERED' AND REQUESTS_RECOVERY = 1
SELECT TRIGGER_NAME, TRIGGER_GROUP FROM TRIGGERS WHERE SCHED_NAME = 'scheduler' AND TRIGGER_STATE = 'COMPLETE'
DELETE FROM FIRED_TRIGGERS WHERE SCHED_NAME = 'scheduler'
// not important
Job with repeat trigger is executed according trigger definition
BUT BELIEVE it is NOT workaround to restart JVM twice to solve problem. There can be another jobs/triggers in such situation in second restart.
Setting request recovery to true is not workaround either, in our case we definitely do not need recovery request but job must be executed according trigger interval after JVM restart
Perhaps workaround to use (before it is fixed in Quartz) is:
on JVM starting up but before scheduler started
if (!scheduler.getMetaData().isJobStoreClustered()) {
// delete all rows from FIRED_TRIGGERS
// which do not request recovery
DELETE FROM FIRED_TRIGGERS
WHERE SCHED_NAME = scheduler.name AND REQUESTS_RECOVERY = 0
}
scheduler.start()
See pull request #94
I have a need to use recurrence rules to define quartz jobs. I read https://jira.terracotta.org/jira/browse/QTZ-252 discussion about it and decide to implement over the solution suggested in the issue. I've also included tests for the new trigger. (Commit checked this time)
In clustered mode,if do not use acquireTriggersWithinLock properties will appear ABA problem.
here is the quartz source code:
public List<OperableTrigger> acquireNextTriggers(final long noLaterThan, final int maxCount, final long timeWindow)
throws JobPersistenceException {
if(isAcquireTriggersWithinLock() || maxCount > 1) {
lockName = LOCK_TRIGGER_ACCESS;
} else {
lockName = null;
}
...
protected List<OperableTrigger> acquireNextTrigger(Connection conn, long noLaterThan, int maxCount, long timeWindow)
throws JobPersistenceException {
...
do {
currentLoopCount ++;
try {
List<TriggerKey> keys = getDelegate().selectTriggerToAcquire(conn, noLaterThan + timeWindow, getMisfireTime(), maxCount);
// No trigger is ready to fire yet.
if (keys == null || keys.size() == 0)
return acquiredTriggers;
long batchEnd = noLaterThan;
for(TriggerKey triggerKey: keys) {
...
// We now have a acquired trigger, let's add to return list.
// If our trigger was no longer in the expected state, try a new one.
int rowsUpdated = getDelegate().updateTriggerStateFromOtherState(conn, triggerKey, STATE_ACQUIRED, STATE_WAITING);
if (rowsUpdated <= 0) {
continue; // next trigger
}
nextTrigger.setFireInstanceId(getFiredTriggerRecordId());
getDelegate().insertFiredTrigger(conn, nextTrigger, STATE_ACQUIRED, null);
if(acquiredTriggers.isEmpty()) {
batchEnd = Math.max(nextTrigger.getNextFireTime().getTime(), System.currentTimeMillis()) + timeWindow;
}
acquiredTriggers.add(nextTrigger);
}
...
} catch (Exception e) {
throw new JobPersistenceException(
"Couldn't acquire next trigger: " + e.getMessage(), e);
}
} while (true);
// Return the acquired trigger list
return acquiredTriggers;
}
In my configuration, i do not set the batchTriggerAcquisitionMaxCount property, so the default value is 1 and maxCount always equals 1. so acquireNextTriggers() method just have the TRIGGERS table row locks. Then the ABA problem will appear, cluster Server_A get trigger_a, cluster Server_B also can get trigger_a in the acquireNextTrigger() method with selectTriggerToAcquire() method, Server_A change trigger_a status WAITING->ACQUIRED->EXECUTING->WAITING, in this situation Server_B execute updateTriggerStateFromOtherState() method will success, finally the trigger_a will be fired twice.
I think this is important infomation, but clustering depoly document not mention it. Theoretically, set acquireTriggersWithinLock properties is not enough. TRIGGERS table may be need add version_number field to avoid this problem.
Here is my two server debug log, Server_A:
2017-02-17 20:58:12.974 [DEBUG] [org.quartz.core.QuartzSchedulerThread:276] batch acquisition of 0 triggers 2017-02-17 20:58:39.996 [DEBUG] [org.quartz.core.QuartzSchedulerThread:276] batch acquisition of 0 triggers 2017-02-17 20:59:07.272 [DEBUG] [org.quartz.core.QuartzSchedulerThread:276] batch acquisition of 0 triggers 2017-02-17 20:59:31.635 [DEBUG] [org.quartz.core.QuartzSchedulerThread:276] batch acquisition of 1 triggers 2017-02-17 21:00:00.002 [DEBUG] [org.quartz.impl.jdbcjobstore.StdRowLockSemaphore:107] Lock 'TRIGGER_ACCESS' is desired by: scheduler_QuartzSchedulerThread 2017-02-17 21:00:00.002 [DEBUG] [org.quartz.impl.jdbcjobstore.StdRowLockSemaphore:92] Lock 'TRIGGER_ACCESS' is being obtained: scheduler_QuartzSchedulerThread 2017-02-17 21:00:00.003 [DEBUG] [org.quartz.impl.jdbcjobstore.StdRowLockSemaphore:116] Lock 'TRIGGER_ACCESS' given to: scheduler_QuartzSchedulerThread 2017-02-17 21:00:00.008 [DEBUG] [org.quartz.impl.jdbcjobstore.StdRowLockSemaphore:141] Lock 'TRIGGER_ACCESS' returned by: scheduler_QuartzSchedulerThread 2017-02-17 21:00:00.008 [DEBUG] [org.quartz.core.JobRunShell:201] Calling execute on job DEFAULT.jobDetail 2017-02-17 21:00:00.013 [DEBUG] [org.apache.http.client.protocol.RequestAddCookies:122] CookieSpec selected: best-match 2017-02-17 21:00:00.013 [DEBUG] [org.apache.http.client.protocol.RequestAuthCache:75] Auth cache not set in the context 2017-02-17 21:00:00.013 [DEBUG] [org.apache.http.impl.conn.PoolingHttpClientConnectionManager:215] Connection request: [route: {}->http://ip:80][total kept alive: 0; route allocated: 0 of 2; total allocated: 0 of 20]
Server_B:
2017-02-17 20:58:11.974 [DEBUG] [org.quartz.core.QuartzSchedulerThread:276] batch acquisition of 0 triggers 2017-02-17 20:58:38.915 [DEBUG] [org.quartz.core.QuartzSchedulerThread:276] batch acquisition of 0 triggers 2017-02-17 20:59:08.128 [DEBUG] [org.quartz.core.QuartzSchedulerThread:276] batch acquisition of 0 triggers 2017-02-17 20:59:33.916 [DEBUG] [org.quartz.core.QuartzSchedulerThread:276] batch acquisition of 1 triggers 2017-02-17 21:00:00.001 [DEBUG] [org.quartz.impl.jdbcjobstore.StdRowLockSemaphore:107] Lock 'TRIGGER_ACCESS' is desired by: scheduler_QuartzSchedulerThread 2017-02-17 21:00:00.001 [DEBUG] [org.quartz.impl.jdbcjobstore.StdRowLockSemaphore:92] Lock 'TRIGGER_ACCESS' is being obtained: scheduler_QuartzSchedulerThread 2017-02-17 21:00:00.002 [DEBUG] [org.quartz.impl.jdbcjobstore.StdRowLockSemaphore:116] Lock 'TRIGGER_ACCESS' given to: scheduler_QuartzSchedulerThread 2017-02-17 21:00:00.008 [DEBUG] [org.quartz.impl.jdbcjobstore.StdRowLockSemaphore:141] Lock 'TRIGGER_ACCESS' returned by: scheduler_QuartzSchedulerThread 2017-02-17 21:00:00.009 [DEBUG] [org.quartz.core.JobRunShell:201] Calling execute on job DEFAULT.jobDetail 2017-02-17 21:00:00.013 [DEBUG] [org.quartz.core.QuartzSchedulerThread:276] batch acquisition of 0 triggers 2017-02-17 21:00:00.014 [DEBUG] [org.apache.http.client.protocol.RequestAddCookies:122] CookieSpec selected: best-match 2017-02-17 21:00:00.014 [DEBUG] [org.apache.http.client.protocol.RequestAuthCache:75] Auth cache not set in the context 2017-02-17 21:00:00.014 [DEBUG] [org.apache.http.impl.conn.PoolingHttpClientConnectionManager:215] Connection request: [route: {}->http://ip:80][total kept alive: 0; route allocated: 0 of 2; total allocated: 0 of 20]
My Cron Expression: 00 00 21 17 02 ? 2017
My property configuration:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd">
<bean id="jobDetail" class="org.springframework.scheduling.quartz.JobDetailFactoryBean">
<property name="jobClass" value="com.netease.mail.yanxuan.scheduler.task.JobInvokeService" />
<property name="durability" value="true"/>
</bean>
<bean id="scheduler" lazy-init="false" autowire="no"
class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<property name="jobDetails">
<list>
<ref bean="jobDetail"/>
</list>
</property>
<property name="dataSource" ref="dataSource" />
<property name="overwriteExistingJobs" value="true"/>
<property name="quartzProperties">
<props>
<prop key="org.quartz.scheduler.instanceName">EventScheduler</prop>
<prop key="org.quartz.scheduler.instanceId">AUTO</prop>
<!-- Configure ThreadPool -->
<prop key="org.quartz.threadPool.class">org.quartz.simpl.SimpleThreadPool</prop>
<prop key="org.quartz.threadPool.threadCount">50</prop>
<prop key="org.quartz.threadPool.threadPriority">5</prop>
<prop key="org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread">true</prop>
<!-- Configure JobStore -->
<prop key="org.quartz.jobStore.class">org.quartz.impl.jdbcjobstore.JobStoreCMT</prop>
<prop key="org.quartz.jobStore.misfireThreshold">60000</prop>
<prop key="org.quartz.jobStore.driverDelegateClass">org.quartz.impl.jdbcjobstore.StdJDBCDelegate</prop>
<prop key="org.quartz.jobStore.tablePrefix">QRTZ_</prop>
<prop key="org.quartz.jobStore.maxMisfiresToHandleAtATime">10</prop>
<prop key="org.quartz.jobStore.isClustered">true</prop>
<prop key="org.quartz.jobStore.clusterCheckinInterval">20000</prop>
<prop key="org.quartz.jobStore.dontSetAutoCommitFalse">true</prop>
<prop key="org.quartz.jobStore.txIsolationLevelSerializable">false</prop>
<prop key="org.quartz.jobStore.useProperties">false</prop>
</props>
</property>
<property name="applicationContextSchedulerContextKey" value="applicationContext" />
</bean>
</beans>
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz</artifactId>
<version>2.2.1</version>
</dependency>
Dear Quartz Team,
We are using Quartz 2.2.1 in clustered-mode with JDBC job store to schedule jobs marked as @DisallowConcurrentExecution
.
We have observed that occasionally triggers are getting stuck in trigger state BLOCKED
without ever recovering automatically. Looking into the job store DB tables, the pattern is always the same:
The TRIGGER_STATE
on <PREFIX>_TRIGGERS
is in state BLOCKED
There is no corresponding record in <PREFIX>_FIRED_TRIGGERS
Obviously org.quartz.impl.jdbcjobstore.JobStoreSupport.clusterRecover(Connection, List<SchedulerStateRecord>)
will not recover such triggers, so the only way to get out of this inconsistent state is to manually set the TRIGGER_STATE
back to WAITING
.
It is not yet clear under which circumstances this error occurs. However, our log files indicate that jobs getting stuck coincides with temporary database problems.
Below you can find an example of a NullPointerException
in org.quartz.impl.jdbcjobstore.JobStoreSupport.triggersFired(List<OperableTrigger>)
. The exception itself was caused somewhere in the JDBC driver (Sybase jConnect) when trying to invoke rollback()
on a JDBC connection. The log entry’s timestamp correlates exactly with the time the trigger got stuck.
2017 05 01 20:20:02#+00#ERROR#org.quartz.core.QuartzSchedulerThread##anonymous#ItOpScheduler_Clustered_QuartzSchedulerThread#Runtime error occurred in main trigger firing loop.java.lang.NullPointerException: while trying to invoke the method com.sybase.jdbc4.tds.TdsCursor.setRowNum(int) of a null object loaded from field com.sybase.jdbc4.tds.CurInfo3Token._cursor of an object loaded from local variable 'this'
at com.sybase.jdbc4.tds.CurInfo3Token.getMetaInformation(CurInfo3Token.java:85)
at com.sybase.jdbc4.tds.CurInfoToken.<init>(CurInfoToken.java:130)
at com.sybase.jdbc4.tds.CurInfo3Token.<init>(CurInfo3Token.java:45)
at com.sybase.jdbc4.tds.Tds.nextResult(Tds.java:3239)
at com.sybase.jdbc4.tds.Tds.readCommandResults(Tds.java:4459)
at com.sybase.jdbc4.tds.Tds.doCommand(Tds.java:4444)
at com.sybase.jdbc4.tds.Tds.endTransaction(Tds.java:2602)
at com.sybase.jdbc4.jdbc.SybConnection.rollback(SybConnection.java:1953)
at sun.reflect.GeneratedMethodAccessor492.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at com.sap.core.persistence.jdbc.trace.TraceableBase$1.invoke(TraceableBase.java:44)
at com.sun.proxy.$Proxy17.rollback(Unknown Source)
at com.sap.core.persistence.jdbc.trace.TraceableConnection.rollback(TraceableConnection.java:239)
at org.apache.commons.dbcp.DelegatingConnection.rollback(DelegatingConnection.java:368)
at org.apache.commons.dbcp.DelegatingConnection.rollback(DelegatingConnection.java:368)
at org.apache.commons.dbcp.PoolingDataSource$PoolGuardConnectionWrapper.rollback(PoolingDataSource.java:323)
at sun.reflect.GeneratedMethodAccessor492.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at org.quartz.impl.jdbcjobstore.AttributeRestoringConnectionInvocationHandler.invoke(AttributeRestoringConnectionInvocationHandler.java:73)
at com.sun.proxy.$Proxy143.rollback(Unknown Source)
at org.quartz.impl.jdbcjobstore.JobStoreSupport.rollbackConnection(JobStoreSupport.java:3658)
at org.quartz.impl.jdbcjobstore.JobStoreSupport.executeInNonManagedTXLock(JobStoreSupport.java:3817)
at org.quartz.impl.jdbcjobstore.JobStoreSupport.triggersFired(JobStoreSupport.java:2908)
at org.quartz.core.QuartzSchedulerThread.run(QuartzSchedulerThread.java:336)
|
Please let me know if you need additional details.
Thanks for your support, Sebastian
Same as https://jira.terracotta.org/jira/browse/QTZ-258. Just porting it to GitHub for tracking.
Use-case: We use quartz scheduler (2.0.2) in clustered mode and have a below use case . There are about total 30 jobs and we have org.quartz.threadPool.threadCount=25. This limit gets applied to all the jobs. However we have 3-4 jobs that can be sometimes very long running and resource intensive (not always). So we want to put a limit on the number of these jobs running parallel on a node and cluster.
This would be really helpful.
staleHi, can someone tell me if this project currently abandoned ... or is this continued because my impression based on the commit history etc. it looks like the project is not continued any more?
I've been digging into a .NET version's problem when database encounters a transient error, like a connectivity problem and thus should be retried. If you look at the code:
https://github.com/quartz-scheduler/quartz/blob/d42fb7770f287afbf91f6629d90e7698761ad7d8/quartz-core/src/main/java/org/quartz/impl/jdbcjobstore/JobStoreSupport.java#L2976-L3020
All exceptions are caught in main txCallback and thus I don't see a way how the txValidator logic would ever be called. This will mean that this operation is not retried, unlike the acquireNextTriggers which allows exceptions to bubble up:
https://github.com/quartz-scheduler/quartz/blob/d42fb7770f287afbf91f6629d90e7698761ad7d8/quartz-core/src/main/java/org/quartz/impl/jdbcjobstore/JobStoreSupport.java#L2802-L2826
So before changing the behavior on .NET side I was hoping to get some feedback from Java side. Should the errors be allowed to bubble up or is the txValidator just redundant?
staleIt would be nice to able to configure certain specific jobs to allows run in a specific host name in cluster mode.
Currently users would have to write this logic into their job implementation to skip the work if host names match to some known list.
Other work around is not to use cluster env and place jobs into individual standalone schedulers.
staleMotivation:
Lack of support job services in OSGi framework when job store set to JobStoreTX/JobStoreCMT
Modifications:
Create org.quartz.osgi package that contains follow features:
- Initialize Quartz bundle with Activator
- Tracking register/unregister of job services
- Provide ClassLoaderHelper that can load classes of
job services from other bundles
Modify org.quartz.simpl.CascadingClassLoadHelper.java:
- Add BundleClassLoaderHelper to end of loaders list
Modify quartz-core/pom.xml:
- Add Bundle-Activator tag
- Modify Private-Package
Add .gitignore file that to ignore IDE files and etc.
Result:
The Quartz support job schedule when OSGi job services configured with
JobStoreTX/JobStoreCMT
Quartz 2.3.2
When using quartz jobs.xml for defining jobs and cron triggers, option to set misfire-instruction
as MISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY
is not available in the current xsd schema.
Code snippet from existing job_scheduling_data_2_0.xsd file:
<xs:simpleType name="cron-trigger-misfire-instructionType">
<xs:annotation>
<xs:documentation>Cron Trigger Misfire Instructions</xs:documentation>
</xs:annotation>
<xs:restriction base="xs:string">
<xs:pattern value="MISFIRE_INSTRUCTION_SMART_POLICY"/>
<xs:pattern value="MISFIRE_INSTRUCTION_DO_NOTHING"/>
<xs:pattern value="MISFIRE_INSTRUCTION_FIRE_ONCE_NOW"/>
</xs:restriction>
</xs:simpleType>
Please add this misfire instruction type in xsd schema.
An ending paragraph tag
was removed.In submitting this contribution, I agree to the current Software AG contributor agreement as referred to here: https://github.com/quartz-scheduler/contributing/blob/main/CONTRIBUTING.md
This PR...
git commit -s
on my commits.
(If you're not using command-line, you can use a browser extension )Fixes #
Hello,
Recently Mongo has released a JDBC driver for their Atlas Services.
This is the reference site for the mongo JDBC driver: www.mongodb.com/docs/atlas/data-federation/query/sql/drivers/jdbc/connect
This is the maven artifact: https://search.maven.org/artifact/org.mongodb/mongodb-jdbc
For the latest version, which at the time of writing this issue is version 2.0.1, the driver Class Name is: com.mongodb.jdbc.MongoDriver
Can you add support for this driver? i.e. create a suitable SQL file here? https://github.com/quartz-scheduler/quartz/tree/master/quartz-core/src/main/resources/org/quartz/impl/jdbcjobstore
Any help provided is appreciated. Thanks in advance, Erik
--- maven-enforcer-plugin:3.1.0:enforce (default-cli) @ xxx-ear --- Downloading from central: https://repo.maven.apache.org/maven2/org/quartz-scheduler/internal/quartz-core/2.3.2/quartz-core-2.3.2.pom [WARNING] Rule 0: org.apache.maven.plugins.enforcer.DependencyConvergence failed with message: Could not build dependency tree Could not collect dependencies:
In CalendarIntervalTriggerTest, references to the invalid 'CEST' timezone are failing over silently to GMT, potentially making the results of the test invalid.
https://github.com/quartz-scheduler/quartz/blob/ff348f62ece41275555b45dba5a4073c910fbeab/quartz-core/src/test/java/org/quartz/CalendarIntervalTriggerTest.java#L373
https://github.com/quartz-scheduler/quartz/blob/ff348f62ece41275555b45dba5a4073c910fbeab/quartz-core/src/test/java/org/quartz/CalendarIntervalTriggerTest.java#L384
Are we certain that daylight savings transitions actually working?
Kind regards, Joshua J. A. Harwood
Signed-off-by: lokeshAlamuri [email protected]
In submitting this contribution, I agree to the current Software AG contributor agreement as referred to here: https://github.com/quartz-scheduler/contributing/blob/main/CONTRIBUTING.md
This PR...
git commit -s
on my commits.
(If you're not using command-line, you can use a browser extension )Fixes #
This a bug fix release containing fixes for:
THIS RELEASE REQUIRES JDK7
db-scheduler Task-scheduler for Java that was inspired by the need for a clustered java.util.concurrent.ScheduledExecutorService simpler than Quartz.
Daily Mail Subscription Service POC Implemented using Java Spring-boot and Quartz Scheduler Working Application Exposing 3 endpoints /subscription/cre
Spring Boot Quartz Scheduler : Building an Email Scheduling Requirements Java - 8 Maven - 3.x.x > MySQL - 5.x.x > Steps to Setup 1. Clone the applicat
Redisson - Redis Java client with features of In-Memory Data Grid Quick start | Documentation | Javadocs | Changelog | Code examples | FAQs | Report a
Wisp Scheduler Wisp is a library for managing the execution of recurring Java jobs. It works like the Java class ScheduledThreadPoolExecutor, but it c
db-scheduler Task-scheduler for Java that was inspired by the need for a clustered java.util.concurrent.ScheduledExecutorService simpler than Quartz.
Redisson - Redis Java client with features of In-Memory Data Grid Quick start | Documentation | Javadocs | Changelog | Code examples | FAQs | Report a
cglib Byte Code Generation Library is high level API to generate and transform JAVA byte code. It is used by AOP, testing, data access frameworks to g
Checkstyle is a tool for checking Java source code for adherence to a Code Standard or set of validation rules (best practices). Members chat: Contrib
Vavr is an object-functional language extension to Java 8, which aims to reduce the lines of code and increase code quality. It provides persistent co
CK CK calculates class-level and method-level code metrics in Java projects by means of static analysis (i.e. no need for compiled code). Currently, i
mobsfscan is a static analysis tool that can find insecure code patterns in your Android and iOS source code. Supports Java, Kotlin, Swift, and Objective C Code. mobsfscan uses MobSF static analysis rules and is powered by semgrep and libsast pattern matcher.
Orienteer What is Orienteer Orienteer is Business Application Platform: Easy creation of business applications Extendable to fit your needs Dynamic da
FRC 2022 Team 5468's 2022 FRC robot code. This code is written in Java and is based off of WPILib's Java control system and utilizes a command based s
FTC Code Organizer This template created by team 19458 Equilibrium.exe makes it easy to keep your code organized and allows the Autonomous and TeleOp
NullAway: Fast Annotation-Based Null Checking for Java NullAway is a tool to help eliminate NullPointerExceptions (NPEs) in your Java code. To use Nul
PMD About PMD is a source code analyzer. It finds common programming flaws like unused variables, empty catch blocks, unnecessary object creation, and
Code Quality and Security for Java This SonarSource project is a code analyzer for Java projects. Information about the analysis of Java features is a
Spoon Spoon is an open-source library to analyze, rewrite, transform, transpile Java source code. It parses source files to build a well-designed AST
SpotBugs is the spiritual successor of FindBugs, carrying on from the point where it left off with support of its community. SpotBugs is licensed unde