Files
z-docs/docs/tutorial-extras/timer.md

9.4 KiB
Raw Blame History

sidebar_position, title, description
sidebar_position title description
2 定时调度 ZHub 定时调度功能详解

定时调度

ZHub 提供了强大的定时调度功能,支持基于 Cron 表达式和简单时间间隔的定时任务。


功能特性

  • Cron 表达式: 支持标准的 Cron 表达式语法
  • 简单间隔: 支持秒、分、时、天等时间单位
  • 数据库持久化: 支持将定时任务配置保存到数据库
  • 任务执行: 支持定时任务执行
  • 动态重载: 支持运行时重新加载定时任务配置

基础使用

1. 简单定时任务

// 订阅定时任务
zhub.timer("T:A", () -> {
    System.out.println("收到定时调度事件T:A");
    // 执行定时任务逻辑
});

// 每5秒执行一次
zhub.timer("T:B", () -> {
    System.out.println("每5秒执行一次");
});

2. 基于 Cron 表达式的定时任务

// 每天早上8点执行
zhub.timer("daily-report", () -> {
    System.out.println("生成日报");
});

// 每周一上午9点执行
zhub.timer("weekly-summary", () -> {
    System.out.println("生成周报");
});

时间表达式语法

1. 简单时间间隔

ZHub 支持以下时间单位格式:

// 支持的时间单位
"5s"    // 5秒
"10m"   // 10分钟
"2H"    // 2小时
"1d"    // 1天
"1M"    // 1个月
"1y"    // 1年

// 纯数字表示毫秒
"5000"  // 5000毫秒

2. Cron 表达式

ZHub 支持标准 Cron 表达式格式:

// 标准 Cron 表达式格式:分 时 日 月 周
"0 8 * * *"      // 每天8点
"0 0 1 * *"      // 每月1号0点
"0 9 * * 1"      // 每周一9点
"*/5 * * * *"    // 每5分钟
"0 0 0 1 1"      // 每年1月1日0点

3. 复杂 Cron 表达式

// 工作日每天9点和18点执行
"0 9,18 * * 1-5"

// 每月1号和15号执行
"0 0 1,15 * *"

// 每小时的0分和30分执行
"0,30 * * * *"

// 每5分钟执行
"*/5 * * * *"

数据库配置

1. 数据库表结构

ZHub 定时任务数据库表结构:

CREATE TABLE `tasktimer` (
  `timerid` varchar(64) NOT NULL DEFAULT '' COMMENT '[主键]UUID',
  `name` varchar(32) NOT NULL DEFAULT '' COMMENT '[任务名称]',
  `expr` varchar(32) NOT NULL DEFAULT '' COMMENT '[时间表达式]',
  `single` int NOT NULL DEFAULT '1' COMMENT '[单实例消费]1单对象0不限',
  `remark` varchar(128) NOT NULL DEFAULT '' COMMENT '[备注]',
  `status` smallint NOT NULL DEFAULT '10' COMMENT '[状态]10启用,60停用',
  PRIMARY KEY (`timerid`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

2. 配置示例

-- 插入定时任务配置
INSERT INTO `tasktimer` (`timerid`, `name`, `expr`, `single`, `remark`, `status`) VALUES 
  ('T1', 'T:A', '*/5 * * * * ?', 1, '每5秒执行一次', 10),
  ('T2', 'T:B', '15s', 1, '每15秒执行一次', 10),
  ('T3', 'T:C', '0 0 0 * * 1', 0, '每周一00:00执行', 10),
  ('T4', 'T:D', '0 0 24 * * ?', 1, '每天00:00执行', 10);

3. 服务端配置

app.ini 中配置数据库连接:

[ztimer]
db.addr=127.0.0.1:3306
db.user=root
db.password=123456
db.database=zhub
db.schema=public           # PostgreSQL 模式名
db.type=mysql             # mysql|postgres

高级功能

1. 单实例执行

// 单实例执行:只有一个客户端实例会执行任务
zhub.timer("single-task", () -> {
    System.out.println("只有一个实例执行此任务");
});

2. 多实例执行

// 多实例执行:所有客户端实例都会执行任务
zhub.timer("multi-task", () -> {
    System.out.println("所有实例都会执行此任务");
});

3. 动态重载配置

# 通过管理接口重新加载定时任务配置
curl http://127.0.0.1:711/timer/reload

4. 本地定时任务

ZHub 客户端还提供本地定时任务功能:

// 本地延时任务(适用于短时间延时)
Timers.delay(() -> {
    System.out.println("延时5秒后执行");
}, 5000);

// 本地重试任务
Timers.tryDelay(() -> {
    // 返回 true 表示成功false 表示需要重试
    return processTask();
}, 1000, 3); // 每1秒重试一次最多重试3次

实际应用场景

1. 数据同步任务

public class DataSyncService {
    private final ZHubClient zhub;
    
    public void init() {
        // 每小时同步一次数据
        zhub.timer("data-sync", () -> {
            syncData();
        });
        
        // 每天凌晨2点清理过期数据
        zhub.timer("data-cleanup", () -> {
            cleanupExpiredData();
        });
    }
    
    private void syncData() {
        System.out.println("开始同步数据...");
        // 数据同步逻辑
    }
    
    private void cleanupExpiredData() {
        System.out.println("开始清理过期数据...");
        // 数据清理逻辑
    }
}

2. 监控和告警

public class MonitorService {
    private final ZHubClient zhub;
    
    public void init() {
        // 每30秒检查系统状态
        zhub.timer("system-check", () -> {
            checkSystemHealth();
        });
        
        // 每天生成监控报告
        zhub.timer("daily-report", () -> {
            generateDailyReport();
        });
    }
    
    private void checkSystemHealth() {
        // 系统健康检查逻辑
        if (isSystemHealthy()) {
            System.out.println("系统状态正常");
        } else {
            sendAlert("系统异常,请检查");
        }
    }
}

3. 缓存刷新

public class CacheService {
    private final ZHubClient zhub;
    
    public void init() {
        // 每5分钟刷新缓存
        zhub.timer("cache-refresh", () -> {
            refreshCache();
        });
        
        // 每天凌晨3点预热缓存
        zhub.timer("cache-warmup", () -> {
            warmupCache();
        });
    }
    
    private void refreshCache() {
        System.out.println("刷新缓存...");
        // 缓存刷新逻辑
    }
}

最佳实践

1. 任务命名规范

// 推荐:使用有意义的任务名称
zhub.timer("user:data-sync", () -> {});
zhub.timer("order:status-check", () -> {});
zhub.timer("system:health-check", () -> {});

// 避免:使用无意义的名称
zhub.timer("task1", () -> {});
zhub.timer("timer", () -> {});

2. 异常处理

zhub.timer("safe-task", () -> {
    try {
        // 任务逻辑
        processTask();
    } catch (Exception e) {
        logger.error("定时任务执行失败", e);
        // 发送告警或记录错误
    }
});

3. 性能优化

// 避免在定时任务中执行耗时操作
zhub.timer("light-task", () -> {
    // 快速执行的任务
    updateStatus();
});

// 耗时操作应该异步执行
zhub.timer("heavy-task", () -> {
    CompletableFuture.runAsync(() -> {
        // 异步执行耗时操作
        processHeavyTask();
    });
});

4. 监控和日志

public class MonitoredTimer {
    private final ZHubClient zhub;
    private final Logger logger = LoggerFactory.getLogger(MonitoredTimer.class);
    
    public void init() {
        zhub.timer("monitored-task", () -> {
            long startTime = System.currentTimeMillis();
            try {
                processTask();
                long duration = System.currentTimeMillis() - startTime;
                logger.info("定时任务执行成功,耗时: {}ms", duration);
            } catch (Exception e) {
                long duration = System.currentTimeMillis() - startTime;
                logger.error("定时任务执行失败,耗时: {}ms", duration, e);
            }
        });
    }
}

故障排除

1. 任务不执行

可能原因

  • 数据库连接配置错误
  • 任务状态为停用status=60
  • 时间表达式格式错误

解决方法

# 检查数据库连接
curl http://127.0.0.1:711/_/info

# 重新加载配置
curl http://127.0.0.1:711/timer/reload

# 检查任务状态
SELECT * FROM tasktimer WHERE status = 10;

2. 任务重复执行

可能原因

  • 多个客户端实例都订阅了同一个任务
  • 单实例配置错误

解决方法

-- 确保单实例配置正确
UPDATE tasktimer SET single = 1 WHERE name = 'task-name';

3. 任务执行时间不准确

可能原因

  • 系统时间不同步
  • 任务执行时间过长

解决方法

  • 同步系统时间
  • 优化任务执行逻辑
  • 考虑拆分长时间任务

监控和调试

1. 任务执行状态

# 查看所有定时任务状态
curl http://127.0.0.1:711/_/info | jq '.timersize'

2. 日志监控

// 在任务中添加详细日志
zhub.timer("logged-task", () -> {
    logger.info("定时任务开始执行: {}", LocalDateTime.now());
    try {
        processTask();
        logger.info("定时任务执行完成: {}", LocalDateTime.now());
    } catch (Exception e) {
        logger.error("定时任务执行异常: {}", e.getMessage(), e);
    }
});

3. 性能监控

// 监控任务执行时间
public class PerformanceMonitor {
    public void monitorTask(String taskName, Runnable task) {
        long startTime = System.currentTimeMillis();
        try {
            task.run();
        } finally {
            long duration = System.currentTimeMillis() - startTime;
            if (duration > 5000) { // 超过5秒记录警告
                logger.warn("任务 {} 执行时间过长: {}ms", taskName, duration);
            }
        }
    }
}