@push.rocks/taskbuffer 5.0.0 → 6.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/dist_ts/00_commitinfo_data.js +1 -1
- package/dist_ts/index.d.ts +1 -1
- package/dist_ts/taskbuffer.classes.taskconstraintgroup.d.ts +4 -2
- package/dist_ts/taskbuffer.classes.taskconstraintgroup.js +11 -4
- package/dist_ts/taskbuffer.classes.taskmanager.d.ts +1 -0
- package/dist_ts/taskbuffer.classes.taskmanager.js +43 -9
- package/dist_ts/taskbuffer.interfaces.d.ts +7 -1
- package/dist_ts_web/00_commitinfo_data.js +1 -1
- package/package.json +1 -1
- package/readme.hints.md +5 -3
- package/readme.md +108 -12
- package/ts/00_commitinfo_data.ts +1 -1
- package/ts/index.ts +1 -1
- package/ts/taskbuffer.classes.taskconstraintgroup.ts +13 -4
- package/ts/taskbuffer.classes.taskmanager.ts +47 -11
- package/ts/taskbuffer.interfaces.ts +8 -1
- package/ts_web/00_commitinfo_data.ts +1 -1
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*/
|
|
4
4
|
export const commitinfo = {
|
|
5
5
|
name: '@push.rocks/taskbuffer',
|
|
6
|
-
version: '
|
|
6
|
+
version: '6.0.0',
|
|
7
7
|
description: 'A flexible task management library supporting TypeScript, allowing for task buffering, scheduling, and execution with dependency management.'
|
|
8
8
|
};
|
|
9
9
|
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiMDBfY29tbWl0aW5mb19kYXRhLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vdHMvMDBfY29tbWl0aW5mb19kYXRhLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOztHQUVHO0FBQ0gsTUFBTSxDQUFDLE1BQU0sVUFBVSxHQUFHO0lBQ3hCLElBQUksRUFBRSx3QkFBd0I7SUFDOUIsT0FBTyxFQUFFLE9BQU87SUFDaEIsV0FBVyxFQUFFLDhJQUE4STtDQUM1SixDQUFBIn0=
|
package/dist_ts/index.d.ts
CHANGED
|
@@ -8,6 +8,6 @@ export { TaskDebounced } from './taskbuffer.classes.taskdebounced.js';
|
|
|
8
8
|
export { TaskConstraintGroup } from './taskbuffer.classes.taskconstraintgroup.js';
|
|
9
9
|
export { TaskStep } from './taskbuffer.classes.taskstep.js';
|
|
10
10
|
export type { ITaskStep } from './taskbuffer.classes.taskstep.js';
|
|
11
|
-
export type { ITaskMetadata, ITaskExecutionReport, IScheduledTaskInfo, ITaskEvent, TTaskEventType, ITaskConstraintGroupOptions } from './taskbuffer.interfaces.js';
|
|
11
|
+
export type { ITaskMetadata, ITaskExecutionReport, IScheduledTaskInfo, ITaskEvent, TTaskEventType, ITaskConstraintGroupOptions, ITaskExecution } from './taskbuffer.interfaces.js';
|
|
12
12
|
import * as distributedCoordination from './taskbuffer.classes.distributedcoordinator.js';
|
|
13
13
|
export { distributedCoordination };
|
|
@@ -4,11 +4,13 @@ export declare class TaskConstraintGroup<TData extends Record<string, unknown> =
|
|
|
4
4
|
name: string;
|
|
5
5
|
maxConcurrent: number;
|
|
6
6
|
cooldownMs: number;
|
|
7
|
-
private
|
|
7
|
+
private constraintKeyForExecution;
|
|
8
|
+
private shouldExecuteFn?;
|
|
8
9
|
private runningCounts;
|
|
9
10
|
private lastCompletionTimes;
|
|
10
11
|
constructor(options: ITaskConstraintGroupOptions<TData>);
|
|
11
|
-
getConstraintKey(task: Task<any, any, TData
|
|
12
|
+
getConstraintKey(task: Task<any, any, TData>, input?: any): string | null;
|
|
13
|
+
checkShouldExecute(task: Task<any, any, TData>, input?: any): Promise<boolean>;
|
|
12
14
|
canRun(subGroupKey: string): boolean;
|
|
13
15
|
acquireSlot(subGroupKey: string): void;
|
|
14
16
|
releaseSlot(subGroupKey: string): void;
|
|
@@ -3,14 +3,21 @@ export class TaskConstraintGroup {
|
|
|
3
3
|
this.runningCounts = new Map();
|
|
4
4
|
this.lastCompletionTimes = new Map();
|
|
5
5
|
this.name = options.name;
|
|
6
|
-
this.
|
|
6
|
+
this.constraintKeyForExecution = options.constraintKeyForExecution;
|
|
7
7
|
this.maxConcurrent = options.maxConcurrent ?? Infinity;
|
|
8
8
|
this.cooldownMs = options.cooldownMs ?? 0;
|
|
9
|
+
this.shouldExecuteFn = options.shouldExecute;
|
|
9
10
|
}
|
|
10
|
-
getConstraintKey(task) {
|
|
11
|
-
const key = this.
|
|
11
|
+
getConstraintKey(task, input) {
|
|
12
|
+
const key = this.constraintKeyForExecution(task, input);
|
|
12
13
|
return key ?? null;
|
|
13
14
|
}
|
|
15
|
+
async checkShouldExecute(task, input) {
|
|
16
|
+
if (!this.shouldExecuteFn) {
|
|
17
|
+
return true;
|
|
18
|
+
}
|
|
19
|
+
return this.shouldExecuteFn(task, input);
|
|
20
|
+
}
|
|
14
21
|
canRun(subGroupKey) {
|
|
15
22
|
const running = this.runningCounts.get(subGroupKey) ?? 0;
|
|
16
23
|
if (running >= this.maxConcurrent) {
|
|
@@ -61,4 +68,4 @@ export class TaskConstraintGroup {
|
|
|
61
68
|
this.lastCompletionTimes.clear();
|
|
62
69
|
}
|
|
63
70
|
}
|
|
64
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
71
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidGFza2J1ZmZlci5jbGFzc2VzLnRhc2tjb25zdHJhaW50Z3JvdXAuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi90cy90YXNrYnVmZmVyLmNsYXNzZXMudGFza2NvbnN0cmFpbnRncm91cC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFHQSxNQUFNLE9BQU8sbUJBQW1CO0lBVTlCLFlBQVksT0FBMkM7UUFIL0Msa0JBQWEsR0FBRyxJQUFJLEdBQUcsRUFBa0IsQ0FBQztRQUMxQyx3QkFBbUIsR0FBRyxJQUFJLEdBQUcsRUFBa0IsQ0FBQztRQUd0RCxJQUFJLENBQUMsSUFBSSxHQUFHLE9BQU8sQ0FBQyxJQUFJLENBQUM7UUFDekIsSUFBSSxDQUFDLHlCQUF5QixHQUFHLE9BQU8sQ0FBQyx5QkFBeUIsQ0FBQztRQUNuRSxJQUFJLENBQUMsYUFBYSxHQUFHLE9BQU8sQ0FBQyxhQUFhLElBQUksUUFBUSxDQUFDO1FBQ3ZELElBQUksQ0FBQyxVQUFVLEdBQUcsT0FBTyxDQUFDLFVBQVUsSUFBSSxDQUFDLENBQUM7UUFDMUMsSUFBSSxDQUFDLGVBQWUsR0FBRyxPQUFPLENBQUMsYUFBYSxDQUFDO0lBQy9DLENBQUM7SUFFTSxnQkFBZ0IsQ0FBQyxJQUEyQixFQUFFLEtBQVc7UUFDOUQsTUFBTSxHQUFHLEdBQUcsSUFBSSxDQUFDLHlCQUF5QixDQUFDLElBQUksRUFBRSxLQUFLLENBQUMsQ0FBQztRQUN4RCxPQUFPLEdBQUcsSUFBSSxJQUFJLENBQUM7SUFDckIsQ0FBQztJQUVNLEtBQUssQ0FBQyxrQkFBa0IsQ0FBQyxJQUEyQixFQUFFLEtBQVc7UUFDdEUsSUFBSSxDQUFDLElBQUksQ0FBQyxlQUFlLEVBQUUsQ0FBQztZQUMxQixPQUFPLElBQUksQ0FBQztRQUNkLENBQUM7UUFDRCxPQUFPLElBQUksQ0FBQyxlQUFlLENBQUMsSUFBSSxFQUFFLEtBQUssQ0FBQyxDQUFDO0lBQzNDLENBQUM7SUFFTSxNQUFNLENBQUMsV0FBbUI7UUFDL0IsTUFB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
|
|
@@ -29,6 +29,7 @@ export declare class TaskManager {
|
|
|
29
29
|
addConstraintGroup(group: TaskConstraintGroup<any>): void;
|
|
30
30
|
removeConstraintGroup(name: string): void;
|
|
31
31
|
triggerTaskConstrained(task: Task<any, any, any>, input?: any): Promise<any>;
|
|
32
|
+
private checkAllShouldExecute;
|
|
32
33
|
private executeWithConstraintTracking;
|
|
33
34
|
private drainConstraintQueue;
|
|
34
35
|
triggerTaskByName(taskName: string): Promise<any>;
|
|
@@ -56,13 +56,17 @@ export class TaskManager {
|
|
|
56
56
|
// Gather applicable constraints
|
|
57
57
|
const applicableGroups = [];
|
|
58
58
|
for (const group of this.constraintGroups) {
|
|
59
|
-
const key = group.getConstraintKey(task);
|
|
59
|
+
const key = group.getConstraintKey(task, input);
|
|
60
60
|
if (key !== null) {
|
|
61
61
|
applicableGroups.push({ group, key });
|
|
62
62
|
}
|
|
63
63
|
}
|
|
64
|
-
// No constraints apply → trigger directly
|
|
64
|
+
// No constraints apply → check shouldExecute then trigger directly
|
|
65
65
|
if (applicableGroups.length === 0) {
|
|
66
|
+
const shouldRun = await this.checkAllShouldExecute(task, input);
|
|
67
|
+
if (!shouldRun) {
|
|
68
|
+
return undefined;
|
|
69
|
+
}
|
|
66
70
|
return task.trigger(input);
|
|
67
71
|
}
|
|
68
72
|
// Check if all constraints allow running
|
|
@@ -70,16 +74,39 @@ export class TaskManager {
|
|
|
70
74
|
if (allCanRun) {
|
|
71
75
|
return this.executeWithConstraintTracking(task, input, applicableGroups);
|
|
72
76
|
}
|
|
73
|
-
// Blocked → enqueue with deferred promise
|
|
77
|
+
// Blocked → enqueue with deferred promise and cached constraint keys
|
|
74
78
|
const deferred = plugins.smartpromise.defer();
|
|
75
|
-
|
|
79
|
+
const constraintKeys = new Map();
|
|
80
|
+
for (const { group, key } of applicableGroups) {
|
|
81
|
+
constraintKeys.set(group.name, key);
|
|
82
|
+
}
|
|
83
|
+
this.constraintQueue.push({ task, input, deferred, constraintKeys });
|
|
76
84
|
return deferred.promise;
|
|
77
85
|
}
|
|
86
|
+
async checkAllShouldExecute(task, input) {
|
|
87
|
+
for (const group of this.constraintGroups) {
|
|
88
|
+
const shouldRun = await group.checkShouldExecute(task, input);
|
|
89
|
+
if (!shouldRun) {
|
|
90
|
+
return false;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
return true;
|
|
94
|
+
}
|
|
78
95
|
async executeWithConstraintTracking(task, input, groups) {
|
|
79
|
-
// Acquire slots
|
|
96
|
+
// Acquire slots synchronously to prevent race conditions
|
|
80
97
|
for (const { group, key } of groups) {
|
|
81
98
|
group.acquireSlot(key);
|
|
82
99
|
}
|
|
100
|
+
// Check shouldExecute after acquiring slots
|
|
101
|
+
const shouldRun = await this.checkAllShouldExecute(task, input);
|
|
102
|
+
if (!shouldRun) {
|
|
103
|
+
// Release slots and drain queue
|
|
104
|
+
for (const { group, key } of groups) {
|
|
105
|
+
group.releaseSlot(key);
|
|
106
|
+
}
|
|
107
|
+
this.drainConstraintQueue();
|
|
108
|
+
return undefined;
|
|
109
|
+
}
|
|
83
110
|
try {
|
|
84
111
|
return await task.trigger(input);
|
|
85
112
|
}
|
|
@@ -97,18 +124,25 @@ export class TaskManager {
|
|
|
97
124
|
for (const entry of this.constraintQueue) {
|
|
98
125
|
const applicableGroups = [];
|
|
99
126
|
for (const group of this.constraintGroups) {
|
|
100
|
-
const key = group.getConstraintKey(entry.task);
|
|
127
|
+
const key = group.getConstraintKey(entry.task, entry.input);
|
|
101
128
|
if (key !== null) {
|
|
102
129
|
applicableGroups.push({ group, key });
|
|
103
130
|
}
|
|
104
131
|
}
|
|
105
|
-
// No constraints apply anymore (group removed?) → run
|
|
132
|
+
// No constraints apply anymore (group removed?) → check shouldExecute then run
|
|
106
133
|
if (applicableGroups.length === 0) {
|
|
107
|
-
entry.task
|
|
134
|
+
this.checkAllShouldExecute(entry.task, entry.input).then((shouldRun) => {
|
|
135
|
+
if (!shouldRun) {
|
|
136
|
+
entry.deferred.resolve(undefined);
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
entry.task.trigger(entry.input).then((result) => entry.deferred.resolve(result), (err) => entry.deferred.reject(err));
|
|
140
|
+
});
|
|
108
141
|
continue;
|
|
109
142
|
}
|
|
110
143
|
const allCanRun = applicableGroups.every(({ group, key }) => group.canRun(key));
|
|
111
144
|
if (allCanRun) {
|
|
145
|
+
// executeWithConstraintTracking handles shouldExecute check internally
|
|
112
146
|
this.executeWithConstraintTracking(entry.task, entry.input, applicableGroups).then((result) => entry.deferred.resolve(result), (err) => entry.deferred.reject(err));
|
|
113
147
|
}
|
|
114
148
|
else {
|
|
@@ -334,4 +368,4 @@ export class TaskManager {
|
|
|
334
368
|
}
|
|
335
369
|
}
|
|
336
370
|
}
|
|
337
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidGFza2J1ZmZlci5jbGFzc2VzLnRhc2ttYW5hZ2VyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vdHMvdGFza2J1ZmZlci5jbGFzc2VzLnRhc2ttYW5hZ2VyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sS0FBSyxPQUFPLE1BQU0seUJBQXlCLENBQUM7QUFDbkQsT0FBTyxFQUFFLElBQUksRUFBRSxNQUFNLDhCQUE4QixDQUFDO0FBQ3BELE9BQU8sRUFBRSxtQkFBbUIsRUFBRSxNQUFNLDZDQUE2QyxDQUFDO0FBQ2xGLE9BQU8sRUFDTCw4QkFBOEIsR0FFL0IsTUFBTSxnREFBZ0QsQ0FBQztBQUV4RCxPQUFPLEVBQUUsTUFBTSxFQUFFLE1BQU0seUJBQXlCLENBQUM7QUFZakQsTUFBTSxPQUFPLFdBQVc7SUFldEIsWUFBWSxVQUEwQyxFQUFFO1FBZGpELGFBQVEsR0FBRyxPQUFPLENBQUMsV0FBVyxDQUFDLE9BQU8sRUFBRSxDQUFDO1FBQ3pDLFlBQU8sR0FBRyxJQUFJLE9BQU8sQ0FBQyxHQUFHLENBQUMsU0FBUyxFQUF1QixDQUFDO1FBQ2xELGdCQUFXLEdBQUcsSUFBSSxPQUFPLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxPQUFPLEVBQWMsQ0FBQztRQUNyRSxzQkFBaUIsR0FBRyxJQUFJLEdBQUcsRUFBMEQsQ0FBQztRQUN0RixtQkFBYyxHQUFHLElBQUksT0FBTyxDQUFDLFNBQVMsQ0FBQyxXQUFXLEVBQUUsQ0FBQztRQUN0RCxZQUFPLEdBQW1DO1lBQy9DLHNCQUFzQixFQUFFLElBQUk7U0FDN0IsQ0FBQztRQUVGLG9CQUFvQjtRQUNiLHFCQUFnQixHQUErQixFQUFFLENBQUM7UUFDakQsb0JBQWUsR0FBNEIsRUFBRSxDQUFDO1FBQzlDLGVBQVUsR0FBeUMsSUFBSSxDQUFDO1FBRzlELElBQUksQ0FBQyxPQUFPLEdBQUcsTUFBTSxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsT0FBTyxFQUFFLE9BQU8sQ0FBQyxD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
|
|
371
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidGFza2J1ZmZlci5jbGFzc2VzLnRhc2ttYW5hZ2VyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vdHMvdGFza2J1ZmZlci5jbGFzc2VzLnRhc2ttYW5hZ2VyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sS0FBSyxPQUFPLE1BQU0seUJBQXlCLENBQUM7QUFDbkQsT0FBTyxFQUFFLElBQUksRUFBRSxNQUFNLDhCQUE4QixDQUFDO0FBQ3BELE9BQU8sRUFBRSxtQkFBbUIsRUFBRSxNQUFNLDZDQUE2QyxDQUFDO0FBQ2xGLE9BQU8sRUFDTCw4QkFBOEIsR0FFL0IsTUFBTSxnREFBZ0QsQ0FBQztBQUV4RCxPQUFPLEVBQUUsTUFBTSxFQUFFLE1BQU0seUJBQXlCLENBQUM7QUFZakQsTUFBTSxPQUFPLFdBQVc7SUFldEIsWUFBWSxVQUEwQyxFQUFFO1FBZGpELGFBQVEsR0FBRyxPQUFPLENBQUMsV0FBVyxDQUFDLE9BQU8sRUFBRSxDQUFDO1FBQ3pDLFlBQU8sR0FBRyxJQUFJLE9BQU8sQ0FBQyxHQUFHLENBQUMsU0FBUyxFQUF1QixDQUFDO1FBQ2xELGdCQUFXLEdBQUcsSUFBSSxPQUFPLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxPQUFPLEVBQWMsQ0FBQztRQUNyRSxzQkFBaUIsR0FBRyxJQUFJLEdBQUcsRUFBMEQsQ0FBQztRQUN0RixtQkFBYyxHQUFHLElBQUksT0FBTyxDQUFDLFNBQVMsQ0FBQyxXQUFXLEVBQUUsQ0FBQztRQUN0RCxZQUFPLEdBQW1DO1lBQy9DLHNCQUFzQixFQUFFLElBQUk7U0FDN0IsQ0FBQztRQUVGLG9CQUFvQjtRQUNiLHFCQUFnQixHQUErQixFQUFFLENBQUM7UUFDakQsb0JBQWUsR0FBNEIsRUFBRSxDQUFDO1FBQzlDLGVBQVUsR0FBeUMsSUFBSSxDQUFDO1FBRzlELElBQUksQ0FBQyxPQUFPLEdBQUcsTUFBTSxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsT0FBTyxFQUFFLE9BQU8sQ0FBQyxD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
|
|
@@ -2,14 +2,20 @@ import type { ITaskStep } from './taskbuffer.classes.taskstep.js';
|
|
|
2
2
|
import type { Task } from './taskbuffer.classes.task.js';
|
|
3
3
|
export interface ITaskConstraintGroupOptions<TData extends Record<string, unknown> = Record<string, unknown>> {
|
|
4
4
|
name: string;
|
|
5
|
-
|
|
5
|
+
constraintKeyForExecution: (task: Task<any, any, TData>, input?: any) => string | null | undefined;
|
|
6
6
|
maxConcurrent?: number;
|
|
7
7
|
cooldownMs?: number;
|
|
8
|
+
shouldExecute?: (task: Task<any, any, TData>, input?: any) => boolean | Promise<boolean>;
|
|
9
|
+
}
|
|
10
|
+
export interface ITaskExecution<TData extends Record<string, unknown> = Record<string, unknown>> {
|
|
11
|
+
task: Task<any, any, TData>;
|
|
12
|
+
input: any;
|
|
8
13
|
}
|
|
9
14
|
export interface IConstrainedTaskEntry {
|
|
10
15
|
task: Task<any, any, any>;
|
|
11
16
|
input: any;
|
|
12
17
|
deferred: import('@push.rocks/smartpromise').Deferred<any>;
|
|
18
|
+
constraintKeys: Map<string, string>;
|
|
13
19
|
}
|
|
14
20
|
export interface ITaskMetadata {
|
|
15
21
|
name: string;
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*/
|
|
4
4
|
export const commitinfo = {
|
|
5
5
|
name: '@push.rocks/taskbuffer',
|
|
6
|
-
version: '
|
|
6
|
+
version: '6.0.0',
|
|
7
7
|
description: 'A flexible task management library supporting TypeScript, allowing for task buffering, scheduling, and execution with dependency management.'
|
|
8
8
|
};
|
|
9
9
|
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiMDBfY29tbWl0aW5mb19kYXRhLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vdHNfd2ViLzAwX2NvbW1pdGluZm9fZGF0YS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7R0FFRztBQUNILE1BQU0sQ0FBQyxNQUFNLFVBQVUsR0FBRztJQUN4QixJQUFJLEVBQUUsd0JBQXdCO0lBQzlCLE9BQU8sRUFBRSxPQUFPO0lBQ2hCLFdBQVcsRUFBRSw4SUFBOEk7Q0FDNUosQ0FBQSJ9
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@push.rocks/taskbuffer",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "6.0.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "A flexible task management library supporting TypeScript, allowing for task buffering, scheduling, and execution with dependency management.",
|
|
6
6
|
"main": "dist_ts/index.js",
|
package/readme.hints.md
CHANGED
|
@@ -12,11 +12,13 @@
|
|
|
12
12
|
- Typed data bag accessible as `task.data`
|
|
13
13
|
|
|
14
14
|
### TaskConstraintGroup
|
|
15
|
-
- `new TaskConstraintGroup<TData>({ name,
|
|
16
|
-
- `
|
|
15
|
+
- `new TaskConstraintGroup<TData>({ name, constraintKeyForExecution, maxConcurrent?, cooldownMs?, shouldExecute? })`
|
|
16
|
+
- `constraintKeyForExecution(task, input?)` returns a string key (constraint applies) or `null` (skip). Receives both task and runtime input.
|
|
17
|
+
- `shouldExecute(task, input?)` — optional pre-execution check. Returns `false` to skip (deferred resolves `undefined`). Can be async.
|
|
17
18
|
- `maxConcurrent` (default: `Infinity`) — max concurrent tasks per key
|
|
18
19
|
- `cooldownMs` (default: `0`) — minimum ms gap between completions per key
|
|
19
|
-
- Methods: `canRun(key)`, `acquireSlot(key)`, `releaseSlot(key)`, `getCooldownRemaining(key)`, `getRunningCount(key)`, `reset()`
|
|
20
|
+
- Methods: `getConstraintKey(task, input?)`, `checkShouldExecute(task, input?)`, `canRun(key)`, `acquireSlot(key)`, `releaseSlot(key)`, `getCooldownRemaining(key)`, `getRunningCount(key)`, `reset()`
|
|
21
|
+
- `ITaskExecution<TData>` type exported from index — `{ task, input }` tuple
|
|
20
22
|
|
|
21
23
|
### TaskManager Constraint Integration
|
|
22
24
|
- `manager.addConstraintGroup(group)` / `manager.removeConstraintGroup(name)`
|
package/readme.md
CHANGED
|
@@ -120,7 +120,7 @@ const manager = new TaskManager();
|
|
|
120
120
|
const domainMutex = new TaskConstraintGroup<{ domain: string }>({
|
|
121
121
|
name: 'domain-mutex',
|
|
122
122
|
maxConcurrent: 1,
|
|
123
|
-
|
|
123
|
+
constraintKeyForExecution: (task, input?) => task.data.domain,
|
|
124
124
|
});
|
|
125
125
|
|
|
126
126
|
manager.addConstraintGroup(domainMutex);
|
|
@@ -156,7 +156,7 @@ Cap how many tasks can run concurrently across a group:
|
|
|
156
156
|
const dnsLimit = new TaskConstraintGroup<{ group: string }>({
|
|
157
157
|
name: 'dns-concurrency',
|
|
158
158
|
maxConcurrent: 3,
|
|
159
|
-
|
|
159
|
+
constraintKeyForExecution: (task) =>
|
|
160
160
|
task.data.group === 'dns' ? 'dns' : null, // null = skip constraint
|
|
161
161
|
});
|
|
162
162
|
|
|
@@ -173,7 +173,7 @@ const rateLimiter = new TaskConstraintGroup<{ domain: string }>({
|
|
|
173
173
|
name: 'api-rate-limit',
|
|
174
174
|
maxConcurrent: 1,
|
|
175
175
|
cooldownMs: 11000,
|
|
176
|
-
|
|
176
|
+
constraintKeyForExecution: (task) => task.data.domain,
|
|
177
177
|
});
|
|
178
178
|
|
|
179
179
|
manager.addConstraintGroup(rateLimiter);
|
|
@@ -187,7 +187,7 @@ Limit total concurrent tasks system-wide:
|
|
|
187
187
|
const globalCap = new TaskConstraintGroup({
|
|
188
188
|
name: 'global-cap',
|
|
189
189
|
maxConcurrent: 10,
|
|
190
|
-
|
|
190
|
+
constraintKeyForExecution: () => 'all', // same key = shared limit
|
|
191
191
|
});
|
|
192
192
|
|
|
193
193
|
manager.addConstraintGroup(globalCap);
|
|
@@ -208,26 +208,119 @@ await manager.triggerTask(dnsTask);
|
|
|
208
208
|
|
|
209
209
|
### Selective Constraints
|
|
210
210
|
|
|
211
|
-
Return `null` from `
|
|
211
|
+
Return `null` from `constraintKeyForExecution` to exempt a task from a constraint group:
|
|
212
212
|
|
|
213
213
|
```typescript
|
|
214
214
|
const constraint = new TaskConstraintGroup<{ priority: string }>({
|
|
215
215
|
name: 'low-priority-limit',
|
|
216
216
|
maxConcurrent: 2,
|
|
217
|
-
|
|
217
|
+
constraintKeyForExecution: (task) =>
|
|
218
218
|
task.data.priority === 'low' ? 'low-priority' : null, // high priority tasks skip this constraint
|
|
219
219
|
});
|
|
220
220
|
```
|
|
221
221
|
|
|
222
|
+
### Input-Aware Constraints 🎯
|
|
223
|
+
|
|
224
|
+
The `constraintKeyForExecution` function receives both the **task** and the **runtime input** passed to `trigger(input)`. This means the same task triggered with different inputs can be constrained independently:
|
|
225
|
+
|
|
226
|
+
```typescript
|
|
227
|
+
const extractTLD = (domain: string) => {
|
|
228
|
+
const parts = domain.split('.');
|
|
229
|
+
return parts.slice(-2).join('.');
|
|
230
|
+
};
|
|
231
|
+
|
|
232
|
+
// Same TLD → serialized. Different TLDs → parallel.
|
|
233
|
+
const tldMutex = new TaskConstraintGroup({
|
|
234
|
+
name: 'tld-mutex',
|
|
235
|
+
maxConcurrent: 1,
|
|
236
|
+
constraintKeyForExecution: (task, input?: string) => {
|
|
237
|
+
if (!input) return null;
|
|
238
|
+
return extractTLD(input); // "example.com", "other.org", etc.
|
|
239
|
+
},
|
|
240
|
+
});
|
|
241
|
+
|
|
242
|
+
manager.addConstraintGroup(tldMutex);
|
|
243
|
+
|
|
244
|
+
// These two serialize (same TLD "example.com")
|
|
245
|
+
const p1 = manager.triggerTaskConstrained(getCert, 'app.example.com');
|
|
246
|
+
const p2 = manager.triggerTaskConstrained(getCert, 'api.example.com');
|
|
247
|
+
|
|
248
|
+
// This runs in parallel (different TLD "other.org")
|
|
249
|
+
const p3 = manager.triggerTaskConstrained(getCert, 'my.other.org');
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
You can also combine `task.data` and `input` for composite keys:
|
|
253
|
+
|
|
254
|
+
```typescript
|
|
255
|
+
const providerDomain = new TaskConstraintGroup<{ provider: string }>({
|
|
256
|
+
name: 'provider-domain',
|
|
257
|
+
maxConcurrent: 1,
|
|
258
|
+
constraintKeyForExecution: (task, input?: string) => {
|
|
259
|
+
return `${task.data.provider}:${input || 'default'}`;
|
|
260
|
+
},
|
|
261
|
+
});
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
### Pre-Execution Check with `shouldExecute` ✅
|
|
265
|
+
|
|
266
|
+
The `shouldExecute` callback runs right before a queued task executes. If it returns `false`, the task is skipped and its promise resolves with `undefined`. This is perfect for scenarios where a prior execution's outcome makes subsequent queued tasks unnecessary:
|
|
267
|
+
|
|
268
|
+
```typescript
|
|
269
|
+
const certCache = new Map<string, string>();
|
|
270
|
+
|
|
271
|
+
const certConstraint = new TaskConstraintGroup({
|
|
272
|
+
name: 'cert-mutex',
|
|
273
|
+
maxConcurrent: 1,
|
|
274
|
+
constraintKeyForExecution: (task, input?: string) => {
|
|
275
|
+
if (!input) return null;
|
|
276
|
+
return extractTLD(input);
|
|
277
|
+
},
|
|
278
|
+
shouldExecute: (task, input?: string) => {
|
|
279
|
+
if (!input) return true;
|
|
280
|
+
// Skip if a wildcard cert already covers this TLD
|
|
281
|
+
return certCache.get(extractTLD(input)) !== 'wildcard';
|
|
282
|
+
},
|
|
283
|
+
});
|
|
284
|
+
|
|
285
|
+
const getCert = new Task({
|
|
286
|
+
name: 'get-certificate',
|
|
287
|
+
taskFunction: async (domain: string) => {
|
|
288
|
+
const cert = await acme.getCert(domain);
|
|
289
|
+
if (cert.isWildcard) certCache.set(extractTLD(domain), 'wildcard');
|
|
290
|
+
return cert;
|
|
291
|
+
},
|
|
292
|
+
});
|
|
293
|
+
|
|
294
|
+
manager.addConstraintGroup(certConstraint);
|
|
295
|
+
manager.addTask(getCert);
|
|
296
|
+
|
|
297
|
+
const r1 = manager.triggerTaskConstrained(getCert, 'app.example.com'); // runs, gets wildcard
|
|
298
|
+
const r2 = manager.triggerTaskConstrained(getCert, 'api.example.com'); // queued → skipped!
|
|
299
|
+
const r3 = manager.triggerTaskConstrained(getCert, 'my.other.org'); // parallel (different TLD)
|
|
300
|
+
|
|
301
|
+
const [cert1, cert2, cert3] = await Promise.all([r1, r2, r3]);
|
|
302
|
+
// cert2 === undefined (skipped because wildcard already covers example.com)
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
**`shouldExecute` semantics:**
|
|
306
|
+
|
|
307
|
+
- Runs right before execution (after slot acquisition, before `trigger()`)
|
|
308
|
+
- Also checked on immediate (non-queued) triggers
|
|
309
|
+
- Returns `false` → skip execution, deferred resolves with `undefined`
|
|
310
|
+
- Can be async (return `Promise<boolean>`)
|
|
311
|
+
- Has closure access to external state modified by prior executions
|
|
312
|
+
- If multiple constraint groups have `shouldExecute`, **all** must return `true`
|
|
313
|
+
|
|
222
314
|
### How It Works
|
|
223
315
|
|
|
224
316
|
When you trigger a task through `TaskManager` (via `triggerTask`, `triggerTaskByName`, `addExecuteRemoveTask`, or cron), the manager:
|
|
225
317
|
|
|
226
|
-
1. Evaluates all registered constraint groups against the task
|
|
227
|
-
2. If no constraints apply (all matchers return `null`) → runs
|
|
228
|
-
3. If all applicable constraints have capacity → acquires slots
|
|
318
|
+
1. Evaluates all registered constraint groups against the task and input
|
|
319
|
+
2. If no constraints apply (all matchers return `null`) → checks `shouldExecute` → runs or skips
|
|
320
|
+
3. If all applicable constraints have capacity → acquires slots → checks `shouldExecute` → runs or skips
|
|
229
321
|
4. If any constraint blocks → enqueues the task; when a running task completes, the queue is drained
|
|
230
322
|
5. Cooldown-blocked tasks auto-retry after the shortest remaining cooldown expires
|
|
323
|
+
6. Queued tasks re-check `shouldExecute` when their turn comes — stale work is automatically pruned
|
|
231
324
|
|
|
232
325
|
## 🎯 Core Concepts
|
|
233
326
|
|
|
@@ -732,7 +825,7 @@ const manager = new TaskManager();
|
|
|
732
825
|
const tenantLimit = new TaskConstraintGroup<{ tenantId: string }>({
|
|
733
826
|
name: 'tenant-concurrency',
|
|
734
827
|
maxConcurrent: 2,
|
|
735
|
-
|
|
828
|
+
constraintKeyForExecution: (task, input?) => task.data.tenantId,
|
|
736
829
|
});
|
|
737
830
|
manager.addConstraintGroup(tenantLimit);
|
|
738
831
|
|
|
@@ -829,15 +922,17 @@ const acmeTasks = manager.getTasksMetadataByLabel('tenantId', 'acme');
|
|
|
829
922
|
| Option | Type | Default | Description |
|
|
830
923
|
| --- | --- | --- | --- |
|
|
831
924
|
| `name` | `string` | *required* | Constraint group identifier |
|
|
832
|
-
| `
|
|
925
|
+
| `constraintKeyForExecution` | `(task, input?) => string \| null` | *required* | Returns key for grouping, or `null` to skip. Receives both the task and runtime input. |
|
|
833
926
|
| `maxConcurrent` | `number` | `Infinity` | Max concurrent tasks per key |
|
|
834
927
|
| `cooldownMs` | `number` | `0` | Minimum ms between completions per key |
|
|
928
|
+
| `shouldExecute` | `(task, input?) => boolean \| Promise<boolean>` | — | Pre-execution check. Return `false` to skip; deferred resolves `undefined`. |
|
|
835
929
|
|
|
836
930
|
### TaskConstraintGroup Methods
|
|
837
931
|
|
|
838
932
|
| Method | Returns | Description |
|
|
839
933
|
| --- | --- | --- |
|
|
840
|
-
| `getConstraintKey(task)` | `string \| null` | Get the constraint key for a task |
|
|
934
|
+
| `getConstraintKey(task, input?)` | `string \| null` | Get the constraint key for a task + input |
|
|
935
|
+
| `checkShouldExecute(task, input?)` | `Promise<boolean>` | Run the `shouldExecute` callback (defaults to `true`) |
|
|
841
936
|
| `canRun(key)` | `boolean` | Check if a slot is available |
|
|
842
937
|
| `acquireSlot(key)` | `void` | Claim a running slot |
|
|
843
938
|
| `releaseSlot(key)` | `void` | Release a slot and record completion time |
|
|
@@ -884,6 +979,7 @@ const acmeTasks = manager.getTasksMetadataByLabel('tenantId', 'acme');
|
|
|
884
979
|
import type {
|
|
885
980
|
ITaskMetadata,
|
|
886
981
|
ITaskExecutionReport,
|
|
982
|
+
ITaskExecution,
|
|
887
983
|
IScheduledTaskInfo,
|
|
888
984
|
ITaskEvent,
|
|
889
985
|
TTaskEventType,
|
package/ts/00_commitinfo_data.ts
CHANGED
|
@@ -3,6 +3,6 @@
|
|
|
3
3
|
*/
|
|
4
4
|
export const commitinfo = {
|
|
5
5
|
name: '@push.rocks/taskbuffer',
|
|
6
|
-
version: '
|
|
6
|
+
version: '6.0.0',
|
|
7
7
|
description: 'A flexible task management library supporting TypeScript, allowing for task buffering, scheduling, and execution with dependency management.'
|
|
8
8
|
}
|
package/ts/index.ts
CHANGED
|
@@ -12,7 +12,7 @@ export { TaskStep } from './taskbuffer.classes.taskstep.js';
|
|
|
12
12
|
export type { ITaskStep } from './taskbuffer.classes.taskstep.js';
|
|
13
13
|
|
|
14
14
|
// Metadata interfaces
|
|
15
|
-
export type { ITaskMetadata, ITaskExecutionReport, IScheduledTaskInfo, ITaskEvent, TTaskEventType, ITaskConstraintGroupOptions } from './taskbuffer.interfaces.js';
|
|
15
|
+
export type { ITaskMetadata, ITaskExecutionReport, IScheduledTaskInfo, ITaskEvent, TTaskEventType, ITaskConstraintGroupOptions, ITaskExecution } from './taskbuffer.interfaces.js';
|
|
16
16
|
|
|
17
17
|
import * as distributedCoordination from './taskbuffer.classes.distributedcoordinator.js';
|
|
18
18
|
export { distributedCoordination };
|
|
@@ -5,23 +5,32 @@ export class TaskConstraintGroup<TData extends Record<string, unknown> = Record<
|
|
|
5
5
|
public name: string;
|
|
6
6
|
public maxConcurrent: number;
|
|
7
7
|
public cooldownMs: number;
|
|
8
|
-
private
|
|
8
|
+
private constraintKeyForExecution: (task: Task<any, any, TData>, input?: any) => string | null | undefined;
|
|
9
|
+
private shouldExecuteFn?: (task: Task<any, any, TData>, input?: any) => boolean | Promise<boolean>;
|
|
9
10
|
|
|
10
11
|
private runningCounts = new Map<string, number>();
|
|
11
12
|
private lastCompletionTimes = new Map<string, number>();
|
|
12
13
|
|
|
13
14
|
constructor(options: ITaskConstraintGroupOptions<TData>) {
|
|
14
15
|
this.name = options.name;
|
|
15
|
-
this.
|
|
16
|
+
this.constraintKeyForExecution = options.constraintKeyForExecution;
|
|
16
17
|
this.maxConcurrent = options.maxConcurrent ?? Infinity;
|
|
17
18
|
this.cooldownMs = options.cooldownMs ?? 0;
|
|
19
|
+
this.shouldExecuteFn = options.shouldExecute;
|
|
18
20
|
}
|
|
19
21
|
|
|
20
|
-
public getConstraintKey(task: Task<any, any, TData
|
|
21
|
-
const key = this.
|
|
22
|
+
public getConstraintKey(task: Task<any, any, TData>, input?: any): string | null {
|
|
23
|
+
const key = this.constraintKeyForExecution(task, input);
|
|
22
24
|
return key ?? null;
|
|
23
25
|
}
|
|
24
26
|
|
|
27
|
+
public async checkShouldExecute(task: Task<any, any, TData>, input?: any): Promise<boolean> {
|
|
28
|
+
if (!this.shouldExecuteFn) {
|
|
29
|
+
return true;
|
|
30
|
+
}
|
|
31
|
+
return this.shouldExecuteFn(task, input);
|
|
32
|
+
}
|
|
33
|
+
|
|
25
34
|
public canRun(subGroupKey: string): boolean {
|
|
26
35
|
const running = this.runningCounts.get(subGroupKey) ?? 0;
|
|
27
36
|
if (running >= this.maxConcurrent) {
|
|
@@ -80,14 +80,18 @@ export class TaskManager {
|
|
|
80
80
|
// Gather applicable constraints
|
|
81
81
|
const applicableGroups: Array<{ group: TaskConstraintGroup<any>; key: string }> = [];
|
|
82
82
|
for (const group of this.constraintGroups) {
|
|
83
|
-
const key = group.getConstraintKey(task);
|
|
83
|
+
const key = group.getConstraintKey(task, input);
|
|
84
84
|
if (key !== null) {
|
|
85
85
|
applicableGroups.push({ group, key });
|
|
86
86
|
}
|
|
87
87
|
}
|
|
88
88
|
|
|
89
|
-
// No constraints apply → trigger directly
|
|
89
|
+
// No constraints apply → check shouldExecute then trigger directly
|
|
90
90
|
if (applicableGroups.length === 0) {
|
|
91
|
+
const shouldRun = await this.checkAllShouldExecute(task, input);
|
|
92
|
+
if (!shouldRun) {
|
|
93
|
+
return undefined;
|
|
94
|
+
}
|
|
91
95
|
return task.trigger(input);
|
|
92
96
|
}
|
|
93
97
|
|
|
@@ -97,22 +101,47 @@ export class TaskManager {
|
|
|
97
101
|
return this.executeWithConstraintTracking(task, input, applicableGroups);
|
|
98
102
|
}
|
|
99
103
|
|
|
100
|
-
// Blocked → enqueue with deferred promise
|
|
104
|
+
// Blocked → enqueue with deferred promise and cached constraint keys
|
|
101
105
|
const deferred = plugins.smartpromise.defer<any>();
|
|
102
|
-
|
|
106
|
+
const constraintKeys = new Map<string, string>();
|
|
107
|
+
for (const { group, key } of applicableGroups) {
|
|
108
|
+
constraintKeys.set(group.name, key);
|
|
109
|
+
}
|
|
110
|
+
this.constraintQueue.push({ task, input, deferred, constraintKeys });
|
|
103
111
|
return deferred.promise;
|
|
104
112
|
}
|
|
105
113
|
|
|
114
|
+
private async checkAllShouldExecute(task: Task<any, any, any>, input?: any): Promise<boolean> {
|
|
115
|
+
for (const group of this.constraintGroups) {
|
|
116
|
+
const shouldRun = await group.checkShouldExecute(task, input);
|
|
117
|
+
if (!shouldRun) {
|
|
118
|
+
return false;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
return true;
|
|
122
|
+
}
|
|
123
|
+
|
|
106
124
|
private async executeWithConstraintTracking(
|
|
107
125
|
task: Task<any, any, any>,
|
|
108
126
|
input: any,
|
|
109
127
|
groups: Array<{ group: TaskConstraintGroup<any>; key: string }>,
|
|
110
128
|
): Promise<any> {
|
|
111
|
-
// Acquire slots
|
|
129
|
+
// Acquire slots synchronously to prevent race conditions
|
|
112
130
|
for (const { group, key } of groups) {
|
|
113
131
|
group.acquireSlot(key);
|
|
114
132
|
}
|
|
115
133
|
|
|
134
|
+
// Check shouldExecute after acquiring slots
|
|
135
|
+
const shouldRun = await this.checkAllShouldExecute(task, input);
|
|
136
|
+
if (!shouldRun) {
|
|
137
|
+
// Release slots and drain queue
|
|
138
|
+
for (const { group, key } of groups) {
|
|
139
|
+
group.releaseSlot(key);
|
|
140
|
+
}
|
|
141
|
+
this.drainConstraintQueue();
|
|
142
|
+
return undefined;
|
|
143
|
+
}
|
|
144
|
+
|
|
116
145
|
try {
|
|
117
146
|
return await task.trigger(input);
|
|
118
147
|
} finally {
|
|
@@ -131,23 +160,30 @@ export class TaskManager {
|
|
|
131
160
|
for (const entry of this.constraintQueue) {
|
|
132
161
|
const applicableGroups: Array<{ group: TaskConstraintGroup<any>; key: string }> = [];
|
|
133
162
|
for (const group of this.constraintGroups) {
|
|
134
|
-
const key = group.getConstraintKey(entry.task);
|
|
163
|
+
const key = group.getConstraintKey(entry.task, entry.input);
|
|
135
164
|
if (key !== null) {
|
|
136
165
|
applicableGroups.push({ group, key });
|
|
137
166
|
}
|
|
138
167
|
}
|
|
139
168
|
|
|
140
|
-
// No constraints apply anymore (group removed?) → run
|
|
169
|
+
// No constraints apply anymore (group removed?) → check shouldExecute then run
|
|
141
170
|
if (applicableGroups.length === 0) {
|
|
142
|
-
entry.task
|
|
143
|
-
(
|
|
144
|
-
|
|
145
|
-
|
|
171
|
+
this.checkAllShouldExecute(entry.task, entry.input).then((shouldRun) => {
|
|
172
|
+
if (!shouldRun) {
|
|
173
|
+
entry.deferred.resolve(undefined);
|
|
174
|
+
return;
|
|
175
|
+
}
|
|
176
|
+
entry.task.trigger(entry.input).then(
|
|
177
|
+
(result) => entry.deferred.resolve(result),
|
|
178
|
+
(err) => entry.deferred.reject(err),
|
|
179
|
+
);
|
|
180
|
+
});
|
|
146
181
|
continue;
|
|
147
182
|
}
|
|
148
183
|
|
|
149
184
|
const allCanRun = applicableGroups.every(({ group, key }) => group.canRun(key));
|
|
150
185
|
if (allCanRun) {
|
|
186
|
+
// executeWithConstraintTracking handles shouldExecute check internally
|
|
151
187
|
this.executeWithConstraintTracking(entry.task, entry.input, applicableGroups).then(
|
|
152
188
|
(result) => entry.deferred.resolve(result),
|
|
153
189
|
(err) => entry.deferred.reject(err),
|
|
@@ -3,15 +3,22 @@ import type { Task } from './taskbuffer.classes.task.js';
|
|
|
3
3
|
|
|
4
4
|
export interface ITaskConstraintGroupOptions<TData extends Record<string, unknown> = Record<string, unknown>> {
|
|
5
5
|
name: string;
|
|
6
|
-
|
|
6
|
+
constraintKeyForExecution: (task: Task<any, any, TData>, input?: any) => string | null | undefined;
|
|
7
7
|
maxConcurrent?: number; // default: Infinity
|
|
8
8
|
cooldownMs?: number; // default: 0
|
|
9
|
+
shouldExecute?: (task: Task<any, any, TData>, input?: any) => boolean | Promise<boolean>;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export interface ITaskExecution<TData extends Record<string, unknown> = Record<string, unknown>> {
|
|
13
|
+
task: Task<any, any, TData>;
|
|
14
|
+
input: any;
|
|
9
15
|
}
|
|
10
16
|
|
|
11
17
|
export interface IConstrainedTaskEntry {
|
|
12
18
|
task: Task<any, any, any>;
|
|
13
19
|
input: any;
|
|
14
20
|
deferred: import('@push.rocks/smartpromise').Deferred<any>;
|
|
21
|
+
constraintKeys: Map<string, string>; // groupName -> key
|
|
15
22
|
}
|
|
16
23
|
|
|
17
24
|
export interface ITaskMetadata {
|
|
@@ -3,6 +3,6 @@
|
|
|
3
3
|
*/
|
|
4
4
|
export const commitinfo = {
|
|
5
5
|
name: '@push.rocks/taskbuffer',
|
|
6
|
-
version: '
|
|
6
|
+
version: '6.0.0',
|
|
7
7
|
description: 'A flexible task management library supporting TypeScript, allowing for task buffering, scheduling, and execution with dependency management.'
|
|
8
8
|
}
|