@nocobase/plugin-async-task-manager 2.1.2 → 2.1.4

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.
@@ -8,19 +8,19 @@
8
8
  */
9
9
 
10
10
  module.exports = {
11
- "@nocobase/client": "2.1.2",
11
+ "@nocobase/client": "2.1.4",
12
12
  "react": "18.2.0",
13
- "@nocobase/utils": "2.1.2",
14
- "@nocobase/flow-engine": "2.1.2",
15
- "@nocobase/client-v2": "2.1.2",
13
+ "@nocobase/utils": "2.1.4",
14
+ "@nocobase/flow-engine": "2.1.4",
15
+ "@nocobase/client-v2": "2.1.4",
16
16
  "lodash": "4.18.1",
17
- "@nocobase/server": "2.1.2",
18
- "@nocobase/logger": "2.1.2",
19
- "@nocobase/database": "2.1.2",
17
+ "@nocobase/server": "2.1.4",
18
+ "@nocobase/logger": "2.1.4",
19
+ "@nocobase/database": "2.1.4",
20
20
  "antd": "5.24.2",
21
21
  "react-i18next": "11.18.6",
22
22
  "dayjs": "1.11.13",
23
23
  "@ant-design/icons": "5.6.1",
24
24
  "ahooks": "3.7.8",
25
- "@nocobase/actions": "2.1.2"
25
+ "@nocobase/actions": "2.1.4"
26
26
  };
@@ -15,6 +15,7 @@ import { ConcurrencyMode, ConcurrencyMonitor } from './interfaces/concurrency-mo
15
15
  export declare class BaseTaskManager implements AsyncTasksManager {
16
16
  private taskTypes;
17
17
  private tasks;
18
+ private taskReqIds;
18
19
  private readonly cleanupDelay;
19
20
  private cleanupTimer;
20
21
  private logger;
@@ -35,13 +36,14 @@ export declare class BaseTaskManager implements AsyncTasksManager {
35
36
  setLogger(logger: Logger): void;
36
37
  setApp(app: Application): void;
37
38
  private enqueueTask;
39
+ private getTaskLogger;
38
40
  cancelTask(taskId: TaskId, externally?: boolean): Promise<void>;
39
41
  createTask(data: TaskModel, { useQueue, ...options }?: CreateTaskOptions): Promise<ITask>;
40
42
  getTask(taskId: TaskId): ITask | undefined;
41
43
  getTaskStatus(taskId: TaskId): Promise<TaskStatus>;
42
44
  registerTaskType(taskType: TaskConstructor): void;
43
45
  private prepareTask;
44
- runTask(task: ITask): Promise<void>;
46
+ runTask(task: ITask, reqId?: string): Promise<void>;
45
47
  }
46
48
  export declare class ConcurrencyMonitorDelegate implements ConcurrencyMonitor {
47
49
  private mode;
@@ -52,6 +52,7 @@ const PROCESS_CONCURRENCY_MONITOR = new import_base_concurrency_monitor.BaseConc
52
52
  class BaseTaskManager {
53
53
  taskTypes = /* @__PURE__ */ new Map();
54
54
  tasks = /* @__PURE__ */ new Map();
55
+ taskReqIds = /* @__PURE__ */ new Map();
55
56
  // Clean up completed tasks after 30 minutes by default
56
57
  cleanupDelay = 30 * 60 * 1e3;
57
58
  cleanupTimer;
@@ -66,21 +67,21 @@ class BaseTaskManager {
66
67
  this.concurrencyMonitor.concurrency = concurrency;
67
68
  }
68
69
  idle = () => this.app.serving(WORKER_JOB_ASYNC_TASK_PROCESS) && this.concurrencyMonitor.idle();
69
- onQueueTask = async ({ id }, { queueOptions }) => {
70
+ onQueueTask = async ({ id, reqId }, { queueOptions }) => {
70
71
  const task = await this.prepareTask(id);
71
72
  if (!this.concurrencyMonitor.increase(task.record.id)) {
72
- this.enqueueTask(task, queueOptions);
73
+ this.enqueueTask(task, queueOptions, reqId);
73
74
  return;
74
75
  }
75
76
  try {
76
- await this.runTask(task);
77
+ await this.runTask(task, reqId);
77
78
  } finally {
78
79
  this.concurrencyMonitor.decrease(task.record.id);
79
80
  }
80
81
  };
81
- onTaskProgress = (item) => {
82
+ onTaskProgress = (item, logger) => {
82
83
  const userId = item.createdById;
83
- this.logger.trace(`Task ${item.id} of user(${userId}) progress: ${item.progressCurrent} / ${item.progressTotal}`);
84
+ logger.trace(`Task ${item.id} of user(${userId}) progress: ${item.progressCurrent} / ${item.progressTotal}`);
84
85
  if (userId) {
85
86
  const throttledEmit = this.getThrottledProgressEmitter(item.id, userId);
86
87
  throttledEmit(item);
@@ -100,6 +101,12 @@ class BaseTaskManager {
100
101
  };
101
102
  onTaskStatusChanged = (task) => {
102
103
  if (!task.changed("status")) return;
104
+ if (task.doneAt) {
105
+ this.progressThrottles.delete(task.id);
106
+ this.tasks.delete(task.id);
107
+ this.taskReqIds.delete(task.id);
108
+ this.concurrencyMonitor.decrease(task.id);
109
+ }
103
110
  const userId = task.createdById;
104
111
  if (!userId) return;
105
112
  this.app.emit("ws:sendToUser", {
@@ -119,17 +126,13 @@ class BaseTaskManager {
119
126
  this.progressThrottles.delete(task.id);
120
127
  }
121
128
  }
122
- if (task.doneAt) {
123
- this.progressThrottles.delete(task.id);
124
- this.tasks.delete(task.id);
125
- this.concurrencyMonitor.decrease(task.id);
126
- }
127
129
  if (task.status === import_constants.TASK_STATUS.SUCCEEDED) {
128
130
  this.app.emit("workflow:dispatch");
129
131
  }
130
132
  };
131
133
  onTaskAfterDelete = (task) => {
132
134
  this.tasks.delete(task.id);
135
+ this.taskReqIds.delete(task.id);
133
136
  this.progressThrottles.delete(task.id);
134
137
  this.concurrencyMonitor.decrease(task.id);
135
138
  const userId = task.createdById;
@@ -170,6 +173,7 @@ class BaseTaskManager {
170
173
  if (tasksToCleanup.length) {
171
174
  for (const task of tasksToCleanup) {
172
175
  this.tasks.delete(task.id);
176
+ this.taskReqIds.delete(task.id);
173
177
  this.progressThrottles.delete(task.id);
174
178
  this.concurrencyMonitor.decrease(task.id);
175
179
  }
@@ -238,9 +242,12 @@ class BaseTaskManager {
238
242
  this.app.db.on("asyncTasks.afterUpdate", this.onTaskStatusChanged);
239
243
  this.app.db.on("asyncTasks.afterDestroy", this.onTaskAfterDelete);
240
244
  }
241
- enqueueTask(task, queueOptions) {
245
+ enqueueTask(task, queueOptions, reqId = this.taskReqIds.get(task.record.id)) {
242
246
  const plugin = this.app.pm.get(import_plugin.default);
243
- this.app.eventQueue.publish(`${plugin.name}.task`, { id: task.record.id }, queueOptions);
247
+ this.app.eventQueue.publish(`${plugin.name}.task`, { id: task.record.id, reqId }, queueOptions);
248
+ }
249
+ getTaskLogger(reqId) {
250
+ return reqId ? this.logger.child({ reqId }) : this.logger;
244
251
  }
245
252
  async cancelTask(taskId, externally = false) {
246
253
  const task = this.tasks.get(taskId);
@@ -271,9 +278,12 @@ class BaseTaskManager {
271
278
  }
272
279
  }
273
280
  async createTask(data, { useQueue, ...options } = {}) {
281
+ var _a;
282
+ const reqId = (_a = options.context) == null ? void 0 : _a.reqId;
283
+ const logger = this.getTaskLogger(reqId);
274
284
  const taskType = this.taskTypes.get(data.type);
275
285
  if (!taskType) {
276
- this.logger.error(`Task type not found: ${data.type}, params: ${JSON.stringify(data.params)}`);
286
+ logger.error(`Task type not found: ${data.type}, params: ${JSON.stringify(data.params)}`);
277
287
  throw new Error(`Task type ${data.type} not found`);
278
288
  }
279
289
  const values = taskType.defaults({
@@ -283,14 +293,17 @@ class BaseTaskManager {
283
293
  });
284
294
  const DBTaskModel = this.app.db.getModel("asyncTasks");
285
295
  const record = await DBTaskModel.create(values, options);
286
- this.logger.debug(`Creating task of type: ${data.type}`);
287
- this.logger.debug(`Task data: ${JSON.stringify(data)}`);
296
+ logger.debug(`Creating task of type: ${data.type}`);
297
+ logger.debug(`Task data: ${JSON.stringify(data)}`);
288
298
  const task = new taskType(record);
289
- this.logger.info(`New task of type: ${data.type} created as ${record.id}`);
299
+ if (reqId && !useQueue) {
300
+ this.taskReqIds.set(record.id, reqId);
301
+ }
302
+ logger.info(`New task of type: ${data.type} created as ${record.id}`);
290
303
  if (useQueue) {
291
- this.logger.debug(`New task ${record.id} will be sent to queue for processing`);
304
+ logger.debug(`New task ${record.id} will be sent to queue for processing`);
292
305
  const queueOptions = typeof useQueue === "object" ? useQueue : {};
293
- this.enqueueTask(task, queueOptions);
306
+ this.enqueueTask(task, queueOptions, reqId);
294
307
  }
295
308
  return task;
296
309
  }
@@ -329,19 +342,21 @@ class BaseTaskManager {
329
342
  const task = new taskType(record);
330
343
  return task;
331
344
  }
332
- async runTask(task) {
345
+ async runTask(task, reqId = this.taskReqIds.get(task.record.id)) {
333
346
  if (task.record.status === import_constants.TASK_STATUS.PENDING) {
334
- task.setLogger(this.logger);
347
+ const logger = this.getTaskLogger(reqId);
348
+ task.setLogger(logger);
335
349
  task.setApp(this.app);
336
- task.onProgress = this.onTaskProgress;
350
+ task.onProgress = (record) => this.onTaskProgress(record, logger);
337
351
  this.tasks.set(task.record.id, task);
338
352
  try {
339
- this.logger.debug(`Starting execution of task ${task.record.id} from queue`);
353
+ logger.debug(`Starting execution of task ${task.record.id} from queue`);
340
354
  await task.run();
341
355
  } catch (error) {
342
- this.logger.error(`Error executing task ${task.record.id} from queue: ${error.message}`);
356
+ logger.error(`Error executing task ${task.record.id} from queue: ${error.message}`);
343
357
  } finally {
344
358
  this.tasks.delete(task.record.id);
359
+ this.taskReqIds.delete(task.record.id);
345
360
  }
346
361
  }
347
362
  }
@@ -13,7 +13,9 @@ import { TaskId, TaskStatus } from '../../common/types';
13
13
  import { Transactionable } from '@nocobase/database';
14
14
  export interface CreateTaskOptions extends Transactionable {
15
15
  useQueue?: boolean | QueueMessageOptions;
16
- context?: any;
16
+ context?: object & {
17
+ reqId?: string;
18
+ };
17
19
  }
18
20
  export interface AsyncTasksManager {
19
21
  concurrency: number;
@@ -24,7 +26,7 @@ export interface AsyncTasksManager {
24
26
  cancelTask(taskId: TaskId): Promise<void>;
25
27
  getTaskStatus(taskId: TaskId): Promise<TaskStatus>;
26
28
  getTask(taskId: TaskId): ITask | undefined;
27
- runTask(task: ITask): Promise<void>;
29
+ runTask(task: ITask, reqId?: string): Promise<void>;
28
30
  }
29
31
  export declare class CancelError extends Error {
30
32
  constructor(message?: string);
package/package.json CHANGED
@@ -6,7 +6,7 @@
6
6
  "description": "Manage and monitor asynchronous tasks such as data import/export. Support task progress tracking and notification.",
7
7
  "description.ru-RU": "Управление асинхронными задачами и мониторинг (например, импорт/экспорт данных). Поддержка отслеживания прогресса и уведомлений о задачах.",
8
8
  "description.zh-CN": "管理和监控数据导入导出等异步任务。支持任务进度跟踪和通知。",
9
- "version": "2.1.2",
9
+ "version": "2.1.4",
10
10
  "main": "dist/server/index.js",
11
11
  "peerDependencies": {
12
12
  "@nocobase/client": "2.x",
@@ -19,5 +19,5 @@
19
19
  "p-queue": "^6.6.2"
20
20
  },
21
21
  "license": "Apache-2.0",
22
- "gitHead": "e1b28561425c5c34ff3bc6ae1f81c66b72f02872"
22
+ "gitHead": "73c01b1e842afdaafdffd6fa4bb090c1da9b0816"
23
23
  }