任务幂等

本文介绍了一个分布式业务流系统中实现幂等性的方法。通过记录业务接口执行过程并利用状态机来确保任务不会重复执行,同时支持失败后的重试机制。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

     最近在做一个业务流系统,部署在分布式环境下,使用到分布式调度系统,一是为了在系统宕机,系统发布的时候任务能够在可用的机器上重启重新;二是任务需要重试,等接口执行失败之后需要设置调度系统的间隔时间在业务集群上重启启动任务(业务的线程和进程都可能发生变化),因为业务流中的业务接口都是有影响或者不幂等比如关闭应用,这条命令就不能重复执行。

     这就要求每个重试/重启单元是幂等,我的思路是能够记录每个外部接口的执行过程,要是某个接口已经执行过某个步骤之后跳过这个阶段,保证命令不会重复下达。

     每个业务接口我把它分成3个阶段,命令下达(下达成功、下达失败),命令执行成功(执行承成功、执行失败),命令结果入库成功(入库成功、入库失败),基本模型

public class IdempotentFlag {

	private Boolean commandSendDown = false;

	// 2 未知(对于异步任务,命令下达成功,此状态下需要不停检测) 0 失败 1 成功
	private int commandSuccess = 2;

	private Boolean commandResultInDB = false;
       // 任务的附加信息,比如异步任务返回的TaskID
	private String attachInfo;
}

     每个幂等对象都有一个Key,在整个流程是唯一的,幂等对象的入库,我使用的是Enhance动态代理,这样代理对象的获得:若数据库存在从数据库查取数据初始化对象,若是数据库不存在构造默认对象。

public class IdempotentFlagFroxyFactory implements MethodInterceptor {


	private String contextKey;

	public IdempotentFlagFroxyFactory(String contextKey) {
		this.contextKey = contextKey;
	}

	public IdempotentFlag getProxy() {

		Enhancer enhancer = new Enhancer();
		enhancer.setSuperclass(IdempotentFlag.class);
		enhancer.setCallback(this);

		IdempotentFlag clearObject = (IdempotentFlag) enhancer.create();
                String IdempotentFlagString =   getFromDB(contextKey);
		if (StringUtils.isNotBlank(IdempotentFlagString)) {
			IdempotentFlag dbObject = IdempotentFlag.toObject(IdempotentFlagString);
			try {
				BeanUtils.copyProperties(clearObject, dbObject);
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		return clearObject;
	}

	@Override
	public Object intercept(Object target, Method method, Object[] args, MethodProxy proxy) throws Throwable {
		Object result = proxy.invokeSuper(target, args);
		if (method.getName().contains("set")) {
			IdempotentFlag flag = (IdempotentFlag) target;
			context.putPersistentString(contextKey, flag.toString());
		}
		return result;
	}



}

         在外部接口周围保存阶段再做一个状态机就可以,保证任务的幂等,不会重复下发,并且失败之后还可以重试。

### XXL-JOB 中的任务等性处理 在分布式系统中,任务等性是非常重要的特性之一。它确保即使由于网络异常或其他原因导致任务重复执行,最终的结果仍然是一致的。以下是关于如何在 XXL-JOB 中实现任务等性的最佳实践。 #### 1. 数据库唯一约束设计 通过数据库层面的设计来保障任务等性是最常见的方式之一。可以在任务对应的业务表中增加唯一的索引来防止重复操作。例如,在创建订单场景下,可以基于 `order_id` 字段设置唯一键[^4]: ```sql ALTER TABLE orders ADD UNIQUE (order_id); ``` 当任务尝试插入相同 `order_id` 的记录时,数据库会抛出唯一键冲突错误,从而阻止重复数据写入。 #### 2. 分布式锁机制 利用 Redis 或 Zookeeper 等工具实现分布式锁也是一种有效的手段。每次执行任务前先获取锁,如果成功则继续运行逻辑;否则跳过当前请求以避免重复处理同一项工作[^5]。 示例代码如下所示(假设采用Redis作为存储介质): ```java public void executeTask(String taskId) { String lockKey = "task_lock:" + taskId; try { boolean isLocked = redisTemplate.opsForValue().setIfAbsent(lockKey, "LOCKED", Duration.ofMinutes(5)); if (!isLocked) { System.out.println("Task already being processed by another instance."); return; // Exit early to prevent duplicate execution. } // Business logic here... processBusinessLogic(taskId); } finally { redisTemplate.delete(lockKey); // Release the lock after completion or exception occurs. } } ``` #### 3. 基于状态机的状态控制 对于某些复杂流程而言,可以通过定义清晰的状态转换规则来达到等效果。比如支付环节可能经历待付款 -> 已付款 -> 成功/失败等多个阶段变化过程。只有处于特定状态下才允许进一步动作发生,其余情况均视为非法输入并忽略掉多余调用[^6]。 以上方法均可单独或者组合应用于实际开发当中,具体选用哪种方案取决于应用场景的具体需求和技术栈现状等因素考量之后再做决定。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值