async-queue-runner 0.15.0 → 0.17.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/index.js +2 -1
- package/_cjs/package.json +4 -4
- package/_cjs/queue.js +13 -0
- package/_cjs/runner.js +44 -0
- package/_cjs/testlib.js +8 -0
- package/_esm/action.js +14 -0
- package/_esm/index.js +1 -1
- package/_esm/package.json +4 -4
- package/_esm/queue.js +13 -0
- package/_esm/runner.js +44 -0
- package/_esm/testlib.js +5 -0
- package/_types/action.d.ts +11 -1
- package/_types/index.d.ts +1 -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/index.js
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.util = exports.Action = exports.AsyncQueue = exports.QueueRunner = void 0;
|
|
3
|
+
exports.util = exports.lockingClassFactory = exports.Action = exports.AsyncQueue = exports.QueueRunner = void 0;
|
|
4
4
|
var runner_js_1 = require("./runner.js");
|
|
5
5
|
Object.defineProperty(exports, "QueueRunner", { enumerable: true, get: function () { return runner_js_1.QueueRunner; } });
|
|
6
6
|
var queue_js_1 = require("./queue.js");
|
|
7
7
|
Object.defineProperty(exports, "AsyncQueue", { enumerable: true, get: function () { return queue_js_1.AsyncQueue; } });
|
|
8
8
|
var action_js_1 = require("./action.js");
|
|
9
9
|
Object.defineProperty(exports, "Action", { enumerable: true, get: function () { return action_js_1.Action; } });
|
|
10
|
+
Object.defineProperty(exports, "lockingClassFactory", { enumerable: true, get: function () { return action_js_1.lockingClassFactory; } });
|
|
10
11
|
var utils_js_1 = require("./utils.js");
|
|
11
12
|
Object.defineProperty(exports, "util", { enumerable: true, get: function () { return utils_js_1.util; } });
|
package/_cjs/package.json
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
{
|
|
2
|
-
"type": "commonjs"
|
|
3
|
-
}
|
|
4
|
-
|
|
1
|
+
{
|
|
2
|
+
"type": "commonjs"
|
|
3
|
+
}
|
|
4
|
+
|
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
|
@@ -5,3 +5,17 @@ export class Action {
|
|
|
5
5
|
this.delay = opts.delay;
|
|
6
6
|
}
|
|
7
7
|
}
|
|
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
package/_esm/package.json
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
{
|
|
2
|
-
"type": "module"
|
|
3
|
-
}
|
|
4
|
-
|
|
1
|
+
{
|
|
2
|
+
"type": "module"
|
|
3
|
+
}
|
|
4
|
+
|
package/_esm/queue.js
CHANGED
|
@@ -11,6 +11,7 @@ export class AsyncQueue {
|
|
|
11
11
|
queue = [];
|
|
12
12
|
end;
|
|
13
13
|
logger;
|
|
14
|
+
locker;
|
|
14
15
|
loopAction = false;
|
|
15
16
|
context = {
|
|
16
17
|
push: (actions) => this.push(actions),
|
|
@@ -28,6 +29,7 @@ export class AsyncQueue {
|
|
|
28
29
|
this.name = opts.name;
|
|
29
30
|
this.end = opts.end || (() => { });
|
|
30
31
|
this.logger = opts.logger || logger;
|
|
32
|
+
this.locker = opts.lockingContext;
|
|
31
33
|
}
|
|
32
34
|
async delay(timeout) {
|
|
33
35
|
return new Promise((res) => setTimeout(res, timeout));
|
|
@@ -44,7 +46,18 @@ export class AsyncQueue {
|
|
|
44
46
|
}
|
|
45
47
|
const item = this.queue.shift();
|
|
46
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
|
+
}
|
|
47
57
|
await this.iterate(action);
|
|
58
|
+
if (isLocking) {
|
|
59
|
+
this.locker.unlock(scope);
|
|
60
|
+
}
|
|
48
61
|
}
|
|
49
62
|
this.end();
|
|
50
63
|
}
|
package/_esm/runner.js
CHANGED
|
@@ -1,12 +1,55 @@
|
|
|
1
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
|
+
}
|
|
2
12
|
export class QueueRunner {
|
|
3
13
|
queues = new Map();
|
|
4
14
|
listeners = [];
|
|
5
15
|
logger;
|
|
16
|
+
locking;
|
|
6
17
|
constructor(opts = {}) {
|
|
7
18
|
if (opts.logger) {
|
|
8
19
|
this.logger = opts.logger;
|
|
9
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
|
+
};
|
|
10
53
|
}
|
|
11
54
|
add(actions, context = {}, name = this.getName()) {
|
|
12
55
|
const queue = new AsyncQueue({
|
|
@@ -16,6 +59,7 @@ export class QueueRunner {
|
|
|
16
59
|
this.endEvent(name);
|
|
17
60
|
},
|
|
18
61
|
logger: this.logger,
|
|
62
|
+
lockingContext: this.locking,
|
|
19
63
|
});
|
|
20
64
|
this.queues.set(name, queue);
|
|
21
65
|
queue.run(context);
|
package/_esm/testlib.js
ADDED
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/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export { IAction, ActionClass, QueueAction, Branches, QueueContext } from './types.js';
|
|
2
2
|
export { QueueRunner, EndListener } from './runner.js';
|
|
3
3
|
export { AsyncQueue, QueueOpts } from './queue.js';
|
|
4
|
-
export { Action, Options } from './action.js';
|
|
4
|
+
export { Action, Options, lockingClassFactory } from './action.js';
|
|
5
5
|
export { util } from './utils.js';
|
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[];
|