跳转到主内容
极星编程网:以代码为星,赴技术山海!

如何通过实现自定义拒绝策略实战实现将溢出变量任务持久化到数据库的补偿逻辑

线程池饱和时应将拒绝任务异步落库补偿,需确保不阻塞主线程、任务关键字段可序列化、状态可追踪;建表存储ID/内容/重试次数/状态/时间;自定义拒绝策略校验后JSON化关键信息入库,并配定时扫描+幂等重试机制。 线程池饱和时,直接丢弃任务或抛异常会导致关键业务数据丢失。把被拒绝的任务存进数据库,是最常用也最稳妥的补偿方式之一——它能保证任务不丢、可追溯、可人工干预。 关键设计原则 实现前必须明确三点: 不阻塞主线程 :落库操作不能在 rejectedExecution 方法里同步执行,否则会拖慢上游请求;建议用异步写入(如 Spring 的
@Async
)或带超时控制的连接池调用 任务要能序列化 :Runnable 对象本身不一定可序列化,推荐只提取关键字段(如订单ID、操作类型、参数JSON),避免直接存
r.toString()
这类不可靠字符串 状态必须可追踪 :数据库表至少包含 ID、任务内容、重试次数、当前状态(WAITING/SUCCESS/FAILED)、创建时间,方便后续定时扫描和幂等重试 数据库表结构与实体定义 建一张轻量但完整的任务表,例如 MySQL: CREATE TABLE rejected_tasks ( id VARCHAR(36) PRIMARY KEY, task_data TEXT NOT NULL, retry_count INT DEFAULT 0, status VARCHAR(20) NOT NULL DEFAULT 'WAITING', create_time DATETIME NOT NULL ); 对应 Java 实体类需支持快速构建和 JSON 序列化,比如用 Lombok 简化: public class RejectedTask { private String id = UUID.randomUUID().toString(); private String taskData; private int retryCount = 0; private String status = "WAITING"; private LocalDateTime createTime = LocalDateTime.now(); } 自定义拒绝策略实现 核心是实现
RejectedExecutionHandler
接口,在
rejectedExecution
方法中完成安全落库: 第一行加空值校验:
if (r == null || executor.isShutdown()) return;
用 Jackson 或 Gson 把任务关键信息转成 JSON 字符串(不要序列化整个 Runnable) 调用 DAO 层插入数据库,包裹 try-catch;失败时不抛异常,改打告警日志并记录到本地内存队列(作为二级兜底) 避免在该方法内调用
executor.submit()
,防止死递归 配套补偿机制 光存进去还不够,得有人“干活”: 定时任务扫描 :每 30 秒查一次
status = 'WAITING'
且
retry_count < 3
的记录,重新提交到线程池 重试后更新状态 :成功则设为 SUCCESS;失败则
retry_count++
,若达上限改为 FAILED 并触发人工告警 防重复执行 :任务执行前先用乐观锁更新状态(
UPDATE ... SET status='PROCESSING' WHERE id=? AND status='WAITING'
),只有一条能成功

相关文章