com.github.kagkarlsson.scheduler.task.FailureHandler Maven / Gradle / Ivy
Show all versions of db-scheduler Show documentation
/*
* Copyright (C) Gustav Karlsson
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of the License at
*
*
http://www.apache.org/licenses/LICENSE-2.0
*
*
Unless required by applicable law or agreed to in writing, software distributed under the
* License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.github.kagkarlsson.scheduler.task;
import static java.lang.Math.pow;
import static java.lang.Math.round;
import com.github.kagkarlsson.scheduler.task.helper.ScheduleAndData;
import com.github.kagkarlsson.scheduler.task.schedule.Schedule;
import java.time.Duration;
import java.time.Instant;
import java.util.function.BiConsumer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public interface FailureHandler {
void onFailure(ExecutionComplete executionComplete, ExecutionOperations executionOperations);
class ExponentialBackoffFailureHandler implements FailureHandler {
private static final Logger LOG =
LoggerFactory.getLogger(ExponentialBackoffFailureHandler.class);
private static final double DEFAULT_MULTIPLIER = 1.5;
private final Duration sleepDuration;
private final double exponentialRate;
public ExponentialBackoffFailureHandler(Duration sleepDuration) {
this.sleepDuration = sleepDuration;
this.exponentialRate = DEFAULT_MULTIPLIER;
}
public ExponentialBackoffFailureHandler(Duration sleepDuration, double exponentialRate) {
this.sleepDuration = sleepDuration;
this.exponentialRate = exponentialRate;
}
@Override
public void onFailure(
final ExecutionComplete executionComplete,
final ExecutionOperations executionOperations) {
long retryDurationMs =
round(
sleepDuration.toMillis()
* pow(exponentialRate, executionComplete.getExecution().consecutiveFailures));
Instant nextTry = executionComplete.getTimeDone().plusMillis(retryDurationMs);
LOG.debug(
"Execution failed {}. Retrying task {} at {}",
executionComplete.getTimeDone(),
executionComplete.getExecution().taskInstance,
nextTry);
executionOperations.reschedule(executionComplete, nextTry);
}
}
class MaxRetriesFailureHandler implements FailureHandler {
private static final Logger LOG = LoggerFactory.getLogger(MaxRetriesFailureHandler.class);
private final int maxRetries;
private final FailureHandler failureHandler;
private final BiConsumer> maxRetriesExceededHandler;
public MaxRetriesFailureHandler(int maxRetries, FailureHandler failureHandler) {
this(maxRetries, failureHandler, (executionComplete, executionOperations) -> {});
}
public MaxRetriesFailureHandler(
int maxRetries,
FailureHandler failureHandler,
BiConsumer> maxRetriesExceededHandler) {
this.maxRetries = maxRetries;
this.failureHandler = failureHandler;
this.maxRetriesExceededHandler = maxRetriesExceededHandler;
}
@Override
public void onFailure(
final ExecutionComplete executionComplete,
final ExecutionOperations executionOperations) {
int consecutiveFailures = executionComplete.getExecution().consecutiveFailures;
int totalNumberOfFailures = consecutiveFailures + 1;
if (totalNumberOfFailures > maxRetries) {
LOG.error(
"Execution has failed {} times for task instance {}. Cancelling execution.",
totalNumberOfFailures,
executionComplete.getExecution().taskInstance);
executionOperations.stop();
maxRetriesExceededHandler.accept(executionComplete, executionOperations);
} else {
this.failureHandler.onFailure(executionComplete, executionOperations);
}
}
}
class OnFailureRetryLater implements FailureHandler {
private static final Logger LOG =
LoggerFactory.getLogger(CompletionHandler.OnCompleteReschedule.class);
private final Duration sleepDuration;
public OnFailureRetryLater(Duration sleepDuration) {
this.sleepDuration = sleepDuration;
}
@Override
public void onFailure(
ExecutionComplete executionComplete, ExecutionOperations executionOperations) {
Instant nextTry = executionComplete.getTimeDone().plus(sleepDuration);
LOG.debug(
"Execution failed. Retrying task {} at {}",
executionComplete.getExecution().taskInstance,
nextTry);
executionOperations.reschedule(executionComplete, nextTry);
}
}
class OnFailureReschedule implements FailureHandler {
private static final Logger LOG =
LoggerFactory.getLogger(CompletionHandler.OnCompleteReschedule.class);
private final Schedule schedule;
public OnFailureReschedule(Schedule schedule) {
this.schedule = schedule;
}
@Override
public void onFailure(
ExecutionComplete executionComplete, ExecutionOperations executionOperations) {
Instant nextExecution = schedule.getNextExecutionTime(executionComplete);
LOG.debug(
"Execution failed. Rescheduling task {} to {}",
executionComplete.getExecution().taskInstance,
nextExecution);
executionOperations.reschedule(executionComplete, nextExecution);
}
}
@SuppressWarnings("unchecked")
class OnFailureRescheduleUsingTaskDataSchedule
implements FailureHandler {
private static final Logger LOG =
LoggerFactory.getLogger(CompletionHandler.OnCompleteReschedule.class);
@Override
public void onFailure(
ExecutionComplete executionComplete, ExecutionOperations executionOperations) {
final T data = (T) executionComplete.getExecution().taskInstance.getData();
final Instant nextExecutionTime = data.getSchedule().getNextExecutionTime(executionComplete);
LOG.debug(
"Execution failed. Rescheduling task {} to {}",
executionComplete.getExecution().taskInstance,
nextExecutionTime);
executionOperations.reschedule(executionComplete, nextExecutionTime);
}
}
}