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

444 lines
9.4 KiB
Markdown
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.

---
sidebar_position: 2
title: 定时调度
description: ZHub 定时调度功能详解
---
# 定时调度
ZHub 提供了强大的定时调度功能,支持基于 Cron 表达式和简单时间间隔的定时任务。
---
## 功能特性
- **Cron 表达式**: 支持标准的 Cron 表达式语法
- **简单间隔**: 支持秒、分、时、天等时间单位
- **数据库持久化**: 支持将定时任务配置保存到数据库
- **任务执行**: 支持定时任务执行
- **动态重载**: 支持运行时重新加载定时任务配置
---
## 基础使用
### 1. 简单定时任务
```java
// 订阅定时任务
zhub.timer("T:A", () -> {
System.out.println("收到定时调度事件T:A");
// 执行定时任务逻辑
});
// 每5秒执行一次
zhub.timer("T:B", () -> {
System.out.println("每5秒执行一次");
});
```
### 2. 基于 Cron 表达式的定时任务
```java
// 每天早上8点执行
zhub.timer("daily-report", () -> {
System.out.println("生成日报");
});
// 每周一上午9点执行
zhub.timer("weekly-summary", () -> {
System.out.println("生成周报");
});
```
---
## 时间表达式语法
### 1. 简单时间间隔
ZHub 支持以下时间单位格式:
```java
// 支持的时间单位
"5s" // 5秒
"10m" // 10分钟
"2H" // 2小时
"1d" // 1天
"1M" // 1个月
"1y" // 1年
// 纯数字表示毫秒
"5000" // 5000毫秒
```
### 2. Cron 表达式
ZHub 支持标准 Cron 表达式格式:
```java
// 标准 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 表达式
```java
// 工作日每天9点和18点执行
"0 9,18 * * 1-5"
// 每月1号和15号执行
"0 0 1,15 * *"
// 每小时的0分和30分执行
"0,30 * * * *"
// 每5分钟执行
"*/5 * * * *"
```
---
## 数据库配置
### 1. 数据库表结构
ZHub 定时任务数据库表结构:
```sql
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. 配置示例
```sql
-- 插入定时任务配置
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` 中配置数据库连接:
```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. 单实例执行
```java
// 单实例执行:只有一个客户端实例会执行任务
zhub.timer("single-task", () -> {
System.out.println("只有一个实例执行此任务");
});
```
### 2. 多实例执行
```java
// 多实例执行:所有客户端实例都会执行任务
zhub.timer("multi-task", () -> {
System.out.println("所有实例都会执行此任务");
});
```
### 3. 动态重载配置
```bash
# 通过管理接口重新加载定时任务配置
curl http://127.0.0.1:711/timer/reload
```
### 4. 本地定时任务
ZHub 客户端还提供本地定时任务功能:
```java
// 本地延时任务(适用于短时间延时)
Timers.delay(() -> {
System.out.println("延时5秒后执行");
}, 5000);
// 本地重试任务
Timers.tryDelay(() -> {
// 返回 true 表示成功false 表示需要重试
return processTask();
}, 1000, 3); // 每1秒重试一次最多重试3次
```
---
## 实际应用场景
### 1. 数据同步任务
```java
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. 监控和告警
```java
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. 缓存刷新
```java
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. 任务命名规范
```java
// 推荐:使用有意义的任务名称
zhub.timer("user:data-sync", () -> {});
zhub.timer("order:status-check", () -> {});
zhub.timer("system:health-check", () -> {});
// 避免:使用无意义的名称
zhub.timer("task1", () -> {});
zhub.timer("timer", () -> {});
```
### 2. 异常处理
```java
zhub.timer("safe-task", () -> {
try {
// 任务逻辑
processTask();
} catch (Exception e) {
logger.error("定时任务执行失败", e);
// 发送告警或记录错误
}
});
```
### 3. 性能优化
```java
// 避免在定时任务中执行耗时操作
zhub.timer("light-task", () -> {
// 快速执行的任务
updateStatus();
});
// 耗时操作应该异步执行
zhub.timer("heavy-task", () -> {
CompletableFuture.runAsync(() -> {
// 异步执行耗时操作
processHeavyTask();
});
});
```
### 4. 监控和日志
```java
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
- 时间表达式格式错误
**解决方法**
```bash
# 检查数据库连接
curl http://127.0.0.1:711/_/info
# 重新加载配置
curl http://127.0.0.1:711/timer/reload
# 检查任务状态
SELECT * FROM tasktimer WHERE status = 10;
```
### 2. 任务重复执行
**可能原因**
- 多个客户端实例都订阅了同一个任务
- 单实例配置错误
**解决方法**
```sql
-- 确保单实例配置正确
UPDATE tasktimer SET single = 1 WHERE name = 'task-name';
```
### 3. 任务执行时间不准确
**可能原因**
- 系统时间不同步
- 任务执行时间过长
**解决方法**
- 同步系统时间
- 优化任务执行逻辑
- 考虑拆分长时间任务
---
## 监控和调试
### 1. 任务执行状态
```bash
# 查看所有定时任务状态
curl http://127.0.0.1:711/_/info | jq '.timersize'
```
### 2. 日志监控
```java
// 在任务中添加详细日志
zhub.timer("logged-task", () -> {
logger.info("定时任务开始执行: {}", LocalDateTime.now());
try {
processTask();
logger.info("定时任务执行完成: {}", LocalDateTime.now());
} catch (Exception e) {
logger.error("定时任务执行异常: {}", e.getMessage(), e);
}
});
```
### 3. 性能监控
```java
// 监控任务执行时间
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);
}
}
}
}
```