подключение в фоновом режиме до успеха


У нас есть некоторые обязательные услуги временно когда наш сервер. Поэтому нам нужна какая-то логика переподключения для них, пока они, наконец, вверх. Есть требование иметь также syncronious способ для этого. Вот мой универсальный осуществления для этого через один фоновый поток:

public class RunUntilSuccess {

private static final Logger log = LoggerFactory.getLogger(RunUntilSuccess.class);

private final String processName;
private final Task task;
private final int maxAttempts;
private final int interval;
private final TimeUnit unit;
private final ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();
private AtomicInteger count = new AtomicInteger(0);

public RunUntilSuccess(String processName, Callable<Boolean> task, int interval, TimeUnit unit) {
    this(processName, task, interval, unit, -1);
}

public RunUntilSuccess(String processName, Callable<Boolean> callable, int interval, TimeUnit unit, int maxAttempts) {
    if (callable == null) {
        throw new IllegalArgumentException("Callable cannot be null");
    }
    this.processName = processName;
    this.task = new Task(callable);
    this.interval = Math.max(0, interval);
    if (unit == null) {
        throw new IllegalArgumentException("Unit cannot be null");
    }
    this.unit = unit;
    this.maxAttempts = (maxAttempts > 0) ? maxAttempts : -1;

    start();
}

private void start() {
    log.debug("Starting task execution. " + toString());
    executor.scheduleWithFixedDelay(task, 0, interval, unit);
}

/**
 * Wait until success
 */
public void await() throws InterruptedException {
    while (!executor.awaitTermination(interval, unit)) { }
}

public boolean await(long timeout, TimeUnit unit) throws InterruptedException {
    return executor.awaitTermination(timeout, unit);
}

private boolean isAttemptsLimitReached(int attempt){
    return (maxAttempts > 0) && (attempt >= maxAttempts);
}

@Override
public String toString() {
    final StringBuilder sb = new StringBuilder();
    sb.append(RunUntilSuccess.class.getSimpleName());
    sb.append("{processName='").append(processName).append('\'');
    sb.append(", interval=").append(interval);
    sb.append(", unit=").append(unit);
    sb.append(", maxAttempts=").append(maxAttempts);
    sb.append('}');
    return sb.toString();
}

private class Task implements Runnable {
    private final Callable<Boolean> task;

    public Task(Callable<Boolean> task) {
        this.task = task;
    }

    @Override
    public void run() {
        if (isAttemptsLimitReached(count.getAndIncrement())) {
            log.debug("Task execution finished unsuccessfully after " + count + " attempts.");
            executor.shutdown();
        } else {
            log.debug("Attempt #" + count);
            try {
                if (Boolean.TRUE.equals(task.call())) {
                    log.debug("Attempt #" + count + " was successful. Task execution finished.");
                    executor.shutdown();
                } else {
                    throw new FalseExecution();
                }

            } catch (Exception e) {
                log.error("Attempt #" + count + " failed due to:", e);
            }
        }
    }
}

public static class FalseExecution extends RuntimeException {

}

использование:

Callable<Boolean> connector = new Callable<Boolean>() {
        @Override
        public Boolean call() throws Exception {
            // connect to ...
            return true;
        }
    };

    RunUntilSuccess initializer = new RunUntilSuccess("name", connector, reconnectTimeoutSeconds, TimeUnit.SECONDS);
            // initializer.await() after it for sync way

Это общей задачей и как общая этот код? Спасибо!



Комментарии
3 ответа

дизайн вы вызвать что-то вроде ниже, и вы можете использовать фьючерсы.получить (), чтобы получить результат обратно.

public Boolean call() {

boolean flag = false;
while(!(isAttemptsLimitReached(count.getAndIncrement()) || flag)){

try{

//try connection (with timeout)

}catch(Exception e){
// show exception
}

//continue loop
}

return flag;
}

1
ответ дан 28 декабря 2011 в 10:12 Источник Поделиться

Использование исполнителем.awaitTermination() , кажется мне странным. Вместо этого я стал бы использовать CountDownLatch за, чтобы вызвать успех в заблокированный поток. Но я также согласен с @Крейг П. Motlin, что в будущем имеет смысл.

Кроме того, что конкретный комментарий, вы могли бы рассмотреть некоторые асинхронный метод уведомления для зависимостей, чтобы объявить, что он жив. Что может быть излишним для вашего сценария, но он работал для меня. Реестр Джини обслуживание, сообщений JMS, Hazelcast, обычный широковещательный UDP, и т. д.

2
ответ дан 28 декабря 2011 в 02:12 Источник Поделиться

Когда вы отправляете задание исполнителя ты вернешься в будущее, которое выглядит как соответствующие API вот так как вы хотите, чтобы заблокировать в одном потоке на отложенный расчет.

1
ответ дан 4 июля 2011 в 07:07 Источник Поделиться