@pisell/core 1.0.27 → 1.0.28

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.
@@ -38,7 +38,10 @@ var import_useTasks = __toESM(require("./useTasks"));
38
38
  var TasksManager = class _TasksManager {
39
39
  static instance;
40
40
  taskFunctions;
41
- tasks;
41
+ tasks = {
42
+ // 内置模块, 定时任务专用
43
+ scheduledTasks: {}
44
+ };
42
45
  app;
43
46
  db;
44
47
  useTasks = import_useTasks.default;
@@ -51,7 +54,9 @@ var TasksManager = class _TasksManager {
51
54
  }
52
55
  this.app = app;
53
56
  this.taskFunctions = /* @__PURE__ */ new Map();
54
- this.tasks = {};
57
+ this.tasks = {
58
+ scheduledTasks: {}
59
+ };
55
60
  this.db = app.dbManager;
56
61
  this.timerIds = [];
57
62
  }
@@ -183,6 +188,149 @@ var TasksManager = class _TasksManager {
183
188
  }
184
189
  this.timerIds = [..._timerIds || []];
185
190
  };
191
+ /**
192
+ * @title: 计算下一次执行时间
193
+ * @description: 根据定时任务配置计算下一次执行时间
194
+ * @param {Task} task
195
+ * @return {string | null} 下一次执行时间
196
+ */
197
+ calculateNextExecuteTime = (task) => {
198
+ if (!task.scheduled) {
199
+ return null;
200
+ }
201
+ const { scheduled, scheduledResult } = task;
202
+ const now = (0, import_dayjs.default)();
203
+ if (scheduled.endAt && now.isAfter((0, import_dayjs.default)(scheduled.endAt))) {
204
+ return null;
205
+ }
206
+ if (Array.isArray(scheduled.executeAt)) {
207
+ const futureTime = scheduled.executeAt.map((time) => (0, import_dayjs.default)(time)).filter((time) => time.isAfter(now)).sort((a, b) => a.valueOf() - b.valueOf())[0];
208
+ if (futureTime) {
209
+ return futureTime.format("YYYY-MM-DD HH:mm:ss");
210
+ }
211
+ if (!scheduled.repeat) {
212
+ return null;
213
+ }
214
+ }
215
+ if (scheduled.repeat && (scheduledResult == null ? void 0 : scheduledResult.nextExecuteTime)) {
216
+ const lastExecuteTime = (0, import_dayjs.default)(scheduledResult.nextExecuteTime);
217
+ const interval = scheduled.repeatInterval || 1;
218
+ let nextTime = lastExecuteTime;
219
+ switch (scheduled.repeatType) {
220
+ case "daily":
221
+ nextTime = lastExecuteTime.add(interval, "day");
222
+ break;
223
+ case "weekly":
224
+ nextTime = lastExecuteTime.add(interval, "week");
225
+ break;
226
+ case "monthly":
227
+ nextTime = lastExecuteTime.add(interval, "month");
228
+ break;
229
+ case "yearly":
230
+ nextTime = lastExecuteTime.add(interval, "year");
231
+ break;
232
+ default:
233
+ nextTime = lastExecuteTime.add(interval, "day");
234
+ }
235
+ if (scheduled.endAt && nextTime.isAfter((0, import_dayjs.default)(scheduled.endAt))) {
236
+ return null;
237
+ }
238
+ return nextTime.format("YYYY-MM-DD HH:mm:ss");
239
+ }
240
+ const executeTime = Array.isArray(scheduled.executeAt) ? scheduled.executeAt[0] : scheduled.executeAt;
241
+ return (0, import_dayjs.default)(executeTime).format("YYYY-MM-DD HH:mm:ss");
242
+ };
243
+ /**
244
+ * @title: 启动定时任务
245
+ * @description: 在特定时间点执行任务(仅在 scheduledTasks 模块中生效)
246
+ * @param {Task} task
247
+ * @return {*}
248
+ */
249
+ startScheduledTask = (task) => {
250
+ var _a;
251
+ if (!task.scheduled) {
252
+ console.log("Tasks--->", "不是定时任务");
253
+ return;
254
+ }
255
+ if (task.module !== "scheduledTasks") {
256
+ console.warn("Tasks--->", `定时任务只在 scheduledTasks 模块中生效,任务 ${task.id} 将作为普通任务执行`);
257
+ return;
258
+ }
259
+ const nextExecuteTime = this.calculateNextExecuteTime(task);
260
+ if (!nextExecuteTime) {
261
+ console.log("Tasks--->", "定时任务已完成或无下次执行时间", task);
262
+ this.deleteTask({
263
+ module: task.module,
264
+ queueId: task.queueId,
265
+ taskId: task.id
266
+ });
267
+ return;
268
+ }
269
+ const now = (0, import_dayjs.default)();
270
+ const executeTime = (0, import_dayjs.default)(nextExecuteTime);
271
+ const delay = executeTime.diff(now);
272
+ if (delay < 0) {
273
+ console.log("Tasks--->", "执行时间已过,跳过此次执行");
274
+ if (task.scheduled.repeat) {
275
+ const _task = { ...task };
276
+ _task.scheduledResult = {
277
+ count: ((_a = _task.scheduledResult) == null ? void 0 : _a.count) || 0,
278
+ nextExecuteTime
279
+ };
280
+ const newTask = this.updateTask({
281
+ module: task.module,
282
+ queueId: task.queueId,
283
+ taskId: task.id,
284
+ other: _task
285
+ });
286
+ if (newTask) {
287
+ this.startScheduledTask(newTask);
288
+ }
289
+ } else {
290
+ this.deleteTask({
291
+ module: task.module,
292
+ queueId: task.queueId,
293
+ taskId: task.id
294
+ });
295
+ }
296
+ return;
297
+ }
298
+ console.log("Tasks--->", `定时任务将在 ${nextExecuteTime} 执行 (${delay}ms 后)`, task);
299
+ const timerId = setTimeout(async () => {
300
+ var _a2, _b;
301
+ try {
302
+ await this.runTask(task);
303
+ console.log("Tasks--->", "定时任务执行完成", task);
304
+ let _task = { ...task };
305
+ _task.scheduledResult = {
306
+ count: (((_a2 = _task.scheduledResult) == null ? void 0 : _a2.count) || 0) + 1,
307
+ timerId,
308
+ nextExecuteTime
309
+ };
310
+ if ((_b = task.scheduled) == null ? void 0 : _b.repeat) {
311
+ const newTask = this.updateTask({
312
+ module: task.module,
313
+ queueId: task.queueId,
314
+ taskId: task.id,
315
+ other: _task
316
+ });
317
+ if (newTask) {
318
+ this.startScheduledTask(newTask);
319
+ }
320
+ } else {
321
+ this.deleteTask({
322
+ module: task.module,
323
+ queueId: task.queueId,
324
+ taskId: task.id
325
+ });
326
+ }
327
+ } catch (error) {
328
+ this.clearTaskTimer({ timerId });
329
+ console.error("定时任务执行异常", error);
330
+ }
331
+ }, delay);
332
+ this.timerIds.push({ taskId: task.id, timerId });
333
+ };
186
334
  /**
187
335
  * @title: 启动轮询
188
336
  * @description: 根据轮询间隔定期执行任务
@@ -273,82 +421,116 @@ var TasksManager = class _TasksManager {
273
421
  * @Date: 2024-09-26 13:52
274
422
  */
275
423
  async run(payload) {
276
- var _a, _b;
424
+ var _a, _b, _c, _d, _e;
277
425
  const { queueId, module: module2, callback } = payload;
426
+ const currentQueue = (_a = this.tasks[module2]) == null ? void 0 : _a[queueId];
427
+ if (currentQueue == null ? void 0 : currentQueue.isRunning) {
428
+ console.warn(
429
+ "Tasks--->",
430
+ `任务队列 [${module2}/${queueId}] 正在执行中,已拦截重复调用。`,
431
+ `当前进度: ${((_b = currentQueue.progress) == null ? void 0 : _b.completed) || 0}/${((_c = currentQueue.progress) == null ? void 0 : _c.total) || 0}`,
432
+ `如需重新执行,请等待当前任务队列执行完成。`
433
+ );
434
+ return;
435
+ }
436
+ this.updateQueueRunningState({
437
+ module: module2,
438
+ queueId,
439
+ isRunning: true,
440
+ lastRunAt: (0, import_dayjs.default)().format("YYYY-MM-DD HH:mm:ss")
441
+ });
442
+ console.log("Tasks--->", `任务队列 [${module2}/${queueId}] 开始执行`);
278
443
  let taskQueueStatus = "";
279
- while (taskQueueStatus !== "completed") {
280
- const taskQueue = this.getTaskQueue(payload);
281
- const errorTaskIds = [];
282
- if (taskQueue && taskQueue.length) {
283
- const tasksToExecute = taskQueue.filter(
284
- (task) => (task == null ? void 0 : task.status) === "pending" || (task == null ? void 0 : task.status) === "failure"
285
- );
286
- console.log("Tasks--->", "需要执行的任务", tasksToExecute);
287
- for (let task of tasksToExecute) {
288
- try {
289
- if (task.retries !== void 0 && task.maxRetries !== void 0 && task.retries < task.maxRetries) {
290
- task.status = "in-progress";
291
- this.updateTask({ module: module2, queueId, taskId: task.id, other: { status: task.status } });
292
- if (task.polling) {
293
- this.startPolling(task);
294
- } else {
295
- const { status } = await this.runTask(task);
296
- task.status = status;
297
- }
298
- if (task.status === "success") {
299
- if ((_a = task.pollingResult) == null ? void 0 : _a.timerId) {
444
+ try {
445
+ while (taskQueueStatus !== "completed") {
446
+ const taskQueue = this.getTaskQueue(payload);
447
+ const errorTaskIds = [];
448
+ if (taskQueue && taskQueue.length) {
449
+ const tasksToExecute = taskQueue.filter(
450
+ (task) => (task == null ? void 0 : task.status) === "pending" || (task == null ? void 0 : task.status) === "failure"
451
+ );
452
+ console.log("Tasks--->", "需要执行的任务", tasksToExecute);
453
+ for (let task of tasksToExecute) {
454
+ try {
455
+ if (task.retries !== void 0 && task.maxRetries !== void 0 && task.retries < task.maxRetries) {
456
+ task.status = "in-progress";
457
+ this.updateTask({ module: module2, queueId, taskId: task.id, other: { status: task.status } });
458
+ if (task.scheduled && module2 === "scheduledTasks") {
459
+ this.startScheduledTask(task);
460
+ } else if (task.polling) {
461
+ this.startPolling(task);
462
+ } else {
463
+ const { status } = await this.runTask(task);
464
+ task.status = status;
300
465
  }
301
- this.deleteTask({ module: module2, queueId, taskId: task.id });
302
- } else {
303
- let _other = {
304
- status: task.status
305
- };
306
- if (task.status === "failure") {
307
- _other.retries = task.retries + 1;
466
+ if (task.status === "success") {
467
+ if ((_d = task.pollingResult) == null ? void 0 : _d.timerId) {
468
+ }
469
+ this.deleteTask({ module: module2, queueId, taskId: task.id });
470
+ } else {
471
+ let _other = {
472
+ status: task.status
473
+ };
474
+ if (task.status === "failure") {
475
+ _other.retries = task.retries + 1;
476
+ }
477
+ errorTaskIds.push(task.id);
478
+ this.updateTask({ module: module2, queueId, taskId: task.id, other: _other });
308
479
  }
309
- errorTaskIds.push(task.id);
310
- this.updateTask({ module: module2, queueId, taskId: task.id, other: _other });
480
+ } else {
481
+ console.log("Tasks--->", "任务没有重试次数,需要删除", task);
482
+ this.deleteTask({ module: module2, queueId, taskId: task.id });
311
483
  }
312
- } else {
313
- console.log("Tasks--->", "任务没有重试次数,需要删除", task);
314
- this.deleteTask({ module: module2, queueId, taskId: task.id });
484
+ } catch (error) {
485
+ console.error("任务异常", error);
315
486
  }
316
- } catch (error) {
317
- console.error("任务异常", error);
318
487
  }
488
+ taskQueueStatus = ((_e = this.getTaskQueue(payload)) == null ? void 0 : _e.some((task) => task.status === "failure")) ? "uncompleted" : "completed";
489
+ this.updateQueueStatus({
490
+ queueId,
491
+ module: module2,
492
+ status: taskQueueStatus
493
+ });
494
+ console.log("Tasks--->", "任务队列执行完成", taskQueue);
495
+ } else {
496
+ taskQueueStatus = "completed";
497
+ }
498
+ if (taskQueueStatus === "uncompleted") {
499
+ this.app.logger.addLog({
500
+ type: "info",
501
+ title: `任务队列执行存在失败-${queueId}`,
502
+ metadata: { taskQueue, errorTaskIds }
503
+ });
504
+ await this.timeout();
505
+ } else if (taskQueueStatus === "completed") {
506
+ console.log("Tasks--->", "任务队列全部执行完成");
507
+ callback == null ? void 0 : callback();
319
508
  }
320
- taskQueueStatus = ((_b = this.getTaskQueue(payload)) == null ? void 0 : _b.some((task) => task.status === "failure")) ? "uncompleted" : "completed";
321
- this.updateQueueStatus({
322
- queueId,
323
- module: module2,
324
- status: taskQueueStatus
325
- });
326
- console.log("Tasks--->", "任务队列执行完成", taskQueue);
327
- } else {
328
- taskQueueStatus = "completed";
329
- }
330
- if (taskQueueStatus === "uncompleted") {
331
- this.app.logger.addLog({
332
- type: "info",
333
- title: `任务队列执行存在失败-${queueId}`,
334
- metadata: { taskQueue, errorTaskIds }
335
- });
336
- await this.timeout();
337
- } else if (taskQueueStatus === "completed") {
338
- console.log("Tasks--->", "任务队列全部执行完成");
339
- callback == null ? void 0 : callback();
340
509
  }
510
+ } finally {
511
+ this.updateQueueRunningState({
512
+ module: module2,
513
+ queueId,
514
+ isRunning: false
515
+ });
516
+ console.log("Tasks--->", `任务队列 [${module2}/${queueId}] 执行结束`);
341
517
  }
342
518
  }
343
519
  deleteTask(payload) {
344
520
  var _a, _b, _c, _d;
345
521
  const { queueId, module: module2, taskId } = payload;
346
522
  this.tasks[module2][queueId].tasks = (_d = (_c = (_b = (_a = this.tasks) == null ? void 0 : _a[module2]) == null ? void 0 : _b[queueId]) == null ? void 0 : _c.tasks) == null ? void 0 : _d.filter((task) => {
347
- var _a2;
348
- if ((_a2 = task.pollingResult) == null ? void 0 : _a2.timerId) {
349
- this.clearTaskTimer({ timerId: task.pollingResult.timerId });
523
+ var _a2, _b2;
524
+ if (task.id === taskId) {
525
+ if ((_a2 = task.pollingResult) == null ? void 0 : _a2.timerId) {
526
+ this.clearTaskTimer({ timerId: task.pollingResult.timerId });
527
+ }
528
+ if ((_b2 = task.scheduledResult) == null ? void 0 : _b2.timerId) {
529
+ this.clearTaskTimer({ timerId: task.scheduledResult.timerId });
530
+ }
531
+ return false;
350
532
  }
351
- return task.id !== taskId;
533
+ return true;
352
534
  });
353
535
  this.saveTaskQueueToLocal(this.tasks);
354
536
  console.log("Tasks--->", "删除指定任务", queueId, module2, taskId);
@@ -371,6 +553,13 @@ var TasksManager = class _TasksManager {
371
553
  const taskQueue = (_b = (_a = this.tasks[module2]) == null ? void 0 : _a[queueId]) == null ? void 0 : _b.tasks;
372
554
  let _tasks = [...taskQueue || []];
373
555
  let newTasks = (_c = tasks == null ? void 0 : tasks.map) == null ? void 0 : _c.call(tasks, (d) => {
556
+ if (d.scheduled && module2 !== "scheduledTasks") {
557
+ console.warn(
558
+ "Tasks--->",
559
+ `检测到定时任务配置,但模块为 "${module2}"。定时任务功能仅在 "scheduledTasks" 模块中生效。`,
560
+ `该任务将作为普通任务立即执行。如需使用定时功能,请将任务添加到 "scheduledTasks" 模块。`
561
+ );
562
+ }
374
563
  return this.createTaskData({ ...d, queueId, module: module2 });
375
564
  });
376
565
  _tasks = _tasks.concat(newTasks);
@@ -407,22 +596,19 @@ var TasksManager = class _TasksManager {
407
596
  }
408
597
  updateQueueStatus(payload) {
409
598
  const { queueId, status, module: module2 } = payload;
410
- const newState = {
411
- ...this.tasks,
412
- [module2]: {
413
- ...this.tasks[module2],
414
- [queueId]: {
415
- ...this.tasks[module2][queueId],
416
- status
417
- }
418
- }
419
- };
420
- this.saveTaskQueueToLocal(newState);
421
- this.tasks = newState;
599
+ this.setTasksData({ queueId, module: module2, status });
600
+ }
601
+ /**
602
+ * @title: 更新队列运行状态
603
+ * @description: 标记队列是否正在执行
604
+ */
605
+ updateQueueRunningState(payload) {
606
+ const { queueId, module: module2, isRunning, lastRunAt } = payload;
607
+ this.setTasksData({ queueId, module: module2, isRunning, lastRunAt });
422
608
  }
423
609
  // 设置任务
424
- setTasks(payload) {
425
- const { queueId, module: module2, tasks } = payload;
610
+ setTasksData(payload) {
611
+ const { queueId, module: module2, ...data } = payload;
426
612
  const moduleData = this.tasks[module2] || {};
427
613
  const queueIdData = moduleData[queueId] || {};
428
614
  const newState = {
@@ -431,13 +617,18 @@ var TasksManager = class _TasksManager {
431
617
  ...moduleData,
432
618
  [queueId]: {
433
619
  ...queueIdData,
434
- tasks
620
+ ...data
435
621
  }
436
622
  }
437
623
  };
438
624
  this.saveTaskQueueToLocal(newState);
439
625
  this.tasks = newState;
440
626
  }
627
+ // 设置任务
628
+ setTasks(payload) {
629
+ const { queueId, module: module2, tasks } = payload;
630
+ this.setTasksData({ queueId, module: module2, tasks });
631
+ }
441
632
  clearAllTaskTimer(tasks) {
442
633
  for (let task of tasks || []) {
443
634
  this.clearTaskTimer({ taskId: task.id });
@@ -445,7 +636,11 @@ var TasksManager = class _TasksManager {
445
636
  }
446
637
  // 清空任务
447
638
  clearTasks(payload) {
639
+ var _a, _b;
448
640
  const { queueId, module: module2 } = payload;
641
+ if (!((_b = (_a = this.tasks) == null ? void 0 : _a[module2]) == null ? void 0 : _b[queueId])) {
642
+ return;
643
+ }
449
644
  this.clearAllTaskTimer(this.tasks[module2][queueId].tasks);
450
645
  this.tasks[module2][queueId].tasks = [];
451
646
  this.saveTaskQueueToLocal(this.tasks);
@@ -466,6 +661,60 @@ var TasksManager = class _TasksManager {
466
661
  watchTask(callback) {
467
662
  this.watchTaskCallback = callback;
468
663
  }
664
+ /**
665
+ * @title: 获取队列执行状态
666
+ * @description: 获取指定队列的执行状态和进度信息
667
+ * @param {string} module - 模块名
668
+ * @param {string} queueId - 队列ID
669
+ * @return {object} 队列状态信息
670
+ */
671
+ getQueueStatus(module2, queueId) {
672
+ var _a, _b;
673
+ const queue = (_a = this.tasks[module2]) == null ? void 0 : _a[queueId];
674
+ if (!queue) {
675
+ return null;
676
+ }
677
+ return {
678
+ isRunning: queue.isRunning || false,
679
+ status: queue.status,
680
+ progress: queue.progress || {
681
+ total: 0,
682
+ completed: 0,
683
+ failed: 0,
684
+ inProgress: 0
685
+ },
686
+ lastRunAt: queue.lastRunAt || null,
687
+ tasksCount: ((_b = queue.tasks) == null ? void 0 : _b.length) || 0
688
+ };
689
+ }
690
+ /**
691
+ * @title: 获取所有队列状态
692
+ * @description: 获取所有任务队列的执行状态概览
693
+ * @return {object} 所有队列的状态信息
694
+ */
695
+ getAllQueuesStatus() {
696
+ var _a;
697
+ const result = {};
698
+ for (const module2 in this.tasks) {
699
+ result[module2] = {};
700
+ for (const queueId in this.tasks[module2]) {
701
+ const queue = this.tasks[module2][queueId];
702
+ result[module2][queueId] = {
703
+ isRunning: queue.isRunning || false,
704
+ status: queue.status,
705
+ progress: queue.progress || {
706
+ total: 0,
707
+ completed: 0,
708
+ failed: 0,
709
+ inProgress: 0
710
+ },
711
+ lastRunAt: queue.lastRunAt || null,
712
+ tasksCount: ((_a = queue.tasks) == null ? void 0 : _a.length) || 0
713
+ };
714
+ }
715
+ }
716
+ return result;
717
+ }
469
718
  };
470
719
  // Annotate the CommonJS export names for ESM import in node:
471
720
  0 && (module.exports = {