All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.remondis.limbus.tasks.TaskExecution Maven / Gradle / Ivy

package com.remondis.limbus.tasks;

import static com.remondis.limbus.tasks.TaskSchedulerImpl.normalizeRate;

import java.util.concurrent.ScheduledFuture;
import java.util.function.Function;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.remondis.limbus.utils.StopWatch;

class TaskExecution implements Runnable {

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

  private TaskSchedulerImpl scheduler;
  private Task task;
  private Function scheduleRateFunction;
  private long currentRate;
  private boolean lastSuccess;
  private ScheduledFuture future;

  private boolean rejected;

  TaskExecution(TaskSchedulerImpl scheduler, Task task, Function scheduleRateFunction) {
    super();
    this.task = task;
    this.scheduleRateFunction = scheduleRateFunction;
    this.scheduler = scheduler;
  }

  @Override
  public void run() {
    StopWatch s = new StopWatch();
    this.rejected = false;
    boolean success = false;
    try {
      s.start();
      task.execute();
      success = true;
    } catch (Exception e) {
      success = false;
      log.warn(String.format("The periodic task %s failed with an exception.", task.getClass()
          .getName()), e);
    } finally {
      s.stop();
    }
    lastSuccess = success;
    rescheduleOnDemand(success, s.getMillisecondsRuntime());
  }

  private void logException(long newRate, boolean success) {
    if (success) {
      log.warn("The priodic task {} was successful after failing - re-scheduling this task with rate {}ms.",
          task.getClass()
              .getName(),
          newRate);
    } else {
      log.warn(String.format("The priodic task %s was unsuccessful - re-scheduling this task with rate %dms.",
          task.getClass()
              .getName(),
          newRate));
    }
  }

  private void rescheduleOnDemand(boolean success, long lastRuntime) {
    if (lastRuntime >= currentRate) {
      // buschmann - 23.05.2017 : The scheduled executor service automatically prevents overlapping of task executions.
      // So subsequent executions will be delayed until after the previous one has finished. We only need to warn here.
      log.warn(String.format("Runtime of task %s was bigger then reschedule delay.", this.getTaskInfo()
          .getTaskName()));
    }

    long newRate = normalizeRate(scheduleRateFunction.apply(success));
    if (currentRate != newRate) {
      logException(newRate, success);
      // Cancel this execution
      cancel();
      currentRate = newRate;
      scheduler.reschedule(this, newRate);
    }

  }

  public void setCurrentRate(Long currentRate) {
    this.currentRate = currentRate;
  }

  public void setFuture(ScheduledFuture future) {
    this.future = future;
  }

  public void cancel() {
    if (future != null) {
      future.cancel(false);
      try {
        future.get();
      } catch (Exception e) {
        /*
         * Ignore any exception because:
         * CancellationException: Is a result of cancelling the job, but this is our intention here.
         *
         * ExecutionException: if the computation threw an exception. This exception cannot be handled here. Exceptions
         * are handled inside the run method.
         *
         * InterruptedException - if the current thread was interrupted while waiting, we cannot do anything.
         *
         */
      }
    }
  }

  public TaskInfo getTaskInfo() {
    return new TaskInfo(task.getClass()
        .getName(), lastSuccess, currentRate, rejected);
  }

  public void wasRejected() {
    this.rejected = true;
  }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy