Quartz XML plugin reschedules fired triggers after

2019-08-08 11:00发布

问题:

I am using XML Scheduling Plugin (XMLSchedulingDataProcessorPlugin) to create several jobs and triggers on startup in JDBC job store in quartz-scheduler. This works fine but I have a problem with simple triggers configured to run only once.

When such a trigger fires, it is removed from the database as there is no next fire time. So far so good. Unfortunately when I restart the application the plugin can't find that trigger so it is reinserted again. Because I use MISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY this job is fired again and again removed from the database. Restarting the application repeats the whole process.

Obviously I want my trigger to fire only once. Is it possible to keep fired triggers in the database even if they don't have next fire time? Or maybe this can be solved in a different way? Excerpt from my quartz_data.xml file:

<processing-directives>
    <overwrite-existing-data>false</overwrite-existing-data>
    <ignore-duplicates>true</ignore-duplicates>
</processing-directives>

<schedule>

    <trigger>
        <simple>
            <!-- ... -->
            <start-time>2012-05-10T07:00:00Z</start-time>
            <repeat-count>0</repeat-count>
            <repeat-interval>0</repeat-interval>
        </simple>
    </trigger>

Note that there is a problem with all triggers that reached the last execution and hence were deleted from db.

回答1:

I ended up extending StdJDBCDelegate and overriding deleteTrigger() to be no-op:

package com.example;

class DurableTriggersDriverDelegate extends StdJDBCDelegate {

    public DurableTriggersDriverDelegate(Logger logger, String tablePrefix, String schedName, String instanceId, ClassLoadHelper classLoadHelper) {
        super(logger, tablePrefix, schedName, instanceId, classLoadHelper);
    }

    public DurableTriggersDriverDelegate(Logger logger, String tablePrefix, String schedName, String instanceId, ClassLoadHelper classLoadHelper, Boolean useProperties) {
        super(logger, tablePrefix, schedName, instanceId, classLoadHelper, useProperties);
    }

    @Override
    public int deleteTrigger(Connection conn, TriggerKey triggerKey) throws SQLException {
        this.logger.debug("deleteTrigger(" + conn + ") skipped");
        return 1;
    }
}

The new implementation can be easily plugged-in via quartz.properties:

org.quartz.jobStore.driverDelegateClass=com.example.DurableTriggersDriverDelegate

This solution has several drawbacks:

  • the database keeps growing and growing, not deleting fired triggers

  • deleting job is not possible since it first tries to delete all triggers (but this is not performed) and constraint violation occurs when trying to delete the job details itself

However it solved my original problem.