@praxisjs/concurrent 1.2.13 → 1.3.1
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/CHANGELOG.md +41 -0
- package/dist/__tests__/decorators.test.js +60 -3
- package/dist/__tests__/decorators.test.js.map +1 -1
- package/dist/__tests__/pool.test.js +103 -70
- package/dist/__tests__/pool.test.js.map +1 -1
- package/dist/__tests__/queue.test.js +86 -71
- package/dist/__tests__/queue.test.js.map +1 -1
- package/dist/__tests__/task.test.js +90 -68
- package/dist/__tests__/task.test.js.map +1 -1
- package/dist/__tests__/utils.test.d.ts +2 -0
- package/dist/__tests__/utils.test.d.ts.map +1 -0
- package/dist/__tests__/utils.test.js +32 -0
- package/dist/__tests__/utils.test.js.map +1 -0
- package/dist/decorators.d.ts +13 -3
- package/dist/decorators.d.ts.map +1 -1
- package/dist/decorators.js +8 -3
- package/dist/decorators.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/pool.d.ts +4 -1
- package/dist/pool.d.ts.map +1 -1
- package/dist/pool.js +29 -5
- package/dist/pool.js.map +1 -1
- package/dist/queue.d.ts +3 -1
- package/dist/queue.d.ts.map +1 -1
- package/dist/queue.js +35 -9
- package/dist/queue.js.map +1 -1
- package/dist/task.d.ts +3 -1
- package/dist/task.d.ts.map +1 -1
- package/dist/task.js +16 -3
- package/dist/task.js.map +1 -1
- package/dist/utils.d.ts +9 -0
- package/dist/utils.d.ts.map +1 -0
- package/dist/utils.js +26 -0
- package/dist/utils.js.map +1 -0
- package/package.json +4 -4
- package/src/__tests__/decorators.test.ts +78 -3
- package/src/__tests__/pool.test.ts +110 -102
- package/src/__tests__/queue.test.ts +103 -114
- package/src/__tests__/task.test.ts +96 -90
- package/src/__tests__/utils.test.ts +48 -0
- package/src/decorators.ts +23 -6
- package/src/index.ts +1 -0
- package/src/pool.ts +33 -4
- package/src/queue.ts +36 -8
- package/src/task.ts +18 -2
- package/src/utils.ts +24 -0
package/dist/decorators.d.ts
CHANGED
|
@@ -1,22 +1,32 @@
|
|
|
1
1
|
import type { Computed } from "@praxisjs/shared";
|
|
2
2
|
type AnyAsyncFn = (this: any, ...args: any[]) => Promise<any>;
|
|
3
|
-
|
|
3
|
+
/**
|
|
4
|
+
* Strips the leading AbortSignal from a parameter tuple when present,
|
|
5
|
+
* so decorated fields expose only the user-visible arguments.
|
|
6
|
+
*
|
|
7
|
+
* Examples:
|
|
8
|
+
* [AbortSignal, number, string] → [number, string]
|
|
9
|
+
* [number, string] → [number, string] (unchanged)
|
|
10
|
+
*/
|
|
11
|
+
type DropSignalIfPresent<T extends unknown[]> = T extends [AbortSignal, ...infer R] ? R : T;
|
|
12
|
+
export type TaskDecorated<T extends AnyAsyncFn> = ((...args: DropSignalIfPresent<Parameters<T>>) => ReturnType<T>) & {
|
|
4
13
|
loading: Computed<boolean>;
|
|
5
14
|
error: Computed<Error | null>;
|
|
6
15
|
lastResult: Computed<Awaited<ReturnType<T>> | null>;
|
|
7
16
|
cancelAll(): void;
|
|
8
17
|
};
|
|
9
|
-
export type QueueDecorated<T extends AnyAsyncFn> = ((...args: Parameters<T
|
|
18
|
+
export type QueueDecorated<T extends AnyAsyncFn> = ((...args: DropSignalIfPresent<Parameters<T>>) => ReturnType<T>) & {
|
|
10
19
|
loading: Computed<boolean>;
|
|
11
20
|
pending: Computed<number>;
|
|
12
21
|
error: Computed<Error | null>;
|
|
13
22
|
clear(): void;
|
|
14
23
|
};
|
|
15
|
-
export type PoolDecorated<T extends AnyAsyncFn> = ((...args: Parameters<T
|
|
24
|
+
export type PoolDecorated<T extends AnyAsyncFn> = ((...args: DropSignalIfPresent<Parameters<T>>) => ReturnType<T>) & {
|
|
16
25
|
loading: Computed<boolean>;
|
|
17
26
|
active: Computed<number>;
|
|
18
27
|
pending: Computed<number>;
|
|
19
28
|
error: Computed<Error | null>;
|
|
29
|
+
cancelAll(): void;
|
|
20
30
|
};
|
|
21
31
|
export type TaskOf<C, K extends keyof C> = C[K] extends AnyAsyncFn ? TaskDecorated<C[K]> : never;
|
|
22
32
|
export type QueueOf<C, K extends keyof C> = C[K] extends AnyAsyncFn ? QueueDecorated<C[K]> : never;
|
package/dist/decorators.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"decorators.d.ts","sourceRoot":"","sources":["../src/decorators.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"decorators.d.ts","sourceRoot":"","sources":["../src/decorators.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAQjD,KAAK,UAAU,GAAG,CAAC,IAAI,EAAE,GAAG,EAAE,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,OAAO,CAAC,GAAG,CAAC,CAAC;AAE9D;;;;;;;GAOG;AACH,KAAK,mBAAmB,CAAC,CAAC,SAAS,OAAO,EAAE,IAC1C,CAAC,SAAS,CAAC,WAAW,EAAE,GAAG,MAAM,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;AAI9C,MAAM,MAAM,aAAa,CAAC,CAAC,SAAS,UAAU,IAC5C,CAAC,CAAC,GAAG,IAAI,EAAE,mBAAmB,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,KAAK,UAAU,CAAC,CAAC,CAAC,CAAC,GAAG;IACjE,OAAO,EAAE,QAAQ,CAAC,OAAO,CAAC,CAAC;IAC3B,KAAK,EAAE,QAAQ,CAAC,KAAK,GAAG,IAAI,CAAC,CAAC;IAC9B,UAAU,EAAE,QAAQ,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;IACpD,SAAS,IAAI,IAAI,CAAC;CACnB,CAAC;AAEJ,MAAM,MAAM,cAAc,CAAC,CAAC,SAAS,UAAU,IAC7C,CAAC,CAAC,GAAG,IAAI,EAAE,mBAAmB,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,KAAK,UAAU,CAAC,CAAC,CAAC,CAAC,GAAG;IACjE,OAAO,EAAE,QAAQ,CAAC,OAAO,CAAC,CAAC;IAC3B,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;IAC1B,KAAK,EAAE,QAAQ,CAAC,KAAK,GAAG,IAAI,CAAC,CAAC;IAC9B,KAAK,IAAI,IAAI,CAAC;CACf,CAAC;AAEJ,MAAM,MAAM,aAAa,CAAC,CAAC,SAAS,UAAU,IAC5C,CAAC,CAAC,GAAG,IAAI,EAAE,mBAAmB,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,KAAK,UAAU,CAAC,CAAC,CAAC,CAAC,GAAG;IACjE,OAAO,EAAE,QAAQ,CAAC,OAAO,CAAC,CAAC;IAC3B,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;IACzB,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;IAC1B,KAAK,EAAE,QAAQ,CAAC,KAAK,GAAG,IAAI,CAAC,CAAC;IAC9B,SAAS,IAAI,IAAI,CAAC;CACnB,CAAC;AAIJ,MAAM,MAAM,MAAM,CAAC,CAAC,EAAE,CAAC,SAAS,MAAM,CAAC,IACrC,CAAC,CAAC,CAAC,CAAC,SAAS,UAAU,GAAG,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC;AAExD,MAAM,MAAM,OAAO,CAAC,CAAC,EAAE,CAAC,SAAS,MAAM,CAAC,IACtC,CAAC,CAAC,CAAC,CAAC,SAAS,UAAU,GAAG,cAAc,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC;AAEzD,MAAM,MAAM,MAAM,CAAC,CAAC,EAAE,CAAC,SAAS,MAAM,CAAC,IACrC,CAAC,CAAC,CAAC,CAAC,SAAS,UAAU,GAAG,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC;AAIxD,wBAAgB,IAAI,CAAC,UAAU,EAAE,MAAM,uHActC;AAID,wBAAgB,KAAK,CAAC,UAAU,EAAE,MAAM,uHAavC;AAID,wBAAgB,IAAI,CAAC,UAAU,EAAE,MAAM,EAAE,WAAW,SAAI,uHAavD"}
|
package/dist/decorators.js
CHANGED
|
@@ -2,14 +2,17 @@ import { createFieldDecorator } from "@praxisjs/decorators";
|
|
|
2
2
|
import { pool } from "./pool";
|
|
3
3
|
import { queue } from "./queue";
|
|
4
4
|
import { task } from "./task";
|
|
5
|
+
import { acceptsSignal } from "./utils";
|
|
5
6
|
// ── @Task ──────────────────────────────────────────────────────────────────────
|
|
6
7
|
export function Task(methodName) {
|
|
7
8
|
return createFieldDecorator({
|
|
8
9
|
bind(instance, _name) {
|
|
9
10
|
const inst = instance;
|
|
11
|
+
// Detect signal on the unbound method — bound functions lose their source.
|
|
12
|
+
const wantsSignal = acceptsSignal(inst[methodName]);
|
|
10
13
|
return {
|
|
11
14
|
descriptor: {
|
|
12
|
-
value: task(inst[methodName].bind(instance)),
|
|
15
|
+
value: task(inst[methodName].bind(instance), { signal: wantsSignal }),
|
|
13
16
|
writable: true,
|
|
14
17
|
},
|
|
15
18
|
};
|
|
@@ -21,9 +24,10 @@ export function Queue(methodName) {
|
|
|
21
24
|
return createFieldDecorator({
|
|
22
25
|
bind(instance, _name) {
|
|
23
26
|
const inst = instance;
|
|
27
|
+
const wantsSignal = acceptsSignal(inst[methodName]);
|
|
24
28
|
return {
|
|
25
29
|
descriptor: {
|
|
26
|
-
value: queue(inst[methodName].bind(instance)),
|
|
30
|
+
value: queue(inst[methodName].bind(instance), { signal: wantsSignal }),
|
|
27
31
|
writable: true,
|
|
28
32
|
},
|
|
29
33
|
};
|
|
@@ -35,9 +39,10 @@ export function Pool(methodName, concurrency = 1) {
|
|
|
35
39
|
return createFieldDecorator({
|
|
36
40
|
bind(instance, _name) {
|
|
37
41
|
const inst = instance;
|
|
42
|
+
const wantsSignal = acceptsSignal(inst[methodName]);
|
|
38
43
|
return {
|
|
39
44
|
descriptor: {
|
|
40
|
-
value: pool(concurrency, inst[methodName].bind(instance)),
|
|
45
|
+
value: pool(concurrency, inst[methodName].bind(instance), { signal: wantsSignal }),
|
|
41
46
|
writable: true,
|
|
42
47
|
},
|
|
43
48
|
};
|
package/dist/decorators.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"decorators.js","sourceRoot":"","sources":["../src/decorators.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAG5D,OAAO,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AAC9B,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAChC,OAAO,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;
|
|
1
|
+
{"version":3,"file":"decorators.js","sourceRoot":"","sources":["../src/decorators.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAG5D,OAAO,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AAC9B,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAChC,OAAO,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AAC9B,OAAO,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAsDxC,kFAAkF;AAElF,MAAM,UAAU,IAAI,CAAC,UAAkB;IACrC,OAAO,oBAAoB,CAAC;QAC1B,IAAI,CAAC,QAAgB,EAAE,KAAa;YAClC,MAAM,IAAI,GAAG,QAAsC,CAAC;YACpD,2EAA2E;YAC3E,MAAM,WAAW,GAAG,aAAa,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC;YACpD,OAAO;gBACL,UAAU,EAAE;oBACV,KAAK,EAAE,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,MAAM,EAAE,WAAW,EAAE,CAAY;oBAChF,QAAQ,EAAE,IAAI;iBACf;aACF,CAAC;QACJ,CAAC;KACF,CAAC,CAAC;AACL,CAAC;AAED,kFAAkF;AAElF,MAAM,UAAU,KAAK,CAAC,UAAkB;IACtC,OAAO,oBAAoB,CAAC;QAC1B,IAAI,CAAC,QAAgB,EAAE,KAAa;YAClC,MAAM,IAAI,GAAG,QAAsC,CAAC;YACpD,MAAM,WAAW,GAAG,aAAa,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC;YACpD,OAAO;gBACL,UAAU,EAAE;oBACV,KAAK,EAAE,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,MAAM,EAAE,WAAW,EAAE,CAAY;oBACjF,QAAQ,EAAE,IAAI;iBACf;aACF,CAAC;QACJ,CAAC;KACF,CAAC,CAAC;AACL,CAAC;AAED,kFAAkF;AAElF,MAAM,UAAU,IAAI,CAAC,UAAkB,EAAE,WAAW,GAAG,CAAC;IACtD,OAAO,oBAAoB,CAAC;QAC1B,IAAI,CAAC,QAAgB,EAAE,KAAa;YAClC,MAAM,IAAI,GAAG,QAAsC,CAAC;YACpD,MAAM,WAAW,GAAG,aAAa,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC;YACpD,OAAO;gBACL,UAAU,EAAE;oBACV,KAAK,EAAE,IAAI,CAAC,WAAW,EAAE,IAAI,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,MAAM,EAAE,WAAW,EAAE,CAAY;oBAC7F,QAAQ,EAAE,IAAI;iBACf;aACF,CAAC;QACJ,CAAC;KACF,CAAC,CAAC;AACL,CAAC"}
|
package/dist/index.d.ts
CHANGED
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,cAAc,CAAC;AACjD,YAAY,EAAE,aAAa,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,cAAc,CAAC;AACjD,YAAY,EAAE,aAAa,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAC1G,OAAO,EAAE,iBAAiB,EAAE,MAAM,SAAS,CAAC"}
|
package/dist/index.js
CHANGED
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,cAAc,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,cAAc,CAAC;AAEjD,OAAO,EAAE,iBAAiB,EAAE,MAAM,SAAS,CAAC"}
|
package/dist/pool.d.ts
CHANGED
|
@@ -5,6 +5,9 @@ export interface PoolInstance<T> {
|
|
|
5
5
|
active: Computed<number>;
|
|
6
6
|
pending: Computed<number>;
|
|
7
7
|
error: Computed<Error | null>;
|
|
8
|
+
cancelAll(): void;
|
|
8
9
|
}
|
|
9
|
-
export declare function pool<T>(concurrency: number, fn: (...args: unknown[]) => Promise<T
|
|
10
|
+
export declare function pool<T>(concurrency: number, fn: (...args: unknown[]) => Promise<T>, options?: {
|
|
11
|
+
signal?: boolean;
|
|
12
|
+
}): PoolInstance<T>;
|
|
10
13
|
//# sourceMappingURL=pool.d.ts.map
|
package/dist/pool.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pool.d.ts","sourceRoot":"","sources":["../src/pool.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"pool.d.ts","sourceRoot":"","sources":["../src/pool.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAIjD,MAAM,WAAW,YAAY,CAAC,CAAC;IAC7B,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,CAAC,GAAG,SAAS,CAAC,CAAC;IAC7C,OAAO,EAAE,QAAQ,CAAC,OAAO,CAAC,CAAC;IAC3B,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;IACzB,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;IAC1B,KAAK,EAAE,QAAQ,CAAC,KAAK,GAAG,IAAI,CAAC,CAAC;IAC9B,SAAS,IAAI,IAAI,CAAC;CACnB;AAMD,wBAAgB,IAAI,CAAC,CAAC,EACpB,WAAW,EAAE,MAAM,EACnB,EAAE,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,OAAO,CAAC,CAAC,CAAC,EACtC,OAAO,CAAC,EAAE;IAAE,MAAM,CAAC,EAAE,OAAO,CAAA;CAAE,GAC7B,YAAY,CAAC,CAAC,CAAC,CAgEjB"}
|
package/dist/pool.js
CHANGED
|
@@ -1,33 +1,45 @@
|
|
|
1
1
|
import { signal, computed } from "@praxisjs/core/internal";
|
|
2
|
-
|
|
2
|
+
import { acceptsSignal } from "./utils";
|
|
3
|
+
function isAbortError(err) {
|
|
4
|
+
return err instanceof Error && err.name === "AbortError";
|
|
5
|
+
}
|
|
6
|
+
export function pool(concurrency, fn, options) {
|
|
3
7
|
concurrency = Math.max(1, concurrency);
|
|
4
8
|
const _active = signal(0);
|
|
5
9
|
const _pending = signal(0);
|
|
6
10
|
const _error = signal(null);
|
|
11
|
+
const _wantsSignal = options?.signal ?? acceptsSignal(fn);
|
|
7
12
|
const _queue = [];
|
|
13
|
+
const _activeControllers = new Set();
|
|
8
14
|
async function tryRun() {
|
|
9
15
|
if (_active() >= concurrency || _queue.length === 0)
|
|
10
16
|
return;
|
|
11
17
|
const item = _queue[0];
|
|
12
18
|
_queue.shift();
|
|
13
|
-
const { args, resolve } = item;
|
|
19
|
+
const { args, resolve, controller } = item;
|
|
14
20
|
_pending.update((n) => n - 1);
|
|
15
21
|
_active.update((n) => n + 1);
|
|
22
|
+
_activeControllers.add(controller);
|
|
16
23
|
try {
|
|
17
|
-
|
|
24
|
+
const result = await (_wantsSignal ? fn(controller.signal, ...args) : fn(...args));
|
|
25
|
+
resolve(result);
|
|
18
26
|
}
|
|
19
27
|
catch (err) {
|
|
20
|
-
|
|
28
|
+
if (!isAbortError(err)) {
|
|
29
|
+
_error.set(err instanceof Error ? err : new Error(String(err)));
|
|
30
|
+
}
|
|
21
31
|
resolve(undefined);
|
|
22
32
|
}
|
|
23
33
|
finally {
|
|
34
|
+
_activeControllers.delete(controller);
|
|
24
35
|
_active.update((n) => n - 1);
|
|
25
36
|
void tryRun();
|
|
26
37
|
}
|
|
27
38
|
}
|
|
28
39
|
function run(...args) {
|
|
40
|
+
const controller = new AbortController();
|
|
29
41
|
return new Promise((resolve) => {
|
|
30
|
-
_queue.push({ args, resolve });
|
|
42
|
+
_queue.push({ args, resolve, controller });
|
|
31
43
|
_pending.update((n) => n + 1);
|
|
32
44
|
void tryRun();
|
|
33
45
|
});
|
|
@@ -36,6 +48,18 @@ export function pool(concurrency, fn) {
|
|
|
36
48
|
run.active = computed(() => _active());
|
|
37
49
|
run.pending = computed(() => _pending());
|
|
38
50
|
run.error = computed(() => _error());
|
|
51
|
+
run.cancelAll = () => {
|
|
52
|
+
for (const c of _activeControllers) {
|
|
53
|
+
c.abort();
|
|
54
|
+
}
|
|
55
|
+
_activeControllers.clear();
|
|
56
|
+
while (_queue.length > 0) {
|
|
57
|
+
const item = _queue.shift();
|
|
58
|
+
item?.controller.abort();
|
|
59
|
+
item?.resolve(undefined);
|
|
60
|
+
}
|
|
61
|
+
_pending.set(0);
|
|
62
|
+
};
|
|
39
63
|
return run;
|
|
40
64
|
}
|
|
41
65
|
//# sourceMappingURL=pool.js.map
|
package/dist/pool.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pool.js","sourceRoot":"","sources":["../src/pool.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAC;
|
|
1
|
+
{"version":3,"file":"pool.js","sourceRoot":"","sources":["../src/pool.ts"],"names":[],"mappings":"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"}
|
package/dist/queue.d.ts
CHANGED
|
@@ -9,5 +9,7 @@ export interface QueueInstance<T> {
|
|
|
9
9
|
error: Computed<Error | null>;
|
|
10
10
|
clear(): void;
|
|
11
11
|
}
|
|
12
|
-
export declare function queue<T>(fn: (...args: unknown[]) => Promise<T
|
|
12
|
+
export declare function queue<T>(fn: (...args: unknown[]) => Promise<T>, options?: {
|
|
13
|
+
signal?: boolean;
|
|
14
|
+
}): QueueInstance<T>;
|
|
13
15
|
//# sourceMappingURL=queue.d.ts.map
|
package/dist/queue.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"queue.d.ts","sourceRoot":"","sources":["../src/queue.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"queue.d.ts","sourceRoot":"","sources":["../src/queue.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAIjD,qBAAa,iBAAkB,SAAQ,KAAK;;CAK3C;AAMD,MAAM,WAAW,aAAa,CAAC,CAAC;IAC9B,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;IACjC,OAAO,EAAE,QAAQ,CAAC,OAAO,CAAC,CAAC;IAC3B,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;IAC1B,KAAK,EAAE,QAAQ,CAAC,KAAK,GAAG,IAAI,CAAC,CAAC;IAC9B,KAAK,IAAI,IAAI,CAAC;CACf;AAED,wBAAgB,KAAK,CAAC,CAAC,EACrB,EAAE,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,OAAO,CAAC,CAAC,CAAC,EACtC,OAAO,CAAC,EAAE;IAAE,MAAM,CAAC,EAAE,OAAO,CAAA;CAAE,GAC7B,aAAa,CAAC,CAAC,CAAC,CAgFlB"}
|
package/dist/queue.js
CHANGED
|
@@ -1,17 +1,24 @@
|
|
|
1
1
|
import { signal, computed } from "@praxisjs/core/internal";
|
|
2
|
+
import { acceptsSignal } from "./utils";
|
|
2
3
|
export class QueueClearedError extends Error {
|
|
3
4
|
constructor() {
|
|
4
5
|
super("Queue cleared");
|
|
5
6
|
this.name = "QueueClearedError";
|
|
6
7
|
}
|
|
7
8
|
}
|
|
8
|
-
|
|
9
|
+
function isAbortError(err) {
|
|
10
|
+
return err instanceof Error && err.name === "AbortError";
|
|
11
|
+
}
|
|
12
|
+
export function queue(fn, options) {
|
|
9
13
|
const _loading = signal(false);
|
|
10
14
|
const _pending = signal(0);
|
|
11
15
|
const _error = signal(null);
|
|
16
|
+
const _wantsSignal = options?.signal ?? acceptsSignal(fn);
|
|
12
17
|
const _queue = [];
|
|
13
18
|
let _running = false;
|
|
14
19
|
let _cleared = false;
|
|
20
|
+
let _activeController = null;
|
|
21
|
+
let _activeAbortedByClear = false;
|
|
15
22
|
async function drain() {
|
|
16
23
|
if (_running || _queue.length === 0)
|
|
17
24
|
return;
|
|
@@ -20,15 +27,28 @@ export function queue(fn) {
|
|
|
20
27
|
while (_queue.length > 0) {
|
|
21
28
|
const item = _queue[0];
|
|
22
29
|
_queue.shift();
|
|
23
|
-
const { args, resolve, reject } = item;
|
|
30
|
+
const { args, resolve, reject, controller } = item;
|
|
31
|
+
_activeController = controller;
|
|
32
|
+
_activeAbortedByClear = false;
|
|
24
33
|
_pending.update((n) => n - 1);
|
|
25
34
|
try {
|
|
26
|
-
|
|
35
|
+
const result = await (_wantsSignal ? fn(controller.signal, ...args) : fn(...args));
|
|
36
|
+
resolve(result);
|
|
27
37
|
}
|
|
28
38
|
catch (err) {
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
39
|
+
// _activeAbortedByClear is set asynchronously by clear() between the await and this catch
|
|
40
|
+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
|
41
|
+
if (isAbortError(err) && _activeAbortedByClear) {
|
|
42
|
+
reject(new QueueClearedError());
|
|
43
|
+
}
|
|
44
|
+
else {
|
|
45
|
+
const e = err instanceof Error ? err : new Error(String(err));
|
|
46
|
+
_error.set(e);
|
|
47
|
+
reject(e);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
finally {
|
|
51
|
+
_activeController = null;
|
|
32
52
|
}
|
|
33
53
|
}
|
|
34
54
|
_cleared = false;
|
|
@@ -39,8 +59,9 @@ export function queue(fn) {
|
|
|
39
59
|
if (_cleared) {
|
|
40
60
|
_cleared = false;
|
|
41
61
|
}
|
|
62
|
+
const controller = new AbortController();
|
|
42
63
|
return new Promise((resolve, reject) => {
|
|
43
|
-
_queue.push({ args, resolve, reject });
|
|
64
|
+
_queue.push({ args, resolve, reject, controller });
|
|
44
65
|
_pending.update((n) => n + 1);
|
|
45
66
|
void drain();
|
|
46
67
|
});
|
|
@@ -49,9 +70,14 @@ export function queue(fn) {
|
|
|
49
70
|
enqueue.pending = computed(() => _pending());
|
|
50
71
|
enqueue.error = computed(() => _error());
|
|
51
72
|
enqueue.clear = () => {
|
|
52
|
-
|
|
73
|
+
if (_activeController) {
|
|
74
|
+
_activeAbortedByClear = true;
|
|
75
|
+
_activeController.abort();
|
|
76
|
+
}
|
|
53
77
|
while (_queue.length > 0) {
|
|
54
|
-
_queue.shift()
|
|
78
|
+
const item = _queue.shift();
|
|
79
|
+
item?.controller.abort();
|
|
80
|
+
item?.reject(new QueueClearedError());
|
|
55
81
|
}
|
|
56
82
|
_pending.set(0);
|
|
57
83
|
_cleared = true;
|
package/dist/queue.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"queue.js","sourceRoot":"","sources":["../src/queue.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AAG3D,MAAM,OAAO,iBAAkB,SAAQ,KAAK;IAC1C;QACE,KAAK,CAAC,eAAe,CAAC,CAAC;QACvB,IAAI,CAAC,IAAI,GAAG,mBAAmB,CAAC;IAClC,CAAC;CACF;AAUD,MAAM,UAAU,KAAK,CACnB,EAAsC;
|
|
1
|
+
{"version":3,"file":"queue.js","sourceRoot":"","sources":["../src/queue.ts"],"names":[],"mappings":"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"}
|
package/dist/task.d.ts
CHANGED
|
@@ -6,5 +6,7 @@ export interface TaskInstance<T> {
|
|
|
6
6
|
lastResult: Computed<T | null>;
|
|
7
7
|
cancelAll(): void;
|
|
8
8
|
}
|
|
9
|
-
export declare function task<T>(fn: (...args: unknown[]) => Promise<T
|
|
9
|
+
export declare function task<T>(fn: (...args: unknown[]) => Promise<T>, options?: {
|
|
10
|
+
signal?: boolean;
|
|
11
|
+
}): TaskInstance<T>;
|
|
10
12
|
//# sourceMappingURL=task.d.ts.map
|
package/dist/task.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"task.d.ts","sourceRoot":"","sources":["../src/task.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"task.d.ts","sourceRoot":"","sources":["../src/task.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAIjD,MAAM,WAAW,YAAY,CAAC,CAAC;IAC7B,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,CAAC,GAAG,SAAS,CAAC,CAAC;IAC7C,OAAO,EAAE,QAAQ,CAAC,OAAO,CAAC,CAAC;IAC3B,KAAK,EAAE,QAAQ,CAAC,KAAK,GAAG,IAAI,CAAC,CAAC;IAC9B,UAAU,EAAE,QAAQ,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;IAC/B,SAAS,IAAI,IAAI,CAAC;CACnB;AAMD,wBAAgB,IAAI,CAAC,CAAC,EACpB,EAAE,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,OAAO,CAAC,CAAC,CAAC,EACtC,OAAO,CAAC,EAAE;IAAE,MAAM,CAAC,EAAE,OAAO,CAAA;CAAE,GAC7B,YAAY,CAAC,CAAC,CAAC,CA0CjB"}
|
package/dist/task.js
CHANGED
|
@@ -1,15 +1,24 @@
|
|
|
1
1
|
import { signal, computed } from "@praxisjs/core/internal";
|
|
2
|
-
|
|
2
|
+
import { acceptsSignal } from "./utils";
|
|
3
|
+
function isAbortError(err) {
|
|
4
|
+
return err instanceof Error && err.name === "AbortError";
|
|
5
|
+
}
|
|
6
|
+
export function task(fn, options) {
|
|
3
7
|
const _loading = signal(false);
|
|
4
8
|
const _error = signal(null);
|
|
5
9
|
const _lastResult = signal(null);
|
|
6
10
|
let _runId = 0;
|
|
11
|
+
let _controller = null;
|
|
12
|
+
const _wantsSignal = options?.signal ?? acceptsSignal(fn);
|
|
7
13
|
async function run(...args) {
|
|
14
|
+
_controller?.abort();
|
|
15
|
+
const controller = new AbortController();
|
|
16
|
+
_controller = controller;
|
|
8
17
|
const id = ++_runId;
|
|
9
18
|
_loading.set(true);
|
|
10
19
|
_error.set(null);
|
|
11
20
|
try {
|
|
12
|
-
const result = await fn(...args);
|
|
21
|
+
const result = await (_wantsSignal ? fn(controller.signal, ...args) : fn(...args));
|
|
13
22
|
if (id !== _runId)
|
|
14
23
|
return undefined;
|
|
15
24
|
_lastResult.set(result);
|
|
@@ -19,7 +28,9 @@ export function task(fn) {
|
|
|
19
28
|
catch (err) {
|
|
20
29
|
if (id !== _runId)
|
|
21
30
|
return undefined;
|
|
22
|
-
|
|
31
|
+
if (!isAbortError(err)) {
|
|
32
|
+
_error.set(err instanceof Error ? err : new Error(String(err)));
|
|
33
|
+
}
|
|
23
34
|
_loading.set(false);
|
|
24
35
|
return undefined;
|
|
25
36
|
}
|
|
@@ -28,6 +39,8 @@ export function task(fn) {
|
|
|
28
39
|
run.error = computed(() => _error());
|
|
29
40
|
run.lastResult = computed(() => _lastResult());
|
|
30
41
|
run.cancelAll = () => {
|
|
42
|
+
_controller?.abort();
|
|
43
|
+
_controller = null;
|
|
31
44
|
_runId++;
|
|
32
45
|
_loading.set(false);
|
|
33
46
|
};
|
package/dist/task.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"task.js","sourceRoot":"","sources":["../src/task.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAC;
|
|
1
|
+
{"version":3,"file":"task.js","sourceRoot":"","sources":["../src/task.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AAG3D,OAAO,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAUxC,SAAS,YAAY,CAAC,GAAY;IAChC,OAAO,GAAG,YAAY,KAAK,IAAI,GAAG,CAAC,IAAI,KAAK,YAAY,CAAC;AAC3D,CAAC;AAED,MAAM,UAAU,IAAI,CAClB,EAAsC,EACtC,OAA8B;IAE9B,MAAM,QAAQ,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;IAC/B,MAAM,MAAM,GAAG,MAAM,CAAe,IAAI,CAAC,CAAC;IAC1C,MAAM,WAAW,GAAG,MAAM,CAAW,IAAI,CAAC,CAAC;IAC3C,IAAI,MAAM,GAAG,CAAC,CAAC;IACf,IAAI,WAAW,GAA2B,IAAI,CAAC;IAC/C,MAAM,YAAY,GAAG,OAAO,EAAE,MAAM,IAAI,aAAa,CAAC,EAAE,CAAC,CAAC;IAE1D,KAAK,UAAU,GAAG,CAAC,GAAG,IAAe;QACnC,WAAW,EAAE,KAAK,EAAE,CAAC;QACrB,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE,CAAC;QACzC,WAAW,GAAG,UAAU,CAAC;QACzB,MAAM,EAAE,GAAG,EAAE,MAAM,CAAC;QACpB,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACnB,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACjB,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,CAAC,YAAY,CAAC,CAAC,CAAC,EAAE,CAAC,UAAU,CAAC,MAAM,EAAE,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC;YACnF,IAAI,EAAE,KAAK,MAAM;gBAAE,OAAO,SAAS,CAAC;YACpC,WAAW,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;YACxB,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;YACpB,OAAO,MAAM,CAAC;QAChB,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAI,EAAE,KAAK,MAAM;gBAAE,OAAO,SAAS,CAAC;YACpC,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,EAAE,CAAC;gBACvB,MAAM,CAAC,GAAG,CAAC,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;YAClE,CAAC;YACD,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;YACpB,OAAO,SAAS,CAAC;QACnB,CAAC;IACH,CAAC;IAED,GAAG,CAAC,OAAO,GAAG,QAAQ,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC,CAAC;IACzC,GAAG,CAAC,KAAK,GAAG,QAAQ,CAAC,GAAG,EAAE,CAAC,MAAM,EAAE,CAAC,CAAC;IACrC,GAAG,CAAC,UAAU,GAAG,QAAQ,CAAC,GAAG,EAAE,CAAC,WAAW,EAAE,CAAC,CAAC;IAC/C,GAAG,CAAC,SAAS,GAAG,GAAG,EAAE;QACnB,WAAW,EAAE,KAAK,EAAE,CAAC;QACrB,WAAW,GAAG,IAAI,CAAC;QACnB,MAAM,EAAE,CAAC;QACT,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;IACtB,CAAC,CAAC;IAEF,OAAO,GAAsB,CAAC;AAChC,CAAC"}
|
package/dist/utils.d.ts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Returns true if the function declares `signal` as its first parameter name.
|
|
3
|
+
* Used to decide whether to inject an AbortSignal at call time.
|
|
4
|
+
*
|
|
5
|
+
* Works on unminified source (class methods, arrow functions, async functions).
|
|
6
|
+
* Bound functions always return false — check the original method before binding.
|
|
7
|
+
*/
|
|
8
|
+
export declare function acceptsSignal(fn: (...args: any[]) => any): boolean;
|
|
9
|
+
//# sourceMappingURL=utils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,wBAAgB,aAAa,CAAC,EAAE,EAAE,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,GAAG,GAAG,OAAO,CAelE"}
|
package/dist/utils.js
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Returns true if the function declares `signal` as its first parameter name.
|
|
3
|
+
* Used to decide whether to inject an AbortSignal at call time.
|
|
4
|
+
*
|
|
5
|
+
* Works on unminified source (class methods, arrow functions, async functions).
|
|
6
|
+
* Bound functions always return false — check the original method before binding.
|
|
7
|
+
*/
|
|
8
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
9
|
+
export function acceptsSignal(fn) {
|
|
10
|
+
try {
|
|
11
|
+
const src = fn.toString();
|
|
12
|
+
// Match the first character of the parameter list, e.g.:
|
|
13
|
+
// async loadUser(signal, id) → "signal"
|
|
14
|
+
// (signal: AbortSignal) => → "signal:" (TS annotation stripped below)
|
|
15
|
+
// (id: number) => → "id:"
|
|
16
|
+
// () => → ""
|
|
17
|
+
const m = /\(\s*([^),\s]*)/.exec(src);
|
|
18
|
+
const rawFirst = m?.[1] ?? "";
|
|
19
|
+
const firstName = rawFirst.split(/[:=]/)[0].trim();
|
|
20
|
+
return firstName === "signal";
|
|
21
|
+
}
|
|
22
|
+
catch {
|
|
23
|
+
return false;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
//# sourceMappingURL=utils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.js","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,8DAA8D;AAC9D,MAAM,UAAU,aAAa,CAAC,EAA2B;IACvD,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC;QAC1B,yDAAyD;QACzD,4CAA4C;QAC5C,6EAA6E;QAC7E,yCAAyC;QACzC,sCAAsC;QACtC,MAAM,CAAC,GAAG,iBAAiB,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACtC,MAAM,QAAQ,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;QAC9B,MAAM,SAAS,GAAG,QAAQ,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;QACnD,OAAO,SAAS,KAAK,QAAQ,CAAC;IAChC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@praxisjs/concurrent",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"types": "./dist/index.d.ts",
|
|
@@ -14,9 +14,9 @@
|
|
|
14
14
|
"typescript": "^5.9.3"
|
|
15
15
|
},
|
|
16
16
|
"dependencies": {
|
|
17
|
-
"@praxisjs/core": "1.
|
|
18
|
-
"@praxisjs/decorators": "1.
|
|
19
|
-
"@praxisjs/shared": "0.
|
|
17
|
+
"@praxisjs/core": "1.8.1",
|
|
18
|
+
"@praxisjs/decorators": "1.3.1",
|
|
19
|
+
"@praxisjs/shared": "0.3.0"
|
|
20
20
|
},
|
|
21
21
|
"scripts": {
|
|
22
22
|
"build": "tsc",
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { describe, it, expect } from "vitest";
|
|
2
2
|
|
|
3
3
|
import { Task, Queue, Pool } from "../decorators";
|
|
4
|
+
import { QueueClearedError } from "../queue";
|
|
4
5
|
|
|
5
6
|
function fieldCtx(name: string) {
|
|
6
7
|
const initializers: Array<(this: unknown) => void> = [];
|
|
@@ -31,12 +32,14 @@ describe("Task decorator", () => {
|
|
|
31
32
|
loading: () => boolean;
|
|
32
33
|
error: () => Error | null;
|
|
33
34
|
lastResult: () => number | null;
|
|
35
|
+
cancelAll: () => void;
|
|
34
36
|
};
|
|
35
37
|
|
|
36
38
|
expect(typeof taskLoad).toBe("function");
|
|
37
39
|
expect(taskLoad.loading).toBeDefined();
|
|
38
40
|
expect(taskLoad.error).toBeDefined();
|
|
39
41
|
expect(taskLoad.lastResult).toBeDefined();
|
|
42
|
+
expect(taskLoad.cancelAll).toBeDefined();
|
|
40
43
|
|
|
41
44
|
const result = await taskLoad(5);
|
|
42
45
|
expect(result).toBe(10);
|
|
@@ -60,6 +63,29 @@ describe("Task decorator", () => {
|
|
|
60
63
|
await p;
|
|
61
64
|
expect(taskFetch.loading()).toBe(false);
|
|
62
65
|
});
|
|
66
|
+
|
|
67
|
+
it("cancelAll() aborts the in-flight signal", async () => {
|
|
68
|
+
const { ctx, run } = fieldCtx("taskFetch");
|
|
69
|
+
Task("fetch")(undefined, ctx);
|
|
70
|
+
|
|
71
|
+
let capturedSignal!: AbortSignal;
|
|
72
|
+
let resolve!: () => void;
|
|
73
|
+
const instance: Record<string, unknown> = {
|
|
74
|
+
fetch: async (signal: AbortSignal) => {
|
|
75
|
+
capturedSignal = signal;
|
|
76
|
+
await new Promise<void>((r) => { resolve = r; });
|
|
77
|
+
},
|
|
78
|
+
};
|
|
79
|
+
run(instance);
|
|
80
|
+
|
|
81
|
+
const taskFetch = instance.taskFetch as { (): Promise<void>; cancelAll: () => void };
|
|
82
|
+
const p = taskFetch();
|
|
83
|
+
taskFetch.cancelAll();
|
|
84
|
+
resolve();
|
|
85
|
+
await p;
|
|
86
|
+
|
|
87
|
+
expect(capturedSignal.aborted).toBe(true);
|
|
88
|
+
});
|
|
63
89
|
});
|
|
64
90
|
|
|
65
91
|
// ── Queue ─────────────────────────────────────────────────────────────────────
|
|
@@ -98,10 +124,12 @@ describe("Queue decorator", () => {
|
|
|
98
124
|
|
|
99
125
|
let resolveFirst!: () => void;
|
|
100
126
|
const instance: Record<string, unknown> = {
|
|
101
|
-
save: async (_: unknown, idx: unknown) =>
|
|
102
|
-
|
|
127
|
+
save: async (signal: AbortSignal, _: unknown, idx: unknown) => {
|
|
128
|
+
void signal;
|
|
129
|
+
return idx === 0
|
|
103
130
|
? new Promise<void>((r) => { resolveFirst = r; })
|
|
104
|
-
: Promise.resolve()
|
|
131
|
+
: Promise.resolve();
|
|
132
|
+
},
|
|
105
133
|
};
|
|
106
134
|
run(instance);
|
|
107
135
|
|
|
@@ -133,6 +161,7 @@ describe("Pool decorator", () => {
|
|
|
133
161
|
active: () => number;
|
|
134
162
|
pending: () => number;
|
|
135
163
|
error: () => Error | null;
|
|
164
|
+
cancelAll: () => void;
|
|
136
165
|
};
|
|
137
166
|
|
|
138
167
|
expect(typeof taskProcess).toBe("function");
|
|
@@ -140,6 +169,7 @@ describe("Pool decorator", () => {
|
|
|
140
169
|
expect(taskProcess.active).toBeDefined();
|
|
141
170
|
expect(taskProcess.pending).toBeDefined();
|
|
142
171
|
expect(taskProcess.error).toBeDefined();
|
|
172
|
+
expect(taskProcess.cancelAll).toBeDefined();
|
|
143
173
|
|
|
144
174
|
const result = await taskProcess(9);
|
|
145
175
|
expect(result).toBe(10);
|
|
@@ -189,4 +219,49 @@ describe("Pool decorator", () => {
|
|
|
189
219
|
resolvers[1]();
|
|
190
220
|
await t2;
|
|
191
221
|
});
|
|
222
|
+
|
|
223
|
+
it("cancelAll() cancels pending and active tasks", async () => {
|
|
224
|
+
const { ctx, run } = fieldCtx("taskWork");
|
|
225
|
+
Pool("work", 1)(undefined, ctx);
|
|
226
|
+
|
|
227
|
+
let resolveFirst!: () => void;
|
|
228
|
+
const instance: Record<string, unknown> = {
|
|
229
|
+
work: async (signal: AbortSignal, idx: unknown) => {
|
|
230
|
+
void signal;
|
|
231
|
+
if (idx === 0) await new Promise<void>((r) => { resolveFirst = r; });
|
|
232
|
+
},
|
|
233
|
+
};
|
|
234
|
+
run(instance);
|
|
235
|
+
|
|
236
|
+
const taskWork = instance.taskWork as {
|
|
237
|
+
(...args: unknown[]): Promise<void>;
|
|
238
|
+
active: () => number;
|
|
239
|
+
pending: () => number;
|
|
240
|
+
cancelAll: () => void;
|
|
241
|
+
};
|
|
242
|
+
|
|
243
|
+
const t1 = taskWork(0);
|
|
244
|
+
const t2 = taskWork(1);
|
|
245
|
+
|
|
246
|
+
await Promise.resolve();
|
|
247
|
+
taskWork.cancelAll();
|
|
248
|
+
resolveFirst();
|
|
249
|
+
|
|
250
|
+
await Promise.all([t1, t2]);
|
|
251
|
+
|
|
252
|
+
expect(taskWork.active()).toBe(0);
|
|
253
|
+
expect(taskWork.pending()).toBe(0);
|
|
254
|
+
});
|
|
255
|
+
});
|
|
256
|
+
|
|
257
|
+
// ── QueueClearedError re-export ────────────────────────────────────────────────
|
|
258
|
+
|
|
259
|
+
describe("QueueClearedError", () => {
|
|
260
|
+
it("is exported from the package", () => {
|
|
261
|
+
expect(QueueClearedError).toBeDefined();
|
|
262
|
+
const e = new QueueClearedError();
|
|
263
|
+
expect(e).toBeInstanceOf(Error);
|
|
264
|
+
expect(e.name).toBe("QueueClearedError");
|
|
265
|
+
expect(e.message).toBe("Queue cleared");
|
|
266
|
+
});
|
|
192
267
|
});
|