Files
fys-Multi-tenant/fys-admin/src/main/java/com/fuyuanshen/global/queue/RedissonAlarmConsumer.java
DragonWenLong c291e47ae8 feat(mqtt): 添加报警检查服务实现多阶段报警处理
- 实现 AlarmCheckService 提供延迟队列消费者功能
- 添加 AlarmDelayProvider 接口定义延迟检查任务
- 集成 AlarmStageConfig 支持租户配置报警阶段延迟时间
- 重构 AliyunVoiceUtil 返回完整响应对象而非字符串
- 在 AppDeviceController 中新增 AlarmList 接口查询设备告警列表
- 扩展设备相关控制器支持数据来源枚举参数传递
- 新增 Xinghan 指令控制器提供 HBY018A 设备专用接口
- 定义 DataSourceEnum 枚举区分 APP 和 Web 数据来源
- 扩展 Device 实体类增加紧急联系人和通知配置字段
- 添加 DeviceAlarm 实体类告警状态和等级属性
- 新增 DeviceContactPhoneBo 处理设备联系人信息
- 优化设备操作记录日志支持数据来源标识
- 实现设备自定义语音短信消息编辑功能
- 添加设备通知开关和紧急联系人设置接口
2026-05-26 15:38:18 +08:00

111 lines
4.3 KiB
Java
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package com.fuyuanshen.global.queue;
import com.fuyuanshen.global.Provider.RedissonAlarmDelayProvider;
import com.fuyuanshen.global.mqtt.service.AlarmCheckService;
import jakarta.annotation.PreDestroy;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RBlockingQueue;
import org.redisson.api.RedissonClient;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
@Component
@Slf4j
@RequiredArgsConstructor
public class RedissonAlarmConsumer implements CommandLineRunner {
private final RedissonClient redissonClient;
private final AlarmCheckService alarmCheckService;
private volatile boolean running = true;
private Thread consumerThread;
private ExecutorService bizExecutor;
private static final int BIZ_THREADS = 4; // 业务处理线程数
private static final int BIZ_QUEUE_CAPACITY = 200; // 有界队列容量
@Override
public void run(String... args) {
// 初始化业务处理线程池(有界队列 + 调用者运行拒绝策略,避免 OOM
bizExecutor = Executors.newFixedThreadPool(
BIZ_THREADS,
new ThreadFactory() {
private final AtomicInteger counter = new AtomicInteger(1);
@Override
public Thread newThread(Runnable r) {
Thread t = new Thread(r, "Alarm-Biz-" + counter.getAndIncrement());
t.setDaemon(false);
return t;
}
}
);
// 启动消费线程
consumerThread = new Thread(() -> {
RBlockingQueue<Long> blockingQueue = redissonClient.getBlockingQueue(RedissonAlarmDelayProvider.QUEUE_NAME);
log.info("Redisson 延迟报警监听线程已启动...");
while (running && !Thread.currentThread().isInterrupted()) {
try {
Long alarmId = blockingQueue.poll(1, TimeUnit.SECONDS); // 改用带超时的 poll可响应中断
if (alarmId != null) {
// 提交到业务线程池异步处理,避免阻塞队列拉取
bizExecutor.submit(() -> processAlarm(alarmId));
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
log.info("Redisson 消费线程被中断,退出循环");
break;
} catch (Exception e) {
log.error("Redisson 延迟队列消费异常", e);
// 发生非中断异常时短暂休眠,避免日志风暴
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException interrupted) {
Thread.currentThread().interrupt();
break;
}
}
}
log.info("Redisson 延迟报警消费线程结束");
}, "Alarm-Consumer-Thread");
consumerThread.setDaemon(false);
consumerThread.start();
}
private void processAlarm(Long alarmId) {
try {
alarmCheckService.executeCheck(alarmId);
} catch (Exception e) {
log.error("处理报警 ID [{}] 时发生异常", alarmId, e);
// 可在此补充重试或死信逻辑
}
}
@PreDestroy
public void destroy() {
log.info("开始关闭 Redisson 报警消费者...");
running = false;
if (consumerThread != null) {
consumerThread.interrupt(); // 中断阻塞在 poll 上的线程
}
if (bizExecutor != null) {
bizExecutor.shutdown();
try {
if (!bizExecutor.awaitTermination(60, TimeUnit.SECONDS)) {
bizExecutor.shutdownNow();
}
} catch (InterruptedException e) {
bizExecutor.shutdownNow();
Thread.currentThread().interrupt();
}
}
log.info("Redisson 报警消费者已关闭");
}
}