You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Java轮询停止检测:60秒无运行时触发告警方案

实现心跳监控与告警方案

核心思路

启动一个独立的监控线程,定期检查主轮询循环的心跳时间戳:

  • 主循环每次迭代时更新线程安全的心跳时间戳
  • 监控线程每隔固定时间(如10秒)检查时间差,若超过60秒未收到心跳则触发告警

具体实现代码

1. 定义共享心跳变量

用AtomicLong保证多线程环境下的读写原子性:

import java.util.concurrent.atomic.AtomicLong;

// 共享心跳时间戳,初始化为当前时间
private static final AtomicLong lastHeartbeat = new AtomicLong(System.currentTimeMillis());

2. 修改主轮询循环

在每次循环迭代时更新心跳,确保正常执行或捕获到异常(循环未终止)时都标记存活:

for (;;) {
    try {
        // 进入循环立即更新心跳
        lastHeartbeat.set(System.currentTimeMillis());
        
        // 1. 轮询消息流逻辑
        // 2. 处理消息逻辑
        // 3. 存储至数据库逻辑
        
        // 计算执行耗时,调整睡眠时间(保证总周期约20秒)
        long executionCost = System.currentTimeMillis() - lastHeartbeat.get();
        long sleepDuration = Math.max(0, 20000 - executionCost);
        Thread.sleep(sleepDuration);
    } catch (Exception e) {
        // 4. 异常处理逻辑(打日志、重试等)
        // 即使发生异常,只要循环未终止,就更新心跳
        lastHeartbeat.set(System.currentTimeMillis());
    }
}

3. 启动监控定时任务

用ScheduledExecutorService实现定期检查,触发告警逻辑:

import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

public class PollingMonitor {
    public static void startMonitor() {
        ScheduledExecutorService monitorService = Executors.newSingleThreadScheduledExecutor(runnable -> {
            Thread thread = new Thread(runnable);
            // 设置为守护线程,避免阻止程序正常退出
            thread.setDaemon(true);
            // 设置未捕获异常处理器,防止监控线程意外挂掉
            thread.setUncaughtExceptionHandler((t, e) -> {
                System.err.println("监控线程异常: " + e.getMessage());
                e.printStackTrace();
            });
            return thread;
        });
        
        // 初始延迟0秒,每隔10秒检查一次
        monitorService.scheduleAtFixedRate(() -> {
            long currentTime = System.currentTimeMillis();
            long lastBeatTime = lastHeartbeat.get();
            
            // 超过60秒未收到心跳,触发告警
            if (currentTime - lastBeatTime > 60 * 1000) {
                sendAlert("轮询任务已停止超过60秒,最后心跳时间: " + lastBeatTime);
            }
        }, 0, 10, TimeUnit.SECONDS);
    }
    
    // 告警实现:发送邮件示例
    private static void sendAlert(String alertMsg) {
        // 此处替换为你的邮件发送逻辑
        try {
            // 示例:使用JavaMail API发送邮件(需引入javax.mail依赖)
            javax.mail.Session session = javax.mail.Session.getInstance(new java.util.Properties(), null);
            javax.mail.Message message = new javax.mail.internet.MimeMessage(session);
            message.setFrom(new javax.mail.internet.InternetAddress("your-alert-sender@example.com"));
            message.setRecipients(javax.mail.Message.RecipientType.TO, 
                javax.mail.internet.InternetAddress.parse("your-alert-receiver@example.com"));
            message.setSubject("轮询任务异常告警");
            message.setText(alertMsg);
            
            javax.mail.Transport.send(message);
            System.out.println("告警邮件已发送");
        } catch (Exception e) {
            System.err.println("告警发送失败: " + e.getMessage());
            e.printStackTrace();
        }
    }
}

4. 启动监控

在应用启动时调用PollingMonitor.startMonitor()即可。

关键注意事项

  • 线程安全:必须用AtomicLong或其他线程安全的方式存储心跳时间戳,避免多线程读写冲突。
  • 监控线程可靠性:设置守护线程和未捕获异常处理器,防止监控自身挂掉导致告警失效。
  • 告警阈值调整:若任务单次执行可能超过60秒(如批量处理大量消息),需适当调高高警阈值,或在任务执行过程中定时更新心跳。
  • 资源清理:应用关闭时,需调用monitorService.shutdown()释放线程池资源。

内容的提问来源于stack exchange,提问作者Om Sao

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.31 09:31:05