3

I have some quartz jobs to process some data. I used InterruptableJob interface when writing these jobs. I have to add an interrupt feature to these jobs. When user press the terminate button, this method calling:

@Override
protected void immediatelyTerminate() {

    try {

        String fireInstanceIdToKillJob = "";

        Scheduler scheduler = schedulerFactory.getScheduler();
        List<JobExecutionContext> currentlyExecutingJobs = scheduler.getCurrentlyExecutingJobs();

        for(JobExecutionContext jec : currentlyExecutingJobs) {
            if(jec.getJobDetail().getKey().getName().contains(specificJobKey) {
                fireInstanceIdToKillJob = jec.getFireInstanceId();
            }
        }

        scheduler.interrupt(fireInstanceIdToKillJob);

    } catch (Exception e) {
        logger.debug("error in immediatelyTerminate() method:" + e);
    }
}

scheduler.interrupt calls the interrupt() method that is overridden in a class and this class has also execute method. The class that has overridden interrupt method is like this:

private Thread threadToKill;

@Override
public void execute() {
  threadToKill = Thread.currentThread();
}

@Override
public void interrupt() throws UnableToInterruptJobException {
    try {
        threadToKill.interrupt();
    } catch (Exception e) {
        System.out.println("Exception handled "+e);
    }   
}

But with this code the job doesn't terminate, it continues to working. threadToKill.interrupt(); line doesn't actually terminate the running job.

How can I terminate runnig job?

Vadim Kotov
  • 8,084
  • 8
  • 48
  • 62
İlkay Gunel
  • 712
  • 2
  • 11
  • 24

1 Answers1

0

I got to implement this very same functionality a couple years ago.

Interrupting a thread does not kill it nor stop it. It just activates a flag so the thread knows it has been asked to stop. Most internal methods will check for this and throw an InterruptedException for you to catch it, but some threads will happily ignore any interruption requests.
So, it's up to the job itself to detect this scenario and act accordingly.

Basically, your interrupt() method should set some flag to true, and your job should check this flag from time to time and stop whatever it's doing when it notices the flag is active.
This is how I implemented it:

public clas SomeJob implements InterruptableJob {

    protected AtomicBoolean stopFlag = new AtomicBoolean(false);

    @Override
    public void execute(final JobExecutionContext context) {
        for (Item item : listOfItems) { // whatever long tasks(s) you are doing,
            if (stopFlag.get()) {       // just check for this on every main loop
                logger.error("Job interrupted! Leaving at item: "+item);
                break;
            }
            performTask(item);
        }
        cleanUp();
        return;
    }

    private void performTask(Item item) {
        for(....) {               // another loop,
            if (stopFlag.get()) { // another check
                // ....
                return; // or break, depending on each case
            }
            someInternalProcessing(...);
        }
    }

    @Override
    protected void interrupt() {
        stopFlag.set(true);
    }
}

That's it. Just make sure to clean up, close connections etc. before aborting.

walen
  • 7,103
  • 2
  • 37
  • 58