halecommarachel
halecommarachel

Reputation: 124

Service interrupts lib, which then throws InterruptException, but doesn't get caught back in service code

In service code, I have a ScheduledTaskExecutor that starts a job, then a second thread that will cancel that first thread by interrupting it. The job checks for interrupts intermittently, and when the job gets one, it will throw an InterruptException; the service has a try/catch around that job and the catch handles that interruption. My problem is, the catch block is never hit. The job is definitely being interrupted, clear from logging statements on the job side, Once it throws the InterruptException, it's lost and the service can't catch it.

I tried changing Thread.interrupted() to Thread.currentThread().interrupted(), but it didn't fix the problem.

Here's the server-side code that waits for the InterruptException from the job. The interrupt signal is sent to thread via another thread that's scheduled to run after a timeout. I've verified the job does get the interrupt signal.

    private void run() {
        try {
            job.run();
        } catch (InterruptedException e) {
            log.info("Job was interrupted", e);
        } finally {
            duration.stop();
            timer.record(duration);
        }
    }

Here's how the job checks for interrupts:

    public void checkForInterrupt() throws InterruptedException {
        if (Thread.currentThread().isInterrupted()) {
            logger.info(jobName + " was interrupted");
            throw new InterruptedException(jobName + " has been interrupted");
        }
    }

I'm expecting to see this log line log.info("Job was interrupted", e); The last thing I hear from the thread is a log statement that confirms it's interrupt flag has been set, after which it throws the InterruptedException.

Upvotes: 0

Views: 49

Answers (1)

Gray
Gray

Reputation: 116918

The job is definitely being interrupted, clear from logging statements on the job side, Once it throws the InterruptException, it's lost and the service can't catch it.

This is a FAQ. Whenever the InterruptedException is thrown, the interrupt flag on the thread is cleared. If you need the thread to be stilled interrupted, you need to re-interrupt it. That is always the correct pattern when catching InterruptedException. The reason for it is that if you are writing some sort of library, you don't want to swallow the interrupt flag which would mean that the caller won't know if a thread was interrupted. Interrupting a thread is designed as a graceful shutdown (as opposed to the deprecated stop() method). So propagating the interrupt thread is always a good pattern.

For example:

   ...
} catch (InterruptedException e) {
   // we always should re-interrupt the thread when we catch InterruptedException
   Thread.currentThread().interrupt();
   log.info("Job was interrupted", e);

Then when you get back to the caller you can test the interrupt flag:

if (Thread.currentThread().isInterrupted()) {
   ...

If you want a lot more detailed information about the various methods that throw InterruptedException and the various Thread methods that affect the flag, then see my answer: Methods that Clear the Thread.interrupt() flag

For example, folks should never use Thread.interrupted() because that clears the interrupt flag when it tests it. Your use of Thread.currentThread().isInterrupted() is correct.

Upvotes: 0

Related Questions