content: package com.aizuda.snailjob.client.core.strategy;
  
  import com.aizuda.snailjob.client.core.RetryExecutor;
  import com.aizuda.snailjob.client.core.RetryExecutorParameter;
  import com.aizuda.snailjob.client.core.intercepter.RetrySiteSnapshot;
  import com.aizuda.snailjob.client.core.retryer.RetryType;
  import com.aizuda.snailjob.client.core.retryer.RetryerInfo;
  import com.aizuda.snailjob.client.core.retryer.RetryerResultContext;
  import com.aizuda.snailjob.common.core.enums.RetryResultStatusEnum;
  import com.aizuda.snailjob.common.log.SnailJobLog;
  import com.github.rholder.retry.*;
  import lombok.extern.slf4j.Slf4j;
  import org.springframework.stereotype.Component;
  
  import java.util.Collections;
  import java.util.List;
  import java.util.concurrent.Callable;
  import java.util.concurrent.TimeUnit;
  import java.util.function.Consumer;
  
  /**
   * 手动执行重试
   *
   * @author: opensnail
   * @date : 2023-05-15 18:19
   */
  @Component
  @Slf4j
  public class ManualRetryStrategies extends AbstractRetryStrategies {
  
      @Override
      protected void setStage() {
          RetrySiteSnapshot.setStage(RetrySiteSnapshot.EnumStage.MANUAL_REPORT.getStage());
      }
  
      @Override
      protected Consumer<Object> doRetrySuccessConsumer(final RetryerResultContext context) {
          return o -> {
              SnailJobLog.LOCAL.debug("ManualRetryStrategies doRetrySuccessConsumer ");
          };
      }
  
      @Override
      protected void error(final RetryerResultContext context) {
          context.setRetryResultStatusEnum(RetryResultStatusEnum.FAILURE);
      }
  
      @Override
      protected boolean preValidator(final RetryerInfo retryerInfo, final RetryerResultContext resultContext) {
  
          if (retryerInfo.isForceReport()) {
              return true;
          }
  
          if (RetrySiteSnapshot.isRunning()) {
              resultContext.setRetryResultStatusEnum(RetryResultStatusEnum.FAILURE);
              resultContext.setMessage("Retry validation failed: reason: there is an ongoing retry task");
              return false;
          }
  
          return true;
      }
  
      @Override
      protected void unexpectedError(final Exception e, final RetryerResultContext retryerResultContext) {
          retryerResultContext.setRetryResultStatusEnum(RetryResultStatusEnum.FAILURE);
      }
  
      @Override
      protected void success(final RetryerResultContext retryerResultContext) {
          retryerResultContext.setRetryResultStatusEnum(RetryResultStatusEnum.SUCCESS);
      }
  
      @Override
      protected Consumer<Throwable> doGetRetryErrorConsumer(final RetryerInfo retryerInfo, final Object[] params) {
          return throwable -> {
              SnailJobLog.LOCAL.debug("ManualRetryStrategies doGetRetryErrorConsumer ");
          };
      }
  
      @Override
      protected Callable doGetCallable(final RetryExecutor<WaitStrategy, StopStrategy> retryExecutor, Object[] params) {
          RetryerInfo retryerInfo = retryExecutor.getRetryerInfo();
          return () -> doReport(retryerInfo, params);
  
      }
  
      @Override
      protected RetryExecutorParameter<WaitStrategy, StopStrategy> getRetryExecutorParameter(RetryerInfo retryerInfo) {
          return new RetryExecutorParameter<WaitStrategy, StopStrategy>() {
  
              @Override
              public WaitStrategy backOff() {
                  return WaitStrategies.fixedWait(500, TimeUnit.MILLISECONDS);
              }
  
              @Override
              public StopStrategy stop() {
                  return StopStrategies.stopAfterAttempt(5);
              }
  
              @Override
              public List<RetryListener> getRetryListeners() {
                  return Collections.singletonList(new RetryListener() {
                      @Override
                      public <V> void onRetry(Attempt<V> attempt) {
                          if (attempt.hasResult()) {
                              SnailJobLog.LOCAL.info("snail-job manually created retry data successfully, scheduled for the [{}] time", attempt.getAttemptNumber());
                          }
  
                          if (attempt.hasException()) {
                              SnailJobLog.LOCAL.error(" Manually creating retry data for snail-job failed, attempt [{}]", attempt.getAttemptNumber(),
                                      attempt.getExceptionCause());
                          }
  
                      }
                  });
              }
          };
      }
  
      @Override
      public boolean supports(final int stage, final RetryType retryType) {
          return RetrySiteSnapshot.EnumStage.MANUAL_REPORT.getStage() == stage;
      }
  }
  