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

com.arextest.schedule.common.SendRedisLimiter Maven / Gradle / Ivy

There is a newer version: 2.0.4
Show newest version
package com.arextest.schedule.common;

import com.arextest.common.cache.CacheProvider;
import com.arextest.schedule.model.ReplayPlan;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import java.util.concurrent.TimeUnit;
import lombok.extern.slf4j.Slf4j;

/**
 * @author wildeslam.
 * @create 2023/12/1 15:38
 */
@Slf4j
public class SendRedisLimiter implements SendLimiter {

  public final static int SUCCESS_COUNT_TO_BALANCE_NO_ERROR = 20;
  public final static int CONTINUOUS_FAIL_TOTAL = 2 * SUCCESS_COUNT_TO_BALANCE_NO_ERROR;
  public final static double ERROR_BREAK_RATE = 0.1;

  private static final String REPLAY_PLAN_KEY_FORMAT = "replayPlan_%s_%s";
  private static final String CONTINUOUS_FAIL_COUNTER = "continuousFailCounter";
  private static final String FAIL_COUNTER = "failCounter";
  private static final long ONE_HOUR_SECONDS = TimeUnit.HOURS.toSeconds(1);

  private final ReplayPlan replayPlan;
  private final CacheProvider redisCacheProvider;

  public SendRedisLimiter(ReplayPlan replayPlan, CacheProvider redisCacheProvider) {
    this.replayPlan = replayPlan;
    this.redisCacheProvider = redisCacheProvider;
  }

  @Override
  public boolean failBreak() {
    int totalTasks = replayPlan.getCaseTotalCount();
    int continuousFailCounter = continuousError();
    int failCounter = totalError();
    return continuousFailCounter > CONTINUOUS_FAIL_TOTAL
        || (totalTasks > 0 && ((double) failCounter / totalTasks) > ERROR_BREAK_RATE);
  }

  @Override
  public void acquire() {

  }

  @Override
  public void release(boolean success) {
    byte[] continuousFailCounterKey = buildReplayPlanKeyWithKeyword(replayPlan.getId(),
        CONTINUOUS_FAIL_COUNTER);
    if (success) {
      long continuousFailCounter = byteArrayToInt(redisCacheProvider.get(continuousFailCounterKey));
      if (continuousFailCounter < CONTINUOUS_FAIL_TOTAL) {
        // reset to zero else pin down
        redisCacheProvider.put(continuousFailCounterKey, ONE_HOUR_SECONDS,
            String.valueOf(0).getBytes(StandardCharsets.UTF_8));
      }
      return;
    }
    redisCacheProvider.incrValue(continuousFailCounterKey);
    redisCacheProvider.incrValue(buildReplayPlanKeyWithKeyword(replayPlan.getId(), FAIL_COUNTER));
  }

  @Override
  public void batchRelease(boolean success, int size) {

  }

  @Override
  public int totalError() {
    return byteArrayToInt(
        redisCacheProvider.get(buildReplayPlanKeyWithKeyword(replayPlan.getId(), FAIL_COUNTER)));
  }

  @Override
  public int continuousError() {
    return byteArrayToInt(redisCacheProvider.get(
        buildReplayPlanKeyWithKeyword(replayPlan.getId(), CONTINUOUS_FAIL_COUNTER)));
  }

  @Override
  public void reset() {
    byte[] continuousFailCounterKey = buildReplayPlanKeyWithKeyword(replayPlan.getId(),
        CONTINUOUS_FAIL_COUNTER);
    redisCacheProvider.put(continuousFailCounterKey, ONE_HOUR_SECONDS,
        String.valueOf(0).getBytes(StandardCharsets.UTF_8));
    byte[] failCounterKey = buildReplayPlanKeyWithKeyword(replayPlan.getId(), FAIL_COUNTER);
    redisCacheProvider.put(failCounterKey, ONE_HOUR_SECONDS,
        String.valueOf(0).getBytes(StandardCharsets.UTF_8));
  }


  private int byteArrayToInt(byte[] bytes) {
    if (bytes == null || bytes.length != Integer.BYTES) {
      return 0;
    }
    return ByteBuffer.wrap(bytes).getInt();
  }

  private byte[] buildReplayPlanKeyWithKeyword(String planId, String keyword) {
    return (String.format(REPLAY_PLAN_KEY_FORMAT, planId, keyword)).getBytes(
        StandardCharsets.UTF_8);
  }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy