@nocobase/plugin-async-task-manager 2.1.2 → 2.1.3
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/dist/externalVersion.js
CHANGED
|
@@ -8,19 +8,19 @@
|
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
10
|
module.exports = {
|
|
11
|
-
"@nocobase/client": "2.1.
|
|
11
|
+
"@nocobase/client": "2.1.3",
|
|
12
12
|
"react": "18.2.0",
|
|
13
|
-
"@nocobase/utils": "2.1.
|
|
14
|
-
"@nocobase/flow-engine": "2.1.
|
|
15
|
-
"@nocobase/client-v2": "2.1.
|
|
13
|
+
"@nocobase/utils": "2.1.3",
|
|
14
|
+
"@nocobase/flow-engine": "2.1.3",
|
|
15
|
+
"@nocobase/client-v2": "2.1.3",
|
|
16
16
|
"lodash": "4.18.1",
|
|
17
|
-
"@nocobase/server": "2.1.
|
|
18
|
-
"@nocobase/logger": "2.1.
|
|
19
|
-
"@nocobase/database": "2.1.
|
|
17
|
+
"@nocobase/server": "2.1.3",
|
|
18
|
+
"@nocobase/logger": "2.1.3",
|
|
19
|
+
"@nocobase/database": "2.1.3",
|
|
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.
|
|
25
|
+
"@nocobase/actions": "2.1.3"
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
287
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
353
|
+
logger.debug(`Starting execution of task ${task.record.id} from queue`);
|
|
340
354
|
await task.run();
|
|
341
355
|
} catch (error) {
|
|
342
|
-
|
|
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?:
|
|
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.
|
|
9
|
+
"version": "2.1.3",
|
|
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": "
|
|
22
|
+
"gitHead": "f61e75119a74bbac25879f4edb8cf9913c99098a"
|
|
23
23
|
}
|