Skip to content

业务相关参数详解

1. 概述

在实际业务场景中,SnailJob 支持通过一系列业务参数实现更灵活的重试任务管理,包括幂等ID、业务编号、重试方法、回调方法等。合理配置这些参数,可以实现任务唯一性、业务追踪、自定义重试与回调逻辑等高级功能。

2. 参数说明

参数描述默认值必须指定
idempotentId幂等id生成器SimpleIdempotentIdGenerate
retryMethod重试处理入口ExecutorAnnotationMethod
retryCompleteCallback服务端重试完成(重试成功、重试到达最大次数)回调客户端SimpleRetryCompleteCallback
bizNo标识具有业务特点的值比如订单号、物流编号等,可以根据具体的业务场景生成,生成规则采用Spel表达式解析。

2.1 idempotentId(幂等ID生成器)

  • 作用:保证每个重试任务的唯一性,防止重复任务。
  • 默认实现:SimpleIdempotentIdGenerate,基于场景、执行器、参数、方法名等信息生成MD5。
  • 自定义:可实现 IdempotentIdGenerate 接口,按需定制唯一ID生成规则。
  • 示例代码
    java
    public class SimpleIdempotentIdGenerate implements IdempotentIdGenerate {
        @Override
        public String idGenerate(IdempotentIdGenerateEntity idempotentIdGenerateEntity) throws Exception {
            return SecureUtil.md5(idempotentIdGenerateEntity.toString());
        }
    }

2.2 bizNo(业务编号)

  • 作用:用于标识具有业务特点的值如订单号、物流编号等,便于控制台检索和追踪。
  • 用法:支持SpEL表达式,如 bizNo = "orderVo.orderId"
  • 示例代码
    java
    @Retryable(scene = "remoteRetryWithBizNo", retryStrategy = RetryType.ONLY_REMOTE, bizNo = "orderVo.orderId")
    public boolean remoteRetryWithBizNo(OrderVo orderVo) {
        throw new NullPointerException();
    }

2.3 retryMethod(重试处理入口)

  • 作用:自定义重试函数的入口方法。
  • 默认实现:ExecutorAnnotationMethod,反射调用原重试方法。
  • 自定义:实现 ExecutorMethod 接口,按需定制重试逻辑。
  • 示例代码
    java
    @Slf4j
    public class ExecutorAnnotationMethod implements ExecutorMethod {
        private RetryerInfo retryerInfo;
        public ExecutorAnnotationMethod(RetryerInfo retryerInfo) { this.retryerInfo = retryerInfo; }
        @Override
        public Object doExecute(Object params) {
            Class<?>[] paramTypes = retryerInfo.getMethod().getParameterTypes();
            LogUtils.info(log, "执行原重试方法:[{}],参数为:[{}]", retryerInfo.getExecutorClassName(), JsonUtil.toJsonString(params));
            if (paramTypes.length > 0) {
                return ReflectionUtils.invokeMethod(retryerInfo.getMethod(), retryerInfo.getExecutor(), (Object[]) params);
            } else {
                return ReflectionUtils.invokeMethod(retryerInfo.getMethod(), retryerInfo.getExecutor());
            }
        }
    }
    public interface ExecutorMethod { Object doExecute(Object params); }
  • 自定义方法示例
    java
    @Component
    public class OrderRetryMethod implements ExecutorMethod {
        @Override
        public Object doExecute(Object params) {
            Object[] args = (Object[]) params;
            OrderVo orderVo = (OrderVo) args[0];
            log.info("进入自定义的回调方法,参数信息是{}", JSONUtil.toJsonStr(orderVo));
            throw new ArithmeticException();
        }
    }
    @Retryable(scene = "remoteRetryWithRetryMethod", retryStrategy = RetryType.ONLY_REMOTE, retryMethod = OrderRetryMethod.class)
    public boolean remoteRetryWithRetryMethod(OrderVo orderVo) {
        throw new NullPointerException();
    }

2.4 retryCompleteCallback(重试完成回调)

  • 作用:自定义重试完成(成功或到达最大次数)后的回调逻辑。
  • 默认实现:SimpleRetryCompleteCallback,默认无操作。
  • 自定义:实现 RetryCompleteCallback 接口,按需处理成功/失败回调。
  • 示例代码
    java
    @Component
    @Slf4j
    public class SimpleRetryCompleteCallback implements RetryCompleteCallback {
        @Override
        public void doSuccessCallback(String sceneName, String executorName, Object[] params) {}
        @Override
        public void doMaxRetryCallback(String sceneName, String executorName, Object[] params) {}
    }
    // 自定义回调
    @Slf4j
    public class OrderCompleteCallback implements RetryCompleteCallback {
        @Autowired
        private FailOrderBaseMapper failOrderBaseMapper;
        @Override
        public void doSuccessCallback(String sceneName, String executorName, Object[] objects) {
            OrderVo orderVo = (OrderVo) objects[0];
            log.info("远程重试成功,场景{},执行器{},参数信息",sceneName,executorName, JSONUtil.toJsonStr(objects));
            failOrderBaseMapper.delete(
                new LambdaQueryChainWrapper<>(failOrderBaseMapper)
                .eq(FailOrderPo::getOrderId,orderVo.getOrderId())
            );
        }
        @Override
        public void doMaxRetryCallback(String sceneName, String executorName, Object[] objects) {
            OrderVo orderVo = (OrderVo) objects[0];
            log.info("远程重试达到最大限度,场景{},执行器{},参数信息",sceneName,executorName, JSONUtil.toJsonStr(objects));
            failOrderBaseMapper.insert(FailOrderPo.builder()
                                       .orderId(orderVo.getOrderId())
                                       .sourceId(orderVo.getSource())
                                       .sceneName(sceneName)
                                       .executorName(executorName)
                                       .args(JSONUtil.toJsonStr(objects))
                                       .build());
        }
    }
    @Retryable(scene = "remoteRetryWithCompleteCallback", retryStrategy = RetryType.LOCAL_REMOTE, retryCompleteCallback = OrderCompleteCallback.class)
    public boolean remoteRetryWithCompleteCallback(OrderVo orderVo) {
        Random random = new Random();
        double probability = random.nextDouble();
        if (probability <= 0.5) {
            throw new NullPointerException();
        }
        return true;
    }

3. 配置与代码示例

3.1 幂等ID自定义场景

java
@Data
public class OrderVo {
    private String orderId; // 订单ID,用于唯一标识订单的编号
    private Integer source; // 订单来源信息,1-手机端下单 2-PC端下单
}

public class OrderIdempotentIdGenerate implements IdempotentIdGenerate {
    @Override
    public String idGenerate(IdempotentIdContext idempotentIdContext) throws Exception {
        Object[] args = idempotentIdContext.getArgs();
        OrderVo orderVo = (OrderVo) args[0];
        return SecureUtil.md5(orderVo.getOrderId());
    }
}
@Retryable(scene = "remoteRetryWithIdempotentId", retryStrategy = RetryType.ONLY_REMOTE, idempotentId = OrderIdempotentIdGenerate.class)
public boolean remoteRetryWithIdempotentId(OrderVo orderVo) {
    double i = 1 / 0;
    return true;
}
  • 多端下单同一订单号只生成一次重试任务。

3.2 业务编号追踪场景

java
@Retryable(scene = "remoteRetryWithBizNo", retryStrategy = RetryType.ONLY_REMOTE, bizNo = "orderVo.orderId")
public boolean remoteRetryWithBizNo(OrderVo orderVo) {
    throw new NullPointerException();
}
  • 控制台可通过业务编号快速检索重试任务。

3.3 自定义重试方法与回调场景

见上文 retryMethod 与 retryCompleteCallback 示例。

4. 最佳实践

  • 业务唯一性强的场景建议自定义幂等ID生成规则,防止重复任务。
  • 充分利用 bizNo 便于业务追踪和控制台检索。
  • 复杂业务可自定义 retryMethod 和 retryCompleteCallback,实现更灵活的重试与回调逻辑。
  • 结合实际业务需求合理配置各参数,提升系统健壮性与可维护性。