forked from dyf/fys-Multi-tenant
feat(mqtt): 添加报警检查服务实现多阶段报警处理
- 实现 AlarmCheckService 提供延迟队列消费者功能 - 添加 AlarmDelayProvider 接口定义延迟检查任务 - 集成 AlarmStageConfig 支持租户配置报警阶段延迟时间 - 重构 AliyunVoiceUtil 返回完整响应对象而非字符串 - 在 AppDeviceController 中新增 AlarmList 接口查询设备告警列表 - 扩展设备相关控制器支持数据来源枚举参数传递 - 新增 Xinghan 指令控制器提供 HBY018A 设备专用接口 - 定义 DataSourceEnum 枚举区分 APP 和 Web 数据来源 - 扩展 Device 实体类增加紧急联系人和通知配置字段 - 添加 DeviceAlarm 实体类告警状态和等级属性 - 新增 DeviceContactPhoneBo 处理设备联系人信息 - 优化设备操作记录日志支持数据来源标识 - 实现设备自定义语音短信消息编辑功能 - 添加设备通知开关和紧急联系人设置接口
This commit is contained in:
@ -0,0 +1,110 @@
|
||||
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 报警消费者已关闭");
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user