Quartz Job Annotation @DisallowConcurrentExecution Implementation

Piyush Upadhyay :

I'm new to quartz. I found out about @DisallowConcurrentExecution annotation provided by quartz library and the doc says:

'An annotation that marks a {@link Job} class as one that must not have multiple instances executed concurrently (where instance is based-upon a {@link JobDetail} definition - or in other words based upon a {@link JobKey}).'

The DisallowConcurrentExecution.java is written as:

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface DisallowConcurrentExecution {

}

However, I could not find the implementation that actually takes care of not having concurrent execution for the same job. It is new for me so can someone help me out with explaining the internal implementation logic.

I tried to look up for the usage but only found it in the class MethodInvokingJobDetailFactoryBean.java

pablosaraiva :

Disclaimer: I am NOT involved at the quartz project. All my comments here come from my own investigation of this out of my own curiosity and some information may be missing.

First thing to know is that the JobDetailImpl will check if the annotation is present and make this information available in a method.

/**
 * @return whether the associated Job class carries the {@link DisallowConcurrentExecution} annotation.
 */
public boolean isConcurrentExectionDisallowed() {

    return ClassUtils.isAnnotationPresent(jobClass, DisallowConcurrentExecution.class);
}

Then you can see this method is checked in different parts of the system.

The JobStoreSupport for example checks it here and if the annotation is present it then checks for the block state:

    if (job.isConcurrentExectionDisallowed() && !recovering) { 
        state = checkBlockedState(conn, job.getKey(), state);
    }

And here is where the actual verification happens and to let Quartz decide to run or not to run the Job on that instance.

org.quartz.impl.jdbcjobstore.JobStoreSupport#checkBlockedState

    /**
     * Determines if a Trigger for the given job should be blocked.  
     * State can only transition to STATE_PAUSED_BLOCKED/BLOCKED from 
     * PAUSED/STATE_WAITING respectively.
     * 
     * @return STATE_PAUSED_BLOCKED, BLOCKED, or the currentState. 
     */
    protected String checkBlockedState(
            Connection conn, JobKey jobKey, String currentState)
        throws JobPersistenceException {

    // State can only transition to BLOCKED from PAUSED or WAITING.
    if ((!currentState.equals(STATE_WAITING)) &&
        (!currentState.equals(STATE_PAUSED))) {
        return currentState;
    }

    try {
        List<FiredTriggerRecord> lst = getDelegate().selectFiredTriggerRecordsByJob(conn,
                jobKey.getName(), jobKey.getGroup());

        if (lst.size() > 0) {
            FiredTriggerRecord rec = lst.get(0);
            if (rec.isJobDisallowsConcurrentExecution()) { // OLD_TODO: worry about failed/recovering/volatile job  states?
                return (STATE_PAUSED.equals(currentState)) ? STATE_PAUSED_BLOCKED : STATE_BLOCKED;
            }
        }

        return currentState;
    } catch (SQLException e) {
        throw new JobPersistenceException(
            "Couldn't determine if trigger should be in a blocked state '"
                + jobKey + "': "
                + e.getMessage(), e);
    }

}

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=164272&siteId=1