async-queue-runner 0.14.0 → 0.16.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/_cjs/action.js +17 -1
- package/_cjs/queue.js +13 -0
- package/_cjs/runner.js +44 -0
- package/_cjs/testlib.js +8 -0
- package/_esm/action.js +15 -5
- package/_esm/index.js +4 -11
- package/_esm/queue.js +16 -7
- package/_esm/runner.js +47 -7
- package/_esm/testlib.js +5 -0
- package/_esm/types.js +1 -2
- package/_esm/utils.js +5 -9
- package/_types/action.d.ts +11 -1
- package/_types/queue.d.ts +3 -0
- package/_types/runner.d.ts +8 -0
- package/_types/testlib.d.ts +2 -0
- package/_types/types.d.ts +5 -1
- package/package.json +1 -1
package/_cjs/action.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.Action = void 0;
|
|
3
|
+
exports.lockingClassFactory = exports.LockingAction = exports.Action = void 0;
|
|
4
4
|
class Action {
|
|
5
5
|
delay = 0;
|
|
6
6
|
constructor(opts = {}) {
|
|
@@ -9,3 +9,19 @@ class Action {
|
|
|
9
9
|
}
|
|
10
10
|
}
|
|
11
11
|
exports.Action = Action;
|
|
12
|
+
class LockingAction extends Action {
|
|
13
|
+
locking = true;
|
|
14
|
+
scope = null;
|
|
15
|
+
}
|
|
16
|
+
exports.LockingAction = LockingAction;
|
|
17
|
+
function lockingClassFactory(scope) {
|
|
18
|
+
if (typeof scope !== 'string') {
|
|
19
|
+
throw new TypeError('scope must be a string');
|
|
20
|
+
}
|
|
21
|
+
class NoName extends LockingAction {
|
|
22
|
+
scope = scope;
|
|
23
|
+
}
|
|
24
|
+
Object.defineProperty(NoName, 'name', { value: `${LockingAction.constructor.name}(${scope})` });
|
|
25
|
+
return NoName;
|
|
26
|
+
}
|
|
27
|
+
exports.lockingClassFactory = lockingClassFactory;
|
package/_cjs/queue.js
CHANGED
|
@@ -14,6 +14,7 @@ class AsyncQueue {
|
|
|
14
14
|
queue = [];
|
|
15
15
|
end;
|
|
16
16
|
logger;
|
|
17
|
+
locker;
|
|
17
18
|
loopAction = false;
|
|
18
19
|
context = {
|
|
19
20
|
push: (actions) => this.push(actions),
|
|
@@ -31,6 +32,7 @@ class AsyncQueue {
|
|
|
31
32
|
this.name = opts.name;
|
|
32
33
|
this.end = opts.end || (() => { });
|
|
33
34
|
this.logger = opts.logger || logger;
|
|
35
|
+
this.locker = opts.lockingContext;
|
|
34
36
|
}
|
|
35
37
|
async delay(timeout) {
|
|
36
38
|
return new Promise((res) => setTimeout(res, timeout));
|
|
@@ -47,7 +49,18 @@ class AsyncQueue {
|
|
|
47
49
|
}
|
|
48
50
|
const item = this.queue.shift();
|
|
49
51
|
const action = this.processQueueItem(item);
|
|
52
|
+
const isLocking = action.locking;
|
|
53
|
+
const scope = action.scope;
|
|
54
|
+
if (isLocking) {
|
|
55
|
+
if (this.locker.isLocked(scope)) {
|
|
56
|
+
await this.locker.wait(scope);
|
|
57
|
+
}
|
|
58
|
+
this.locker.lock(scope);
|
|
59
|
+
}
|
|
50
60
|
await this.iterate(action);
|
|
61
|
+
if (isLocking) {
|
|
62
|
+
this.locker.unlock(scope);
|
|
63
|
+
}
|
|
51
64
|
}
|
|
52
65
|
this.end();
|
|
53
66
|
}
|
package/_cjs/runner.js
CHANGED
|
@@ -2,14 +2,57 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.QueueRunner = void 0;
|
|
4
4
|
const queue_js_1 = require("./queue.js");
|
|
5
|
+
function reversePromiseFactory() {
|
|
6
|
+
let resolve = (value) => { };
|
|
7
|
+
const promise = new Promise((res) => {
|
|
8
|
+
resolve = res;
|
|
9
|
+
});
|
|
10
|
+
return {
|
|
11
|
+
promise,
|
|
12
|
+
resolve,
|
|
13
|
+
};
|
|
14
|
+
}
|
|
5
15
|
class QueueRunner {
|
|
6
16
|
queues = new Map();
|
|
7
17
|
listeners = [];
|
|
8
18
|
logger;
|
|
19
|
+
locking;
|
|
9
20
|
constructor(opts = {}) {
|
|
10
21
|
if (opts.logger) {
|
|
11
22
|
this.logger = opts.logger;
|
|
12
23
|
}
|
|
24
|
+
this.locking = this.preparteLockingContext();
|
|
25
|
+
}
|
|
26
|
+
preparteLockingContext() {
|
|
27
|
+
const lockedScopes = new Map();
|
|
28
|
+
const unlock = (scope) => {
|
|
29
|
+
if (!lockedScopes.has(scope)) {
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
lockedScopes.get(scope).resolve();
|
|
33
|
+
lockedScopes.delete(scope);
|
|
34
|
+
};
|
|
35
|
+
const wait = (scope) => {
|
|
36
|
+
if (!lockedScopes.has(scope)) {
|
|
37
|
+
return Promise.resolve();
|
|
38
|
+
}
|
|
39
|
+
return lockedScopes.get(scope).promise;
|
|
40
|
+
};
|
|
41
|
+
const lock = (scope) => {
|
|
42
|
+
if (lockedScopes.has(scope)) {
|
|
43
|
+
throw new Error(`scope "${scope}" is already locked`);
|
|
44
|
+
}
|
|
45
|
+
lockedScopes.set(scope, reversePromiseFactory());
|
|
46
|
+
};
|
|
47
|
+
const isLocked = (scope) => {
|
|
48
|
+
return lockedScopes.has(scope);
|
|
49
|
+
};
|
|
50
|
+
return {
|
|
51
|
+
isLocked,
|
|
52
|
+
lock,
|
|
53
|
+
unlock,
|
|
54
|
+
wait,
|
|
55
|
+
};
|
|
13
56
|
}
|
|
14
57
|
add(actions, context = {}, name = this.getName()) {
|
|
15
58
|
const queue = new queue_js_1.AsyncQueue({
|
|
@@ -19,6 +62,7 @@ class QueueRunner {
|
|
|
19
62
|
this.endEvent(name);
|
|
20
63
|
},
|
|
21
64
|
logger: this.logger,
|
|
65
|
+
lockingContext: this.locking,
|
|
22
66
|
});
|
|
23
67
|
this.queues.set(name, queue);
|
|
24
68
|
queue.run(context);
|
package/_cjs/testlib.js
ADDED
package/_esm/action.js
CHANGED
|
@@ -1,11 +1,21 @@
|
|
|
1
|
-
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.Action = void 0;
|
|
4
|
-
class Action {
|
|
1
|
+
export class Action {
|
|
5
2
|
delay = 0;
|
|
6
3
|
constructor(opts = {}) {
|
|
7
4
|
if (opts.delay)
|
|
8
5
|
this.delay = opts.delay;
|
|
9
6
|
}
|
|
10
7
|
}
|
|
11
|
-
|
|
8
|
+
export class LockingAction extends Action {
|
|
9
|
+
locking = true;
|
|
10
|
+
scope = null;
|
|
11
|
+
}
|
|
12
|
+
export function lockingClassFactory(scope) {
|
|
13
|
+
if (typeof scope !== 'string') {
|
|
14
|
+
throw new TypeError('scope must be a string');
|
|
15
|
+
}
|
|
16
|
+
class NoName extends LockingAction {
|
|
17
|
+
scope = scope;
|
|
18
|
+
}
|
|
19
|
+
Object.defineProperty(NoName, 'name', { value: `${LockingAction.constructor.name}(${scope})` });
|
|
20
|
+
return NoName;
|
|
21
|
+
}
|
package/_esm/index.js
CHANGED
|
@@ -1,11 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
Object.defineProperty(exports, "QueueRunner", { enumerable: true, get: function () { return runner_js_1.QueueRunner; } });
|
|
6
|
-
var queue_js_1 = require("./queue.js");
|
|
7
|
-
Object.defineProperty(exports, "AsyncQueue", { enumerable: true, get: function () { return queue_js_1.AsyncQueue; } });
|
|
8
|
-
var action_js_1 = require("./action.js");
|
|
9
|
-
Object.defineProperty(exports, "Action", { enumerable: true, get: function () { return action_js_1.Action; } });
|
|
10
|
-
var utils_js_1 = require("./utils.js");
|
|
11
|
-
Object.defineProperty(exports, "util", { enumerable: true, get: function () { return utils_js_1.util; } });
|
|
1
|
+
export { QueueRunner } from './runner.js';
|
|
2
|
+
export { AsyncQueue } from './queue.js';
|
|
3
|
+
export { Action } from './action.js';
|
|
4
|
+
export { util } from './utils.js';
|
package/_esm/queue.js
CHANGED
|
@@ -1,7 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.AsyncQueue = void 0;
|
|
4
|
-
const action_js_1 = require("./action.js");
|
|
1
|
+
import { Action } from './action.js';
|
|
5
2
|
const logger = {
|
|
6
3
|
info(message) {
|
|
7
4
|
console.log(message);
|
|
@@ -9,11 +6,12 @@ const logger = {
|
|
|
9
6
|
setContext(context) { },
|
|
10
7
|
error(e) { console.error(e); },
|
|
11
8
|
};
|
|
12
|
-
class AsyncQueue {
|
|
9
|
+
export class AsyncQueue {
|
|
13
10
|
name = 'default queue name';
|
|
14
11
|
queue = [];
|
|
15
12
|
end;
|
|
16
13
|
logger;
|
|
14
|
+
locker;
|
|
17
15
|
loopAction = false;
|
|
18
16
|
context = {
|
|
19
17
|
push: (actions) => this.push(actions),
|
|
@@ -31,6 +29,7 @@ class AsyncQueue {
|
|
|
31
29
|
this.name = opts.name;
|
|
32
30
|
this.end = opts.end || (() => { });
|
|
33
31
|
this.logger = opts.logger || logger;
|
|
32
|
+
this.locker = opts.lockingContext;
|
|
34
33
|
}
|
|
35
34
|
async delay(timeout) {
|
|
36
35
|
return new Promise((res) => setTimeout(res, timeout));
|
|
@@ -47,7 +46,18 @@ class AsyncQueue {
|
|
|
47
46
|
}
|
|
48
47
|
const item = this.queue.shift();
|
|
49
48
|
const action = this.processQueueItem(item);
|
|
49
|
+
const isLocking = action.locking;
|
|
50
|
+
const scope = action.scope;
|
|
51
|
+
if (isLocking) {
|
|
52
|
+
if (this.locker.isLocked(scope)) {
|
|
53
|
+
await this.locker.wait(scope);
|
|
54
|
+
}
|
|
55
|
+
this.locker.lock(scope);
|
|
56
|
+
}
|
|
50
57
|
await this.iterate(action);
|
|
58
|
+
if (isLocking) {
|
|
59
|
+
this.locker.unlock(scope);
|
|
60
|
+
}
|
|
51
61
|
}
|
|
52
62
|
this.end();
|
|
53
63
|
}
|
|
@@ -67,11 +77,10 @@ class AsyncQueue {
|
|
|
67
77
|
this.queue.unshift(...actions);
|
|
68
78
|
}
|
|
69
79
|
processQueueItem(item) {
|
|
70
|
-
if (item instanceof
|
|
80
|
+
if (item instanceof Action) {
|
|
71
81
|
return item;
|
|
72
82
|
}
|
|
73
83
|
else
|
|
74
84
|
return new item;
|
|
75
85
|
}
|
|
76
86
|
}
|
|
77
|
-
exports.AsyncQueue = AsyncQueue;
|
package/_esm/runner.js
CHANGED
|
@@ -1,24 +1,65 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
const
|
|
5
|
-
|
|
1
|
+
import { AsyncQueue } from "./queue.js";
|
|
2
|
+
function reversePromiseFactory() {
|
|
3
|
+
let resolve = (value) => { };
|
|
4
|
+
const promise = new Promise((res) => {
|
|
5
|
+
resolve = res;
|
|
6
|
+
});
|
|
7
|
+
return {
|
|
8
|
+
promise,
|
|
9
|
+
resolve,
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
export class QueueRunner {
|
|
6
13
|
queues = new Map();
|
|
7
14
|
listeners = [];
|
|
8
15
|
logger;
|
|
16
|
+
locking;
|
|
9
17
|
constructor(opts = {}) {
|
|
10
18
|
if (opts.logger) {
|
|
11
19
|
this.logger = opts.logger;
|
|
12
20
|
}
|
|
21
|
+
this.locking = this.preparteLockingContext();
|
|
22
|
+
}
|
|
23
|
+
preparteLockingContext() {
|
|
24
|
+
const lockedScopes = new Map();
|
|
25
|
+
const unlock = (scope) => {
|
|
26
|
+
if (!lockedScopes.has(scope)) {
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
lockedScopes.get(scope).resolve();
|
|
30
|
+
lockedScopes.delete(scope);
|
|
31
|
+
};
|
|
32
|
+
const wait = (scope) => {
|
|
33
|
+
if (!lockedScopes.has(scope)) {
|
|
34
|
+
return Promise.resolve();
|
|
35
|
+
}
|
|
36
|
+
return lockedScopes.get(scope).promise;
|
|
37
|
+
};
|
|
38
|
+
const lock = (scope) => {
|
|
39
|
+
if (lockedScopes.has(scope)) {
|
|
40
|
+
throw new Error(`scope "${scope}" is already locked`);
|
|
41
|
+
}
|
|
42
|
+
lockedScopes.set(scope, reversePromiseFactory());
|
|
43
|
+
};
|
|
44
|
+
const isLocked = (scope) => {
|
|
45
|
+
return lockedScopes.has(scope);
|
|
46
|
+
};
|
|
47
|
+
return {
|
|
48
|
+
isLocked,
|
|
49
|
+
lock,
|
|
50
|
+
unlock,
|
|
51
|
+
wait,
|
|
52
|
+
};
|
|
13
53
|
}
|
|
14
54
|
add(actions, context = {}, name = this.getName()) {
|
|
15
|
-
const queue = new
|
|
55
|
+
const queue = new AsyncQueue({
|
|
16
56
|
name, actions,
|
|
17
57
|
end: () => {
|
|
18
58
|
this.queues.delete(name);
|
|
19
59
|
this.endEvent(name);
|
|
20
60
|
},
|
|
21
61
|
logger: this.logger,
|
|
62
|
+
lockingContext: this.locking,
|
|
22
63
|
});
|
|
23
64
|
this.queues.set(name, queue);
|
|
24
65
|
queue.run(context);
|
|
@@ -35,4 +76,3 @@ class QueueRunner {
|
|
|
35
76
|
return Math.random().toString(36).substring(2, 10);
|
|
36
77
|
}
|
|
37
78
|
}
|
|
38
|
-
exports.QueueRunner = QueueRunner;
|
package/_esm/testlib.js
ADDED
package/_esm/types.js
CHANGED
|
@@ -1,2 +1 @@
|
|
|
1
|
-
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
1
|
+
export {};
|
package/_esm/utils.js
CHANGED
|
@@ -1,21 +1,17 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
exports.util = exports.Delay = void 0;
|
|
4
|
-
const action_js_1 = require("./action.js");
|
|
5
|
-
class Delay extends action_js_1.Action {
|
|
1
|
+
import { Action } from "./action.js";
|
|
2
|
+
export class Delay extends Action {
|
|
6
3
|
async execute() {
|
|
7
4
|
return new Promise(res => {
|
|
8
5
|
setTimeout(res, this.delay);
|
|
9
6
|
});
|
|
10
7
|
}
|
|
11
8
|
}
|
|
12
|
-
|
|
13
|
-
exports.util = {
|
|
9
|
+
export const util = {
|
|
14
10
|
delay(timeout) {
|
|
15
11
|
return new Delay({ delay: timeout });
|
|
16
12
|
},
|
|
17
13
|
if(condition, branches) {
|
|
18
|
-
class IfAction extends
|
|
14
|
+
class IfAction extends Action {
|
|
19
15
|
async execute(context) {
|
|
20
16
|
const result = await condition(context);
|
|
21
17
|
if (result) {
|
|
@@ -29,7 +25,7 @@ exports.util = {
|
|
|
29
25
|
return new IfAction();
|
|
30
26
|
},
|
|
31
27
|
valid(validator, actions) {
|
|
32
|
-
class Validator extends
|
|
28
|
+
class Validator extends Action {
|
|
33
29
|
async execute(context) {
|
|
34
30
|
const valid = await validator(context);
|
|
35
31
|
if (valid) {
|
package/_types/action.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { IAction, QueueContext } from "./types.js";
|
|
1
|
+
import { IAction, ILockingAction, QueueContext } from "./types.js";
|
|
2
2
|
export type Options = {
|
|
3
3
|
delay?: number;
|
|
4
4
|
};
|
|
@@ -7,3 +7,13 @@ export declare abstract class Action<C> implements IAction {
|
|
|
7
7
|
constructor(opts?: Options);
|
|
8
8
|
abstract execute(context: C & QueueContext): Promise<void>;
|
|
9
9
|
}
|
|
10
|
+
export declare abstract class LockingAction<C> extends Action<C> implements ILockingAction {
|
|
11
|
+
locking: boolean;
|
|
12
|
+
scope: string | null;
|
|
13
|
+
}
|
|
14
|
+
export declare function lockingClassFactory<C>(scope: string): abstract new (opts?: Options) => {
|
|
15
|
+
scope: string;
|
|
16
|
+
locking: boolean;
|
|
17
|
+
delay: number;
|
|
18
|
+
execute(context: C & QueueContext): Promise<void>;
|
|
19
|
+
};
|
package/_types/queue.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { LockingContext } from './runner.js';
|
|
1
2
|
import { IAction, QueueAction, QueueContext } from './types.js';
|
|
2
3
|
export interface ILogger {
|
|
3
4
|
info: (message: string) => void;
|
|
@@ -9,12 +10,14 @@ export type QueueOpts = {
|
|
|
9
10
|
name: string;
|
|
10
11
|
end?: () => void;
|
|
11
12
|
logger?: ILogger;
|
|
13
|
+
lockingContext: LockingContext;
|
|
12
14
|
};
|
|
13
15
|
export declare class AsyncQueue {
|
|
14
16
|
name: string;
|
|
15
17
|
queue: QueueAction[];
|
|
16
18
|
end: () => void;
|
|
17
19
|
logger: ILogger;
|
|
20
|
+
locker: LockingContext;
|
|
18
21
|
loopAction: boolean;
|
|
19
22
|
context: QueueContext;
|
|
20
23
|
constructor(opts: QueueOpts);
|
package/_types/runner.d.ts
CHANGED
|
@@ -4,11 +4,19 @@ export type EndListener = (name: string, size: number) => void;
|
|
|
4
4
|
export type RunnerOpts = {
|
|
5
5
|
logger?: ILogger;
|
|
6
6
|
};
|
|
7
|
+
export type LockingContext = {
|
|
8
|
+
isLocked: (scope: string) => boolean;
|
|
9
|
+
lock: (scope: string) => void;
|
|
10
|
+
unlock: (scope: string) => void;
|
|
11
|
+
wait: (scope: string) => Promise<unknown>;
|
|
12
|
+
};
|
|
7
13
|
export declare class QueueRunner {
|
|
8
14
|
queues: Map<any, any>;
|
|
9
15
|
listeners: EndListener[];
|
|
10
16
|
logger?: ILogger;
|
|
17
|
+
locking: LockingContext;
|
|
11
18
|
constructor(opts?: RunnerOpts);
|
|
19
|
+
preparteLockingContext(): LockingContext;
|
|
12
20
|
add(actions: QueueAction[], context?: object, name?: string): void;
|
|
13
21
|
addEndListener(listener: EndListener): void;
|
|
14
22
|
endEvent(name: string): void;
|
package/_types/types.d.ts
CHANGED
|
@@ -2,8 +2,12 @@ export interface IAction {
|
|
|
2
2
|
delay: number;
|
|
3
3
|
execute: (context: any) => Promise<void>;
|
|
4
4
|
}
|
|
5
|
+
export interface ILockingAction {
|
|
6
|
+
locking: boolean;
|
|
7
|
+
scope: string | null;
|
|
8
|
+
}
|
|
5
9
|
export type ActionClass = new (...args: any[]) => IAction;
|
|
6
|
-
export type QueueAction = IAction | ActionClass
|
|
10
|
+
export type QueueAction = IAction | ActionClass | Partial<ILockingAction>;
|
|
7
11
|
export type Branches = {
|
|
8
12
|
then: QueueAction[];
|
|
9
13
|
else?: QueueAction[];
|