package io.cattle.platform.async.retry.impl; import io.cattle.platform.async.retry.CancelRetryException; import io.cattle.platform.async.retry.Retry; import io.cattle.platform.async.retry.RetryTimeoutService; import io.cattle.platform.async.utils.TimeoutException; import io.cattle.platform.util.concurrent.DelayedObject; import java.util.concurrent.DelayQueue; import java.util.concurrent.ExecutorService; import java.util.concurrent.Future; import org.apache.cloudstack.managed.context.NoExceptionRunnable; import com.google.common.util.concurrent.SettableFuture; public class RetryTimeoutServiceImpl implements RetryTimeoutService { DelayQueue<DelayedObject<Retry>> retryQueue = new DelayQueue<DelayedObject<Retry>>(); ExecutorService executorService; @Override public Object submit(Retry retry) { return queue(retry); } public void retry() { DelayedObject<Retry> delayed = retryQueue.poll(); while (delayed != null) { final Retry retry = delayed.getObject(); if (retry.isKeepalive()) { retry.setKeepalive(false); queue(retry); } else { retry.increment(); if (retry.getRetryCount() >= retry.getRetries()) { Future<?> future = retry.getFuture(); if (future instanceof SettableFuture) { ((SettableFuture<?>) future).setException(new TimeoutException()); } else { future.cancel(true); } } else { executorService.execute(new Runnable() { @Override public void run() { queue(retry); final Runnable run = retry.getRunnable(); if (run != null) { new NoExceptionRunnable() { @Override protected void doRun() throws Exception { try { run.run(); } catch (CancelRetryException e) { completed(retry); } } }.run(); } } }); } } delayed = retryQueue.poll(); } } protected DelayedObject<Retry> queue(Retry retry) { DelayedObject<Retry> delayed = new DelayedObject<Retry>(System.currentTimeMillis() + retry.getTimeoutMillis(), retry); retryQueue.add(delayed); return delayed; } @Override public void completed(Object obj) { retryQueue.remove(obj); } public ExecutorService getExecutorService() { return executorService; } public void setExecutorService(ExecutorService executorService) { this.executorService = executorService; } }