I have a single threaded executor which reads emaling jobs from a blocking queue as I have to send emails sequentially. Sometimes the java mail sender's sendMail() call hangs up. Since I have just 1 thread sending emails, I don't want to freeze this indefinitely when mail server call hangs.
So, effectively I want to run the emailing tasks with a defined timeout after which it should be cancelled.
The way I have done this is with Java 8 Future class. So I submit the task to my single threaded executor, get the future object in return and then schedule future.cancel() in a separate scheduledExecutor. With the scheduledExecutor, my main thread which is dequeing the emailing jobs from the blocking queue remains async.
But this approach has a problem. Let's say there are 5 objects to be emailed sitting in the blocking queue. And let's assume I have a timeout of 5 secs after which future.cancel() would be called. My async dequeuing thread loops through quickly and puts all 5 objects into the single threaded executor's queue. And when my single thread picks the first job and calls JavaMail's->sendMail(), the call hangs. After 5 secs, the future.cancel() would be called on this task. But my other 4 jobs were also in the executor's queue for the last 5 secs, so their future.cancel() would also be called even before they were processed by the single thread!
Here is my existing implementation
// process sequentially using single 'EmailMain'thread.
Future future = singleThreadExecutor.submit( () -> {
try {
mailService.sendEmail( tradeConfirmationInputFields, tradeConfirmFile );
} catch ( MessagingException | IOException e ) {
log.error( "Found error", e );
return;
}
} );
// timeout the single 'EmailMain' thread if not completed within allowed time.
taskTimeoutScheduledExecutor.schedule( () -> {
future.cancel( true );
}, 5000L, TimeUnit.MILLISECONDS );
} catch ( InterruptedException e ) {
log.error( "Error while emailing tradeConfirmation", e );
}
I want each of emailing jobs to to be processed through the'EmailMain' single thread in sequence and the timer for their timeout to start when the single threads starts processing them and NOT when the jobs are added to the singleThreadedExecutor's queue. Is there any clean solution in Java 8? I know in Java 9, there is some simple option like the below (taken from
https://www.deadcoderising.com/java-9-handle-timeouts-asynchronously-using-completablefutures-ortimeout-and-completeontimeout/
):
CompletableFuture.supplyAsync(this::getArticles)
.orTimeout(1, TimeUnit.MINUTES);