content: /*
   * Copyright 2010-2025 Hyland Software, Inc. and its affiliates.
   *
   * 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 org.activiti.engine.impl.interceptor;
  
  import org.activiti.engine.ActivitiException;
  import org.activiti.engine.ActivitiOptimisticLockingException;
  import org.slf4j.Logger;
  import org.slf4j.LoggerFactory;
  
  /**
   * Intercepts {@link ActivitiOptimisticLockingException} and tries to run the same command again. The number of retries and the time waited between retries is configurable.
   *
  
   */
  public class RetryInterceptor extends AbstractCommandInterceptor {
  
      private static Logger log = LoggerFactory.getLogger(RetryInterceptor.class);
  
      protected int numOfRetries = 3;
      protected int waitTimeInMs = 50;
      protected int waitIncreaseFactor = 5;
  
      public <T> T execute(CommandConfig config, Command<T> command) {
          long waitTime = waitTimeInMs;
          int failedAttempts = 0;
  
          do {
              if (failedAttempts > 0) {
                  log.info("Waiting for {}ms before retrying the command.", waitTime);
                  waitBeforeRetry(waitTime);
                  waitTime *= waitIncreaseFactor;
              }
  
              try {
                  // try to execute the command
                  return next.execute(config, command);
              } catch (ActivitiOptimisticLockingException e) {
                  log.info("Caught optimistic locking exception: " + e);
              }
  
              failedAttempts++;
          } while (failedAttempts <= numOfRetries);
  
          throw new ActivitiException(
              numOfRetries + " retries failed with ActivitiOptimisticLockingException. Giving up."
          );
      }
  
      protected void waitBeforeRetry(long waitTime) {
          try {
              Thread.sleep(waitTime);
          } catch (InterruptedException e) {
              log.debug("I am interrupted while waiting for a retry.");
          }
      }
  
      public void setNumOfRetries(int numOfRetries) {
          this.numOfRetries = numOfRetries;
      }
  
      public void setWaitIncreaseFactor(int waitIncreaseFactor) {
          this.waitIncreaseFactor = waitIncreaseFactor;
      }
  
      public void setWaitTimeInMs(int waitTimeInMs) {
          this.waitTimeInMs = waitTimeInMs;
      }
  
      public int getNumOfRetries() {
          return numOfRetries;
      }
  
      public int getWaitIncreaseFactor() {
          return waitIncreaseFactor;
      }
  
      public int getWaitTimeInMs() {
          return waitTimeInMs;
      }
  }
  