AsyncCallableService implements Callable<T> { @Override public T call() { long startTimeInMillis = Calendar.getInstance().getTimeInMillis(); LOG.info("Task execution started at: {}", startTimeInMillis); Future<T> future = executorService.submit(task); while (!taskCompleted(future)) { if (!timeoutExceeded(startTimeInMillis)) { LOG.debug("Retrying task execution in [ {} ] milliseconds.", delay); future = executorService.schedule(task, delay, TimeUnit.MILLISECONDS); } else { LOG.debug("Timout exceeded, cancelling task ... "); if (!future.isDone()) { boolean cancelled = future.cancel(true); LOG.debug("Task cancelled: {}", cancelled); } else { LOG.debug("Task already done."); } LOG.info("Timeout exceeded, task execution won't be retried!"); break; } } LOG.info("Exiting Async task execution with the result: [ {} ]", serviceResult); return serviceResult; } AsyncCallableService(Callable<T> task, long timeout, long delay,
                              ScheduledExecutorService executorService); @Override T call(); Set<Exception> getErrors();  }
@Test public void testCallableServiceShouldExitWhenTaskCompleted() throws Exception { expect(taskMock.call()).andReturn(Boolean.TRUE).times(1); replayAll(); asyncCallableService = new AsyncCallableService<>(taskMock, timeout, delay, Executors.newScheduledThreadPool(2)); Boolean serviceResult = asyncCallableService.call(); verify(); Assert.assertNotNull("Service result must not be null", serviceResult); Assert.assertTrue(serviceResult); }
@Test public void testCallableServiceShouldRetryTaskExecutionTillTimeoutExceededWhenTaskThrowsException() throws Exception { expect(taskMock.call()).andThrow(new IllegalStateException("****************** TESTING ****************")).times(2, 3); replayAll(); asyncCallableService = new AsyncCallableService<>(taskMock, timeout, delay, Executors.newScheduledThreadPool(2)); Boolean serviceResult = asyncCallableService.call(); verify(); Assert.assertNull("Service result must be null", serviceResult); }
@Test public void testShouldAsyncCallableServiceRetryExecutionWhenTaskThrowsException() throws Exception { Callable<Boolean> hangingTask = new Callable<Boolean>() { @Override public Boolean call() throws Exception { throw new IllegalStateException("****************** TESTING ****************"); } }; asyncCallableService = new AsyncCallableService<>(hangingTask, timeout, delay, Executors.newScheduledThreadPool(2)); Boolean serviceResult = asyncCallableService.call(); verify(); Assert.assertNull("Service result must be null", serviceResult); }