@spinajs/tasks 2.0.552 → 2.0.554
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/lib/cjs/decorators.d.ts +17 -11
- package/lib/cjs/decorators.d.ts.map +1 -1
- package/lib/cjs/decorators.js +67 -23
- package/lib/cjs/decorators.js.map +1 -1
- package/lib/mjs/decorators.d.ts +17 -11
- package/lib/mjs/decorators.d.ts.map +1 -1
- package/lib/mjs/decorators.js +67 -23
- package/lib/mjs/decorators.js.map +1 -1
- package/lib/tsconfig.cjs.tsbuildinfo +1 -1
- package/lib/tsconfig.mjs.tsbuildinfo +1 -1
- package/package.json +7 -6
package/lib/cjs/decorators.d.ts
CHANGED
|
@@ -1,18 +1,24 @@
|
|
|
1
1
|
export declare const TASK_COMMAND = "task:command";
|
|
2
|
-
interface TaskOptions {
|
|
2
|
+
export interface TaskOptions {
|
|
3
|
+
/**
|
|
4
|
+
* Allow several runs of the same task at once, e.g. a long run that overlaps the next start.
|
|
5
|
+
*/
|
|
3
6
|
taskStacking: boolean;
|
|
7
|
+
/**
|
|
8
|
+
* Lifetime of the task mutex in ms, renewed every lockTtl / 3 while the task runs, so a
|
|
9
|
+
* crashed process frees the task after at most lockTtl. 0 = never expires.
|
|
10
|
+
*/
|
|
11
|
+
lockTtl: number;
|
|
4
12
|
}
|
|
13
|
+
export declare const DEFAULT_TASK_OPTIONS: TaskOptions;
|
|
5
14
|
/**
|
|
6
|
-
*
|
|
7
|
-
*
|
|
15
|
+
* Marks a method as a task: records runs in `__tasks` / `__task_history`, emits
|
|
16
|
+
* TaskSuccess / TaskFailed and, unless `taskStacking` is set, lets only one run
|
|
17
|
+
* happen at a time across all processes sharing the database.
|
|
8
18
|
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
* @param nameAndArgs - name of command with optional args defined
|
|
13
|
-
* @param description - short description
|
|
14
|
-
* @param opts - additional options, see https://github.com/tj/commander.js
|
|
19
|
+
* @param taskName - unique task name
|
|
20
|
+
* @param description - short description
|
|
21
|
+
* @param opts - see {@link TaskOptions}, defaults to {@link DEFAULT_TASK_OPTIONS}
|
|
15
22
|
*/
|
|
16
|
-
export declare function Task(taskName: string, description: string, opts?: TaskOptions): (_target: any, _propertyKey: string | symbol, descriptor: PropertyDescriptor) => void;
|
|
17
|
-
export {};
|
|
23
|
+
export declare function Task(taskName: string, description: string, opts?: Partial<TaskOptions>): (_target: any, _propertyKey: string | symbol, descriptor: PropertyDescriptor) => void;
|
|
18
24
|
//# sourceMappingURL=decorators.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"decorators.d.ts","sourceRoot":"","sources":["../../src/decorators.ts"],"names":[],"mappings":"AAUA,eAAO,MAAM,YAAY,iBAAiB,CAAC;AAE3C,
|
|
1
|
+
{"version":3,"file":"decorators.d.ts","sourceRoot":"","sources":["../../src/decorators.ts"],"names":[],"mappings":"AAUA,eAAO,MAAM,YAAY,iBAAiB,CAAC;AAE3C,MAAM,WAAW,WAAW;IAC1B;;OAEG;IACH,YAAY,EAAE,OAAO,CAAC;IAEtB;;;OAGG;IACH,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,eAAO,MAAM,oBAAoB,EAAE,WAGlC,CAAC;AAqDF;;;;;;;;GAQG;AACH,wBAAgB,IAAI,CAAC,QAAQ,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO,CAAC,WAAW,CAAC,aAK3D,GAAG,gBAAgB,MAAM,GAAG,MAAM,cAAc,kBAAkB,UAyE7F"}
|
package/lib/cjs/decorators.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.TASK_COMMAND = void 0;
|
|
3
|
+
exports.DEFAULT_TASK_OPTIONS = exports.TASK_COMMAND = void 0;
|
|
4
4
|
exports.Task = Task;
|
|
5
5
|
const threading_1 = require("@spinajs/threading");
|
|
6
6
|
const util_1 = require("@spinajs/util");
|
|
@@ -11,20 +11,65 @@ const __task_history_js_1 = require("./models/__task_history.js");
|
|
|
11
11
|
const TaskSuccess_js_1 = require("./events/TaskSuccess.js");
|
|
12
12
|
const TaskFailed_js_1 = require("./events/TaskFailed.js");
|
|
13
13
|
exports.TASK_COMMAND = 'task:command';
|
|
14
|
+
exports.DEFAULT_TASK_OPTIONS = {
|
|
15
|
+
taskStacking: false,
|
|
16
|
+
lockTtl: 60000,
|
|
17
|
+
};
|
|
18
|
+
// The mutex is re-entrant per tenant and the default tenant is per process,
|
|
19
|
+
// so overlapping runs inside one process are excluded here, not by the mutex.
|
|
20
|
+
const runningInProcess = new Set();
|
|
21
|
+
async function lockTask(name, opts, log) {
|
|
22
|
+
if (opts.taskStacking) {
|
|
23
|
+
return async () => { };
|
|
24
|
+
}
|
|
25
|
+
if (runningInProcess.has(name)) {
|
|
26
|
+
log.warn(`Task ${name} is already running in this process`);
|
|
27
|
+
return null;
|
|
28
|
+
}
|
|
29
|
+
runningInProcess.add(name);
|
|
30
|
+
const mutexName = `task-${name}`;
|
|
31
|
+
try {
|
|
32
|
+
const lock = await (0, threading_1.mutex_acquire)({ Name: mutexName, ttl: opts.lockTtl });
|
|
33
|
+
if (!lock.Locked) {
|
|
34
|
+
runningInProcess.delete(name);
|
|
35
|
+
log.warn(`Cannot acquire mutex for task ${name}, already locked !`);
|
|
36
|
+
return null;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
catch (err) {
|
|
40
|
+
runningInProcess.delete(name);
|
|
41
|
+
throw err;
|
|
42
|
+
}
|
|
43
|
+
const heartbeat = opts.lockTtl > 0
|
|
44
|
+
? setInterval(() => {
|
|
45
|
+
(0, threading_1.mutex_renew)({ Name: mutexName, ttl: opts.lockTtl })
|
|
46
|
+
.then((renewed) => {
|
|
47
|
+
if (!renewed) {
|
|
48
|
+
log.warn(`Task ${name} lost its mutex, another process may run it now`);
|
|
49
|
+
}
|
|
50
|
+
})
|
|
51
|
+
.catch((err) => log.error(err, `Cannot renew mutex for task ${name}`));
|
|
52
|
+
}, Math.max(1, Math.floor(opts.lockTtl / 3)))
|
|
53
|
+
: undefined;
|
|
54
|
+
return async () => {
|
|
55
|
+
clearInterval(heartbeat);
|
|
56
|
+
runningInProcess.delete(name);
|
|
57
|
+
await (0, threading_1.mutex_release)({ Name: mutexName });
|
|
58
|
+
};
|
|
59
|
+
}
|
|
14
60
|
/**
|
|
15
|
-
*
|
|
16
|
-
*
|
|
61
|
+
* Marks a method as a task: records runs in `__tasks` / `__task_history`, emits
|
|
62
|
+
* TaskSuccess / TaskFailed and, unless `taskStacking` is set, lets only one run
|
|
63
|
+
* happen at a time across all processes sharing the database.
|
|
17
64
|
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
* @param nameAndArgs - name of command with optional args defined
|
|
22
|
-
* @param description - short description
|
|
23
|
-
* @param opts - additional options, see https://github.com/tj/commander.js
|
|
65
|
+
* @param taskName - unique task name
|
|
66
|
+
* @param description - short description
|
|
67
|
+
* @param opts - see {@link TaskOptions}, defaults to {@link DEFAULT_TASK_OPTIONS}
|
|
24
68
|
*/
|
|
25
69
|
function Task(taskName, description, opts) {
|
|
26
70
|
const _name = (0, util_1._check_arg)((0, util_1._trim)(), (0, util_1._non_empty)())(taskName, 'Task name is empty');
|
|
27
71
|
const _description = (0, util_1._check_arg)((0, util_1._trim)(), (0, util_1._non_empty)())(description, 'Task description is empty');
|
|
72
|
+
const _opts = { ...exports.DEFAULT_TASK_OPTIONS, ...opts };
|
|
28
73
|
return function (_target, _propertyKey, descriptor) {
|
|
29
74
|
const oldFunction = descriptor.value;
|
|
30
75
|
descriptor.value = async function (...args) {
|
|
@@ -36,18 +81,19 @@ function Task(taskName, description, opts) {
|
|
|
36
81
|
Description: _description,
|
|
37
82
|
State: 'stopped',
|
|
38
83
|
});
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
84
|
+
const unlock = await lockTask(_name, _opts, log);
|
|
85
|
+
if (!unlock) {
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
try {
|
|
89
|
+
task.State = 'running';
|
|
90
|
+
task.LastRunAt = luxon_1.DateTime.now();
|
|
91
|
+
await task.update();
|
|
92
|
+
}
|
|
93
|
+
catch (err) {
|
|
94
|
+
await unlock();
|
|
95
|
+
throw err;
|
|
47
96
|
}
|
|
48
|
-
task.State = 'running';
|
|
49
|
-
task.LastRunAt = luxon_1.DateTime.now();
|
|
50
|
-
await task.update();
|
|
51
97
|
let taskResult = null;
|
|
52
98
|
const start = luxon_1.DateTime.now();
|
|
53
99
|
try {
|
|
@@ -70,9 +116,7 @@ function Task(taskName, description, opts) {
|
|
|
70
116
|
}
|
|
71
117
|
finally {
|
|
72
118
|
try {
|
|
73
|
-
await (
|
|
74
|
-
Name: `task-${name}`,
|
|
75
|
-
});
|
|
119
|
+
await unlock();
|
|
76
120
|
await task.update({
|
|
77
121
|
State: 'stopped',
|
|
78
122
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"decorators.js","sourceRoot":"","sources":["../../src/decorators.ts"],"names":[],"mappings":";;;;AAAA,
|
|
1
|
+
{"version":3,"file":"decorators.js","sourceRoot":"","sources":["../../src/decorators.ts"],"names":[],"mappings":"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"}
|
package/lib/mjs/decorators.d.ts
CHANGED
|
@@ -1,18 +1,24 @@
|
|
|
1
1
|
export declare const TASK_COMMAND = "task:command";
|
|
2
|
-
interface TaskOptions {
|
|
2
|
+
export interface TaskOptions {
|
|
3
|
+
/**
|
|
4
|
+
* Allow several runs of the same task at once, e.g. a long run that overlaps the next start.
|
|
5
|
+
*/
|
|
3
6
|
taskStacking: boolean;
|
|
7
|
+
/**
|
|
8
|
+
* Lifetime of the task mutex in ms, renewed every lockTtl / 3 while the task runs, so a
|
|
9
|
+
* crashed process frees the task after at most lockTtl. 0 = never expires.
|
|
10
|
+
*/
|
|
11
|
+
lockTtl: number;
|
|
4
12
|
}
|
|
13
|
+
export declare const DEFAULT_TASK_OPTIONS: TaskOptions;
|
|
5
14
|
/**
|
|
6
|
-
*
|
|
7
|
-
*
|
|
15
|
+
* Marks a method as a task: records runs in `__tasks` / `__task_history`, emits
|
|
16
|
+
* TaskSuccess / TaskFailed and, unless `taskStacking` is set, lets only one run
|
|
17
|
+
* happen at a time across all processes sharing the database.
|
|
8
18
|
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
* @param nameAndArgs - name of command with optional args defined
|
|
13
|
-
* @param description - short description
|
|
14
|
-
* @param opts - additional options, see https://github.com/tj/commander.js
|
|
19
|
+
* @param taskName - unique task name
|
|
20
|
+
* @param description - short description
|
|
21
|
+
* @param opts - see {@link TaskOptions}, defaults to {@link DEFAULT_TASK_OPTIONS}
|
|
15
22
|
*/
|
|
16
|
-
export declare function Task(taskName: string, description: string, opts?: TaskOptions): (_target: any, _propertyKey: string | symbol, descriptor: PropertyDescriptor) => void;
|
|
17
|
-
export {};
|
|
23
|
+
export declare function Task(taskName: string, description: string, opts?: Partial<TaskOptions>): (_target: any, _propertyKey: string | symbol, descriptor: PropertyDescriptor) => void;
|
|
18
24
|
//# sourceMappingURL=decorators.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"decorators.d.ts","sourceRoot":"","sources":["../../src/decorators.ts"],"names":[],"mappings":"AAUA,eAAO,MAAM,YAAY,iBAAiB,CAAC;AAE3C,
|
|
1
|
+
{"version":3,"file":"decorators.d.ts","sourceRoot":"","sources":["../../src/decorators.ts"],"names":[],"mappings":"AAUA,eAAO,MAAM,YAAY,iBAAiB,CAAC;AAE3C,MAAM,WAAW,WAAW;IAC1B;;OAEG;IACH,YAAY,EAAE,OAAO,CAAC;IAEtB;;;OAGG;IACH,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,eAAO,MAAM,oBAAoB,EAAE,WAGlC,CAAC;AAqDF;;;;;;;;GAQG;AACH,wBAAgB,IAAI,CAAC,QAAQ,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO,CAAC,WAAW,CAAC,aAK3D,GAAG,gBAAgB,MAAM,GAAG,MAAM,cAAc,kBAAkB,UAyE7F"}
|
package/lib/mjs/decorators.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { mutex_acquire, mutex_release } from '@spinajs/threading';
|
|
1
|
+
import { mutex_acquire, mutex_release, mutex_renew } from '@spinajs/threading';
|
|
2
2
|
import { _check_arg, _non_empty, _trim } from '@spinajs/util';
|
|
3
3
|
import { DI } from '@spinajs/di';
|
|
4
4
|
import { __task } from './models/__task.js';
|
|
@@ -7,20 +7,65 @@ import { __task_history } from './models/__task_history.js';
|
|
|
7
7
|
import { TaskSuccess } from './events/TaskSuccess.js';
|
|
8
8
|
import { TaskFailed } from './events/TaskFailed.js';
|
|
9
9
|
export const TASK_COMMAND = 'task:command';
|
|
10
|
+
export const DEFAULT_TASK_OPTIONS = {
|
|
11
|
+
taskStacking: false,
|
|
12
|
+
lockTtl: 60000,
|
|
13
|
+
};
|
|
14
|
+
// The mutex is re-entrant per tenant and the default tenant is per process,
|
|
15
|
+
// so overlapping runs inside one process are excluded here, not by the mutex.
|
|
16
|
+
const runningInProcess = new Set();
|
|
17
|
+
async function lockTask(name, opts, log) {
|
|
18
|
+
if (opts.taskStacking) {
|
|
19
|
+
return async () => { };
|
|
20
|
+
}
|
|
21
|
+
if (runningInProcess.has(name)) {
|
|
22
|
+
log.warn(`Task ${name} is already running in this process`);
|
|
23
|
+
return null;
|
|
24
|
+
}
|
|
25
|
+
runningInProcess.add(name);
|
|
26
|
+
const mutexName = `task-${name}`;
|
|
27
|
+
try {
|
|
28
|
+
const lock = await mutex_acquire({ Name: mutexName, ttl: opts.lockTtl });
|
|
29
|
+
if (!lock.Locked) {
|
|
30
|
+
runningInProcess.delete(name);
|
|
31
|
+
log.warn(`Cannot acquire mutex for task ${name}, already locked !`);
|
|
32
|
+
return null;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
catch (err) {
|
|
36
|
+
runningInProcess.delete(name);
|
|
37
|
+
throw err;
|
|
38
|
+
}
|
|
39
|
+
const heartbeat = opts.lockTtl > 0
|
|
40
|
+
? setInterval(() => {
|
|
41
|
+
mutex_renew({ Name: mutexName, ttl: opts.lockTtl })
|
|
42
|
+
.then((renewed) => {
|
|
43
|
+
if (!renewed) {
|
|
44
|
+
log.warn(`Task ${name} lost its mutex, another process may run it now`);
|
|
45
|
+
}
|
|
46
|
+
})
|
|
47
|
+
.catch((err) => log.error(err, `Cannot renew mutex for task ${name}`));
|
|
48
|
+
}, Math.max(1, Math.floor(opts.lockTtl / 3)))
|
|
49
|
+
: undefined;
|
|
50
|
+
return async () => {
|
|
51
|
+
clearInterval(heartbeat);
|
|
52
|
+
runningInProcess.delete(name);
|
|
53
|
+
await mutex_release({ Name: mutexName });
|
|
54
|
+
};
|
|
55
|
+
}
|
|
10
56
|
/**
|
|
11
|
-
*
|
|
12
|
-
*
|
|
57
|
+
* Marks a method as a task: records runs in `__tasks` / `__task_history`, emits
|
|
58
|
+
* TaskSuccess / TaskFailed and, unless `taskStacking` is set, lets only one run
|
|
59
|
+
* happen at a time across all processes sharing the database.
|
|
13
60
|
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
* @param nameAndArgs - name of command with optional args defined
|
|
18
|
-
* @param description - short description
|
|
19
|
-
* @param opts - additional options, see https://github.com/tj/commander.js
|
|
61
|
+
* @param taskName - unique task name
|
|
62
|
+
* @param description - short description
|
|
63
|
+
* @param opts - see {@link TaskOptions}, defaults to {@link DEFAULT_TASK_OPTIONS}
|
|
20
64
|
*/
|
|
21
65
|
export function Task(taskName, description, opts) {
|
|
22
66
|
const _name = _check_arg(_trim(), _non_empty())(taskName, 'Task name is empty');
|
|
23
67
|
const _description = _check_arg(_trim(), _non_empty())(description, 'Task description is empty');
|
|
68
|
+
const _opts = { ...DEFAULT_TASK_OPTIONS, ...opts };
|
|
24
69
|
return function (_target, _propertyKey, descriptor) {
|
|
25
70
|
const oldFunction = descriptor.value;
|
|
26
71
|
descriptor.value = async function (...args) {
|
|
@@ -32,18 +77,19 @@ export function Task(taskName, description, opts) {
|
|
|
32
77
|
Description: _description,
|
|
33
78
|
State: 'stopped',
|
|
34
79
|
});
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
80
|
+
const unlock = await lockTask(_name, _opts, log);
|
|
81
|
+
if (!unlock) {
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
try {
|
|
85
|
+
task.State = 'running';
|
|
86
|
+
task.LastRunAt = DateTime.now();
|
|
87
|
+
await task.update();
|
|
88
|
+
}
|
|
89
|
+
catch (err) {
|
|
90
|
+
await unlock();
|
|
91
|
+
throw err;
|
|
43
92
|
}
|
|
44
|
-
task.State = 'running';
|
|
45
|
-
task.LastRunAt = DateTime.now();
|
|
46
|
-
await task.update();
|
|
47
93
|
let taskResult = null;
|
|
48
94
|
const start = DateTime.now();
|
|
49
95
|
try {
|
|
@@ -66,9 +112,7 @@ export function Task(taskName, description, opts) {
|
|
|
66
112
|
}
|
|
67
113
|
finally {
|
|
68
114
|
try {
|
|
69
|
-
await
|
|
70
|
-
Name: `task-${name}`,
|
|
71
|
-
});
|
|
115
|
+
await unlock();
|
|
72
116
|
await task.update({
|
|
73
117
|
State: 'stopped',
|
|
74
118
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"decorators.js","sourceRoot":"","sources":["../../src/decorators.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"decorators.js","sourceRoot":"","sources":["../../src/decorators.ts"],"names":[],"mappings":"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"}
|