hyper-scheduler 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.editorconfig +21 -0
- package/.eslintrc.cjs +26 -0
- package/GEMINI.md +1 -0
- package/README.md +38 -0
- package/docs/.vitepress/config.ts +52 -0
- package/docs/README.md +120 -0
- package/docs/api/devtools.md +232 -0
- package/docs/api/index.md +178 -0
- package/docs/api/scheduler.md +322 -0
- package/docs/api/task.md +439 -0
- package/docs/api/types.md +365 -0
- package/docs/examples/index.md +295 -0
- package/docs/guide/best-practices.md +436 -0
- package/docs/guide/core-concepts.md +363 -0
- package/docs/guide/getting-started.md +138 -0
- package/docs/index.md +33 -0
- package/docs/public/logo.svg +54 -0
- package/examples/browser/index.html +354 -0
- package/examples/node/simple.js +36 -0
- package/examples/react-demo/index.html +12 -0
- package/examples/react-demo/package.json +23 -0
- package/examples/react-demo/src/App.css +212 -0
- package/examples/react-demo/src/App.jsx +160 -0
- package/examples/react-demo/src/main.jsx +9 -0
- package/examples/react-demo/vite.config.ts +12 -0
- package/examples/react-demo/yarn.lock +752 -0
- package/examples/vue-demo/index.html +12 -0
- package/examples/vue-demo/package.json +21 -0
- package/examples/vue-demo/src/App.vue +373 -0
- package/examples/vue-demo/src/main.ts +4 -0
- package/examples/vue-demo/vite.config.ts +13 -0
- package/examples/vue-demo/yarn.lock +375 -0
- package/package.json +51 -0
- package/src/constants.ts +18 -0
- package/src/core/retry-strategy.ts +28 -0
- package/src/core/scheduler.ts +601 -0
- package/src/core/task-registry.ts +58 -0
- package/src/index.ts +74 -0
- package/src/platform/browser/browser-timer.ts +66 -0
- package/src/platform/browser/main-thread-timer.ts +16 -0
- package/src/platform/browser/worker.ts +31 -0
- package/src/platform/node/debug-cli.ts +19 -0
- package/src/platform/node/node-timer.ts +15 -0
- package/src/platform/timer-strategy.ts +19 -0
- package/src/plugins/dev-tools.ts +101 -0
- package/src/types.ts +115 -0
- package/src/ui/components/devtools.ts +525 -0
- package/src/ui/components/floating-trigger.ts +102 -0
- package/src/ui/components/icons.ts +16 -0
- package/src/ui/components/resizer.ts +129 -0
- package/src/ui/components/task-detail.ts +228 -0
- package/src/ui/components/task-header.ts +319 -0
- package/src/ui/components/task-list.ts +416 -0
- package/src/ui/components/timeline.ts +364 -0
- package/src/ui/debug-panel.ts +56 -0
- package/src/ui/i18n/en.ts +76 -0
- package/src/ui/i18n/index.ts +42 -0
- package/src/ui/i18n/zh.ts +76 -0
- package/src/ui/store/dev-tools-store.ts +191 -0
- package/src/ui/styles/theme.css.ts +56 -0
- package/src/ui/styles.ts +43 -0
- package/src/utils/cron-lite.ts +221 -0
- package/src/utils/cron.ts +20 -0
- package/src/utils/id.ts +10 -0
- package/src/utils/schedule.ts +93 -0
- package/src/vite-env.d.ts +1 -0
- package/stats.html +4949 -0
- package/tests/integration/Debug.test.ts +58 -0
- package/tests/unit/Plugin.test.ts +16 -0
- package/tests/unit/RetryStrategy.test.ts +21 -0
- package/tests/unit/Scheduler.test.ts +38 -0
- package/tests/unit/schedule.test.ts +70 -0
- package/tests/unit/ui/DevToolsStore.test.ts +67 -0
- package/tsconfig.json +28 -0
- package/vite.config.ts +51 -0
- package/vitest.config.ts +24 -0
package/docs/api/task.md
ADDED
|
@@ -0,0 +1,439 @@
|
|
|
1
|
+
# Task
|
|
2
|
+
|
|
3
|
+
任务是调度器的基本执行单元,包含调度规则、执行逻辑和配置选项。
|
|
4
|
+
|
|
5
|
+
## TaskDefinition
|
|
6
|
+
|
|
7
|
+
任务定义接口,用于创建新任务。
|
|
8
|
+
|
|
9
|
+
```typescript
|
|
10
|
+
interface TaskDefinition {
|
|
11
|
+
id: string;
|
|
12
|
+
schedule: string;
|
|
13
|
+
handler: () => void | Promise<void>;
|
|
14
|
+
tags?: string[];
|
|
15
|
+
options?: TaskOptions;
|
|
16
|
+
}
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
### 属性
|
|
20
|
+
|
|
21
|
+
#### id
|
|
22
|
+
|
|
23
|
+
- **类型**: `string`
|
|
24
|
+
- **必填**: ✓
|
|
25
|
+
|
|
26
|
+
任务的唯一标识符,用于查询、触发、停止等操作。
|
|
27
|
+
|
|
28
|
+
```typescript
|
|
29
|
+
scheduler.createTask({
|
|
30
|
+
id: 'daily-report',
|
|
31
|
+
// ...
|
|
32
|
+
});
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
#### schedule
|
|
36
|
+
|
|
37
|
+
- **类型**: `string`
|
|
38
|
+
- **必填**: ✓
|
|
39
|
+
|
|
40
|
+
任务的调度规则,支持两种格式:
|
|
41
|
+
|
|
42
|
+
**1. Cron 表达式**
|
|
43
|
+
|
|
44
|
+
标准的 6 位 Cron 表达式:`秒 分 时 日 月 周`
|
|
45
|
+
|
|
46
|
+
```typescript
|
|
47
|
+
// 每分钟执行
|
|
48
|
+
schedule: '0 * * * * *'
|
|
49
|
+
|
|
50
|
+
// 每 5 秒执行
|
|
51
|
+
schedule: '*/5 * * * * *'
|
|
52
|
+
|
|
53
|
+
// 每天凌晨 2:00 执行
|
|
54
|
+
schedule: '0 0 2 * * *'
|
|
55
|
+
|
|
56
|
+
// 每周一 9:00 执行
|
|
57
|
+
schedule: '0 0 9 * * 1'
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
**2. 时间间隔**
|
|
61
|
+
|
|
62
|
+
人性化的时间间隔字符串:
|
|
63
|
+
|
|
64
|
+
```typescript
|
|
65
|
+
// 每 30 秒
|
|
66
|
+
schedule: '30s'
|
|
67
|
+
|
|
68
|
+
// 每 5 分钟
|
|
69
|
+
schedule: '5m'
|
|
70
|
+
|
|
71
|
+
// 每 2 小时
|
|
72
|
+
schedule: '2h'
|
|
73
|
+
|
|
74
|
+
// 每天
|
|
75
|
+
schedule: '1d'
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
#### handler
|
|
79
|
+
|
|
80
|
+
- **类型**: `() => void | Promise<void>`
|
|
81
|
+
- **必填**: ✓
|
|
82
|
+
|
|
83
|
+
任务执行函数,支持同步和异步。
|
|
84
|
+
|
|
85
|
+
```typescript
|
|
86
|
+
// 同步函数
|
|
87
|
+
handler: () => {
|
|
88
|
+
console.log('Task executed');
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// 异步函数
|
|
92
|
+
handler: async () => {
|
|
93
|
+
const data = await fetchData();
|
|
94
|
+
await processData(data);
|
|
95
|
+
}
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
#### tags
|
|
99
|
+
|
|
100
|
+
- **类型**: `string[]`
|
|
101
|
+
- **可选**
|
|
102
|
+
|
|
103
|
+
任务标签,用于分类和过滤。
|
|
104
|
+
|
|
105
|
+
```typescript
|
|
106
|
+
scheduler.createTask({
|
|
107
|
+
id: 'sync-orders',
|
|
108
|
+
schedule: '1m',
|
|
109
|
+
tags: ['sync', 'orders', 'critical'],
|
|
110
|
+
handler: async () => {
|
|
111
|
+
await syncOrders();
|
|
112
|
+
}
|
|
113
|
+
});
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
#### options
|
|
117
|
+
|
|
118
|
+
- **类型**: `TaskOptions`
|
|
119
|
+
- **可选**
|
|
120
|
+
|
|
121
|
+
任务配置选项,详见 [TaskOptions](#taskoptions)。
|
|
122
|
+
|
|
123
|
+
## TaskOptions
|
|
124
|
+
|
|
125
|
+
任务配置选项接口。
|
|
126
|
+
|
|
127
|
+
```typescript
|
|
128
|
+
interface TaskOptions {
|
|
129
|
+
retry?: RetryConfig;
|
|
130
|
+
timezone?: string;
|
|
131
|
+
driver?: 'main' | 'worker';
|
|
132
|
+
onError?: (error: Error, taskId: string) => void;
|
|
133
|
+
}
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
### retry
|
|
137
|
+
|
|
138
|
+
- **类型**: `RetryConfig`
|
|
139
|
+
- **可选**
|
|
140
|
+
|
|
141
|
+
任务失败时的重试配置。
|
|
142
|
+
|
|
143
|
+
```typescript
|
|
144
|
+
interface RetryConfig {
|
|
145
|
+
maxAttempts: number; // 最大重试次数
|
|
146
|
+
initialDelay: number; // 首次重试延迟(毫秒)
|
|
147
|
+
factor?: number; // 延迟递增因子,默认 2
|
|
148
|
+
}
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
重试延迟计算公式:`initialDelay * (factor ^ attempt)`
|
|
152
|
+
|
|
153
|
+
#### 示例
|
|
154
|
+
|
|
155
|
+
```typescript
|
|
156
|
+
scheduler.createTask({
|
|
157
|
+
id: 'api-call',
|
|
158
|
+
schedule: '1m',
|
|
159
|
+
handler: async () => {
|
|
160
|
+
await callAPI();
|
|
161
|
+
},
|
|
162
|
+
options: {
|
|
163
|
+
retry: {
|
|
164
|
+
maxAttempts: 3,
|
|
165
|
+
initialDelay: 1000,
|
|
166
|
+
factor: 2
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
// 重试延迟序列:
|
|
172
|
+
// 第 1 次重试:1000ms (1s)
|
|
173
|
+
// 第 2 次重试:2000ms (2s)
|
|
174
|
+
// 第 3 次重试:4000ms (4s)
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
### timezone
|
|
178
|
+
|
|
179
|
+
- **类型**: `string`
|
|
180
|
+
- **可选**
|
|
181
|
+
|
|
182
|
+
任务专属时区,覆盖全局时区设置。使用 IANA 时区标识符。
|
|
183
|
+
|
|
184
|
+
#### 示例
|
|
185
|
+
|
|
186
|
+
```typescript
|
|
187
|
+
scheduler.createTask({
|
|
188
|
+
id: 'tokyo-report',
|
|
189
|
+
schedule: '0 0 9 * * *', // 每天 9:00
|
|
190
|
+
handler: () => generateReport(),
|
|
191
|
+
options: {
|
|
192
|
+
timezone: 'Asia/Tokyo'
|
|
193
|
+
}
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
scheduler.createTask({
|
|
197
|
+
id: 'ny-report',
|
|
198
|
+
schedule: '0 0 9 * * *', // 每天 9:00
|
|
199
|
+
handler: () => generateReport(),
|
|
200
|
+
options: {
|
|
201
|
+
timezone: 'America/New_York'
|
|
202
|
+
}
|
|
203
|
+
});
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
### driver
|
|
207
|
+
|
|
208
|
+
- **类型**: `'main' | 'worker'`
|
|
209
|
+
- **默认值**: `'worker'`
|
|
210
|
+
- **可选**
|
|
211
|
+
|
|
212
|
+
指定任务的运行环境(驱动模式)。
|
|
213
|
+
|
|
214
|
+
| 模式 | 说明 | 适用场景 |
|
|
215
|
+
|------|------|----------|
|
|
216
|
+
| `'worker'` | 任务在 Web Worker 线程中运行计时器 | 繁重计算、高频任务、不想阻塞 UI |
|
|
217
|
+
| `'main'` | 任务在主线程中运行 (setInterval/setTimeout) | 需要访问 DOM 或 window 对象、简单的 UI 更新 |
|
|
218
|
+
|
|
219
|
+
#### 示例
|
|
220
|
+
|
|
221
|
+
```typescript
|
|
222
|
+
// 在 Worker 中运行(默认)
|
|
223
|
+
scheduler.createTask({
|
|
224
|
+
id: 'heavy-calc',
|
|
225
|
+
schedule: '5s',
|
|
226
|
+
handler: () => heavyComputation(),
|
|
227
|
+
options: {
|
|
228
|
+
driver: 'worker'
|
|
229
|
+
}
|
|
230
|
+
});
|
|
231
|
+
|
|
232
|
+
// 在主线程中运行
|
|
233
|
+
scheduler.createTask({
|
|
234
|
+
id: 'ui-update',
|
|
235
|
+
schedule: '1s',
|
|
236
|
+
handler: () => updateClockUI(),
|
|
237
|
+
options: {
|
|
238
|
+
driver: 'main'
|
|
239
|
+
}
|
|
240
|
+
});
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
### onError
|
|
244
|
+
|
|
245
|
+
- **类型**: `(error: Error, taskId: string) => void`
|
|
246
|
+
- **可选**
|
|
247
|
+
|
|
248
|
+
任务执行失败时的错误处理回调函数。
|
|
249
|
+
|
|
250
|
+
#### 示例
|
|
251
|
+
|
|
252
|
+
```typescript
|
|
253
|
+
scheduler.createTask({
|
|
254
|
+
id: 'critical-task',
|
|
255
|
+
schedule: '30s',
|
|
256
|
+
handler: async () => {
|
|
257
|
+
await criticalOperation();
|
|
258
|
+
},
|
|
259
|
+
options: {
|
|
260
|
+
onError: (error, taskId) => {
|
|
261
|
+
// 记录错误日志
|
|
262
|
+
logger.error(`Task ${taskId} failed:`, error);
|
|
263
|
+
|
|
264
|
+
// 发送告警通知
|
|
265
|
+
alertService.send({
|
|
266
|
+
title: 'Task Failed',
|
|
267
|
+
message: error.message,
|
|
268
|
+
taskId
|
|
269
|
+
});
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
});
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
## Task
|
|
276
|
+
|
|
277
|
+
任务运行时对象,继承自 `TaskDefinition` 并包含运行时状态。
|
|
278
|
+
|
|
279
|
+
```typescript
|
|
280
|
+
interface Task extends TaskDefinition {
|
|
281
|
+
status: TaskStatus;
|
|
282
|
+
lastRun?: number;
|
|
283
|
+
nextRun?: number;
|
|
284
|
+
executionCount?: number;
|
|
285
|
+
history: ExecutionRecord[];
|
|
286
|
+
}
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
### 属性
|
|
290
|
+
|
|
291
|
+
#### status
|
|
292
|
+
|
|
293
|
+
- **类型**: `TaskStatus`
|
|
294
|
+
|
|
295
|
+
任务当前状态。
|
|
296
|
+
|
|
297
|
+
```typescript
|
|
298
|
+
type TaskStatus = 'idle' | 'running' | 'stopped' | 'error';
|
|
299
|
+
```
|
|
300
|
+
|
|
301
|
+
| 状态 | 说明 |
|
|
302
|
+
|------|------|
|
|
303
|
+
| `idle` | 等待调度,将在下次触发时间执行 |
|
|
304
|
+
| `running` | 正在执行 |
|
|
305
|
+
| `stopped` | 已停止,不参与调度 |
|
|
306
|
+
| `error` | 执行出错 |
|
|
307
|
+
|
|
308
|
+
#### lastRun
|
|
309
|
+
|
|
310
|
+
- **类型**: `number | undefined`
|
|
311
|
+
|
|
312
|
+
上次执行时间戳(毫秒)。
|
|
313
|
+
|
|
314
|
+
```typescript
|
|
315
|
+
const task = scheduler.getTask('my-task');
|
|
316
|
+
if (task.lastRun) {
|
|
317
|
+
console.log('Last run:', new Date(task.lastRun));
|
|
318
|
+
}
|
|
319
|
+
```
|
|
320
|
+
|
|
321
|
+
#### nextRun
|
|
322
|
+
|
|
323
|
+
- **类型**: `number | undefined`
|
|
324
|
+
|
|
325
|
+
下次执行时间戳(毫秒)。
|
|
326
|
+
|
|
327
|
+
```typescript
|
|
328
|
+
const task = scheduler.getTask('my-task');
|
|
329
|
+
if (task.nextRun) {
|
|
330
|
+
console.log('Next run:', new Date(task.nextRun));
|
|
331
|
+
console.log('Time until next run:', task.nextRun - Date.now(), 'ms');
|
|
332
|
+
}
|
|
333
|
+
```
|
|
334
|
+
|
|
335
|
+
#### executionCount
|
|
336
|
+
|
|
337
|
+
- **类型**: `number | undefined`
|
|
338
|
+
|
|
339
|
+
任务累计执行次数。
|
|
340
|
+
|
|
341
|
+
```typescript
|
|
342
|
+
const task = scheduler.getTask('my-task');
|
|
343
|
+
console.log(`Executed ${task.executionCount} times`);
|
|
344
|
+
```
|
|
345
|
+
|
|
346
|
+
#### history
|
|
347
|
+
|
|
348
|
+
- **类型**: `ExecutionRecord[]`
|
|
349
|
+
|
|
350
|
+
任务执行历史记录数组,最多保留 `maxHistory` 条(默认 50)。
|
|
351
|
+
|
|
352
|
+
```typescript
|
|
353
|
+
interface ExecutionRecord {
|
|
354
|
+
timestamp: number; // 执行时间戳
|
|
355
|
+
duration: number; // 执行耗时(毫秒)
|
|
356
|
+
success: boolean; // 是否成功
|
|
357
|
+
error?: string; // 错误信息(失败时)
|
|
358
|
+
}
|
|
359
|
+
```
|
|
360
|
+
|
|
361
|
+
#### 示例
|
|
362
|
+
|
|
363
|
+
```typescript
|
|
364
|
+
const task = scheduler.getTask('my-task');
|
|
365
|
+
|
|
366
|
+
// 查看最近 5 次执行
|
|
367
|
+
task.history.slice(-5).forEach(record => {
|
|
368
|
+
const time = new Date(record.timestamp).toLocaleString();
|
|
369
|
+
const status = record.success ? '✓' : '✗';
|
|
370
|
+
console.log(`${status} ${time} - ${record.duration}ms`);
|
|
371
|
+
if (record.error) {
|
|
372
|
+
console.log(` Error: ${record.error}`);
|
|
373
|
+
}
|
|
374
|
+
});
|
|
375
|
+
|
|
376
|
+
// 计算成功率
|
|
377
|
+
const successCount = task.history.filter(r => r.success).length;
|
|
378
|
+
const successRate = (successCount / task.history.length * 100).toFixed(2);
|
|
379
|
+
console.log(`Success rate: ${successRate}%`);
|
|
380
|
+
|
|
381
|
+
// 计算平均执行时间
|
|
382
|
+
const avgDuration = task.history.reduce((sum, r) => sum + r.duration, 0) / task.history.length;
|
|
383
|
+
console.log(`Average duration: ${avgDuration.toFixed(2)}ms`);
|
|
384
|
+
```
|
|
385
|
+
|
|
386
|
+
## 完整示例
|
|
387
|
+
|
|
388
|
+
```typescript
|
|
389
|
+
import { Scheduler } from 'hyper-scheduler';
|
|
390
|
+
|
|
391
|
+
const scheduler = new Scheduler({
|
|
392
|
+
debug: true,
|
|
393
|
+
maxHistory: 100
|
|
394
|
+
});
|
|
395
|
+
|
|
396
|
+
// 创建带完整配置的任务
|
|
397
|
+
scheduler.createTask({
|
|
398
|
+
id: 'data-sync',
|
|
399
|
+
schedule: '*/30 * * * * *', // 每 30 秒
|
|
400
|
+
tags: ['sync', 'data', 'high-priority'],
|
|
401
|
+
handler: async () => {
|
|
402
|
+
const data = await fetchRemoteData();
|
|
403
|
+
await saveToDatabase(data);
|
|
404
|
+
},
|
|
405
|
+
options: {
|
|
406
|
+
timezone: 'Asia/Shanghai',
|
|
407
|
+
retry: {
|
|
408
|
+
maxAttempts: 3,
|
|
409
|
+
initialDelay: 1000,
|
|
410
|
+
factor: 2
|
|
411
|
+
},
|
|
412
|
+
onError: (error, taskId) => {
|
|
413
|
+
console.error(`[${taskId}] Error:`, error.message);
|
|
414
|
+
// 发送告警
|
|
415
|
+
sendAlert({
|
|
416
|
+
taskId,
|
|
417
|
+
error: error.message,
|
|
418
|
+
timestamp: Date.now()
|
|
419
|
+
});
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
});
|
|
423
|
+
|
|
424
|
+
scheduler.start();
|
|
425
|
+
|
|
426
|
+
// 查询任务状态
|
|
427
|
+
setTimeout(() => {
|
|
428
|
+
const task = scheduler.getTask('data-sync');
|
|
429
|
+
console.log('Task status:', task.status);
|
|
430
|
+
console.log('Execution count:', task.executionCount);
|
|
431
|
+
console.log('Last 3 executions:', task.history.slice(-3));
|
|
432
|
+
}, 60000);
|
|
433
|
+
```
|
|
434
|
+
|
|
435
|
+
## 相关链接
|
|
436
|
+
|
|
437
|
+
- [Scheduler API](./scheduler.md) - 调度器 API
|
|
438
|
+
- [核心概念](../guide/core-concepts.md) - 任务状态流转
|
|
439
|
+
- [类型定义](./types.md) - 完整类型定义
|