@praxisjs/concurrent 0.2.2 → 0.2.3
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 +7 -0
- package/dist/__tests__/pool.test.js +63 -1
- package/dist/__tests__/pool.test.js.map +1 -1
- package/dist/__tests__/queue.test.js +22 -0
- package/dist/__tests__/queue.test.js.map +1 -1
- package/dist/__tests__/task.test.js +58 -0
- package/dist/__tests__/task.test.js.map +1 -1
- package/package.json +2 -2
- package/src/__tests__/pool.test.ts +78 -1
- package/src/__tests__/queue.test.ts +25 -0
- package/src/__tests__/task.test.ts +73 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { describe, it, expect } from "vitest";
|
|
1
|
+
import { describe, it, expect, vi } from "vitest";
|
|
2
2
|
import { pool } from "../pool";
|
|
3
3
|
describe("pool", () => {
|
|
4
4
|
it("executes a task and resolves with its result", async () => {
|
|
@@ -60,5 +60,67 @@ describe("pool", () => {
|
|
|
60
60
|
await t2;
|
|
61
61
|
expect(p.pending()).toBe(0);
|
|
62
62
|
});
|
|
63
|
+
it("wraps non-Error throws in an Error object", async () => {
|
|
64
|
+
const p = pool(1, async () => {
|
|
65
|
+
// eslint-disable-next-line @typescript-eslint/only-throw-error
|
|
66
|
+
throw "plain string error";
|
|
67
|
+
});
|
|
68
|
+
const result = await p();
|
|
69
|
+
expect(result).toBeUndefined();
|
|
70
|
+
expect(p.error()).toBeInstanceOf(Error);
|
|
71
|
+
expect(p.error()?.message).toBe("plain string error");
|
|
72
|
+
});
|
|
73
|
+
it("concurrency=1 guarantees serial execution", async () => {
|
|
74
|
+
const order = [];
|
|
75
|
+
let resolveFirst;
|
|
76
|
+
const p = pool(1, async (n) => {
|
|
77
|
+
if (n === 0)
|
|
78
|
+
await new Promise((r) => { resolveFirst = r; });
|
|
79
|
+
order.push(n);
|
|
80
|
+
});
|
|
81
|
+
const t1 = p(0);
|
|
82
|
+
const t2 = p(1);
|
|
83
|
+
// t2 cannot start until t1 finishes
|
|
84
|
+
expect(p.active()).toBe(1);
|
|
85
|
+
expect(p.pending()).toBe(1);
|
|
86
|
+
resolveFirst();
|
|
87
|
+
await t1;
|
|
88
|
+
await t2;
|
|
89
|
+
expect(order).toEqual([0, 1]); // serial order preserved
|
|
90
|
+
});
|
|
91
|
+
it("error in one task does not block subsequent tasks", async () => {
|
|
92
|
+
const results = [];
|
|
93
|
+
const p = pool(1, async (n) => {
|
|
94
|
+
if (n === 0)
|
|
95
|
+
throw new Error("task 0 failed");
|
|
96
|
+
return n;
|
|
97
|
+
});
|
|
98
|
+
const r0 = p(0);
|
|
99
|
+
const r1 = p(1);
|
|
100
|
+
results.push(await r0);
|
|
101
|
+
results.push(await r1);
|
|
102
|
+
expect(results[0]).toBeUndefined(); // error → undefined
|
|
103
|
+
expect(results[1]).toBe(1); // subsequent task ran
|
|
104
|
+
});
|
|
105
|
+
it("concurrency=0 — tasks are enqueued but never executed", async () => {
|
|
106
|
+
const fn = vi.fn(async () => "result");
|
|
107
|
+
const p = pool(0, fn);
|
|
108
|
+
// Queue a task — tryRun() bails immediately because _active(0) >= concurrency(0)
|
|
109
|
+
void p();
|
|
110
|
+
await new Promise((r) => setTimeout(r, 0));
|
|
111
|
+
expect(fn).not.toHaveBeenCalled();
|
|
112
|
+
expect(p.pending()).toBe(1);
|
|
113
|
+
expect(p.loading()).toBe(false);
|
|
114
|
+
});
|
|
115
|
+
it("active() never exceeds concurrency", async () => {
|
|
116
|
+
const concurrency = 2;
|
|
117
|
+
let maxObservedActive = 0;
|
|
118
|
+
const p = pool(concurrency, async () => {
|
|
119
|
+
maxObservedActive = Math.max(maxObservedActive, p.active());
|
|
120
|
+
await new Promise((r) => setTimeout(r, 5));
|
|
121
|
+
});
|
|
122
|
+
await Promise.all([p(), p(), p(), p()]);
|
|
123
|
+
expect(maxObservedActive).toBeLessThanOrEqual(concurrency);
|
|
124
|
+
});
|
|
63
125
|
});
|
|
64
126
|
//# sourceMappingURL=pool.test.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pool.test.js","sourceRoot":"","sources":["../../src/__tests__/pool.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;
|
|
1
|
+
{"version":3,"file":"pool.test.js","sourceRoot":"","sources":["../../src/__tests__/pool.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -45,6 +45,28 @@ describe("queue", () => {
|
|
|
45
45
|
await expect(q()).rejects.toThrow("boom");
|
|
46
46
|
expect(q.error()?.message).toBe("boom");
|
|
47
47
|
});
|
|
48
|
+
it("wraps non-Error throws in an Error", async () => {
|
|
49
|
+
const q = queue(async () => {
|
|
50
|
+
// eslint-disable-next-line @typescript-eslint/no-throw-literal
|
|
51
|
+
throw "string error";
|
|
52
|
+
});
|
|
53
|
+
await expect(q()).rejects.toThrow("string error");
|
|
54
|
+
expect(q.error()?.message).toBe("string error");
|
|
55
|
+
});
|
|
56
|
+
it("error in one task does not prevent subsequent tasks from running", async () => {
|
|
57
|
+
const q = queue(async (n) => {
|
|
58
|
+
if (n === 0)
|
|
59
|
+
throw new Error("task 0 failed");
|
|
60
|
+
return n;
|
|
61
|
+
});
|
|
62
|
+
const p0 = q(0); // will reject
|
|
63
|
+
const p1 = q(1); // should still run despite p0 failing
|
|
64
|
+
const p2 = q(2);
|
|
65
|
+
await expect(p0).rejects.toThrow("task 0 failed");
|
|
66
|
+
expect(await p1).toBe(1);
|
|
67
|
+
expect(await p2).toBe(2);
|
|
68
|
+
expect(q.error()?.message).toBe("task 0 failed");
|
|
69
|
+
});
|
|
48
70
|
it("clear() empties the pending queue", async () => {
|
|
49
71
|
let resolveFirst;
|
|
50
72
|
const q = queue((_, idx) => idx === 0
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"queue.test.js","sourceRoot":"","sources":["../../src/__tests__/queue.test.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"queue.test.js","sourceRoot":"","sources":["../../src/__tests__/queue.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -51,5 +51,63 @@ describe("task", () => {
|
|
|
51
51
|
expect(result).toBeUndefined();
|
|
52
52
|
expect(t.loading()).toBe(false);
|
|
53
53
|
});
|
|
54
|
+
it("cancelAll() during a failing task discards the error", async () => {
|
|
55
|
+
let reject;
|
|
56
|
+
const t = task(() => new Promise((_res, rej) => { reject = rej; }));
|
|
57
|
+
const p = t();
|
|
58
|
+
t.cancelAll();
|
|
59
|
+
reject(new Error("cancelled"));
|
|
60
|
+
const result = await p;
|
|
61
|
+
// The error was from a stale run — result is undefined, no error stored
|
|
62
|
+
expect(result).toBeUndefined();
|
|
63
|
+
expect(t.error()).toBeNull();
|
|
64
|
+
});
|
|
65
|
+
it("wraps non-Error throws in an Error object", async () => {
|
|
66
|
+
const t = task(async () => {
|
|
67
|
+
// eslint-disable-next-line @typescript-eslint/only-throw-error
|
|
68
|
+
throw "string-error";
|
|
69
|
+
});
|
|
70
|
+
const result = await t();
|
|
71
|
+
expect(result).toBeUndefined();
|
|
72
|
+
expect(t.error()).toBeInstanceOf(Error);
|
|
73
|
+
expect(t.error()?.message).toBe("string-error");
|
|
74
|
+
});
|
|
75
|
+
it("second run while first is pending discards the first result", async () => {
|
|
76
|
+
let resolveFirst;
|
|
77
|
+
let resolveSecond;
|
|
78
|
+
const t = task((_run) => (_run === 1
|
|
79
|
+
? new Promise((r) => { resolveFirst = r; })
|
|
80
|
+
: new Promise((r) => { resolveSecond = r; })));
|
|
81
|
+
let run = 1;
|
|
82
|
+
const p1 = t(run++); // run 1
|
|
83
|
+
const p2 = t(run++); // run 2 — increments _runId, making run 1 stale
|
|
84
|
+
resolveSecond("result-2");
|
|
85
|
+
resolveFirst("result-1"); // stale
|
|
86
|
+
const [r1, r2] = await Promise.all([p1, p2]);
|
|
87
|
+
expect(r2).toBe("result-2");
|
|
88
|
+
expect(r1).toBeUndefined(); // stale run discarded
|
|
89
|
+
expect(t.lastResult()).toBe("result-2");
|
|
90
|
+
});
|
|
91
|
+
it("synchronous function (non-async) resolves correctly via await", async () => {
|
|
92
|
+
// await on a non-Promise simply resolves the value
|
|
93
|
+
const t = task((() => 42));
|
|
94
|
+
const result = await t();
|
|
95
|
+
expect(result).toBe(42);
|
|
96
|
+
expect(t.lastResult()).toBe(42);
|
|
97
|
+
expect(t.loading()).toBe(false);
|
|
98
|
+
});
|
|
99
|
+
it("cancelAll() followed by a new run works correctly", async () => {
|
|
100
|
+
const t = task(async () => "fresh");
|
|
101
|
+
let resolve;
|
|
102
|
+
const staleTask = task(() => new Promise((r) => { resolve = r; }));
|
|
103
|
+
const p = staleTask();
|
|
104
|
+
staleTask.cancelAll();
|
|
105
|
+
resolve("stale");
|
|
106
|
+
await p;
|
|
107
|
+
// Now run a fresh task after cancelAll
|
|
108
|
+
const result = await t();
|
|
109
|
+
expect(result).toBe("fresh");
|
|
110
|
+
expect(t.loading()).toBe(false);
|
|
111
|
+
});
|
|
54
112
|
});
|
|
55
113
|
//# sourceMappingURL=task.test.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"task.test.js","sourceRoot":"","sources":["../../src/__tests__/task.test.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"task.test.js","sourceRoot":"","sources":["../../src/__tests__/task.test.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@praxisjs/concurrent",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.3",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"types": "./dist/index.d.ts",
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
"typescript": "^5.9.3"
|
|
15
15
|
},
|
|
16
16
|
"dependencies": {
|
|
17
|
-
"@praxisjs/core": "0.4.
|
|
17
|
+
"@praxisjs/core": "0.4.2",
|
|
18
18
|
"@praxisjs/shared": "0.2.0"
|
|
19
19
|
},
|
|
20
20
|
"scripts": {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { describe, it, expect } from "vitest";
|
|
1
|
+
import { describe, it, expect, vi } from "vitest";
|
|
2
2
|
|
|
3
3
|
import { pool } from "../pool";
|
|
4
4
|
|
|
@@ -77,4 +77,81 @@ describe("pool", () => {
|
|
|
77
77
|
await t2;
|
|
78
78
|
expect(p.pending()).toBe(0);
|
|
79
79
|
});
|
|
80
|
+
|
|
81
|
+
it("wraps non-Error throws in an Error object", async () => {
|
|
82
|
+
const p = pool(1, async () => {
|
|
83
|
+
// eslint-disable-next-line @typescript-eslint/only-throw-error
|
|
84
|
+
throw "plain string error";
|
|
85
|
+
});
|
|
86
|
+
const result = await p();
|
|
87
|
+
expect(result).toBeUndefined();
|
|
88
|
+
expect(p.error()).toBeInstanceOf(Error);
|
|
89
|
+
expect(p.error()?.message).toBe("plain string error");
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
it("concurrency=1 guarantees serial execution", async () => {
|
|
93
|
+
const order: number[] = [];
|
|
94
|
+
let resolveFirst!: () => void;
|
|
95
|
+
|
|
96
|
+
const p = pool(1, async (n: unknown) => {
|
|
97
|
+
if (n === 0) await new Promise<void>((r) => { resolveFirst = r; });
|
|
98
|
+
order.push(n as number);
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
const t1 = p(0);
|
|
102
|
+
const t2 = p(1);
|
|
103
|
+
|
|
104
|
+
// t2 cannot start until t1 finishes
|
|
105
|
+
expect(p.active()).toBe(1);
|
|
106
|
+
expect(p.pending()).toBe(1);
|
|
107
|
+
|
|
108
|
+
resolveFirst();
|
|
109
|
+
await t1;
|
|
110
|
+
await t2;
|
|
111
|
+
|
|
112
|
+
expect(order).toEqual([0, 1]); // serial order preserved
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
it("error in one task does not block subsequent tasks", async () => {
|
|
116
|
+
const results: Array<number | undefined> = [];
|
|
117
|
+
const p = pool(1, async (n: unknown) => {
|
|
118
|
+
if (n === 0) throw new Error("task 0 failed");
|
|
119
|
+
return n as number;
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
const r0 = p(0);
|
|
123
|
+
const r1 = p(1);
|
|
124
|
+
|
|
125
|
+
results.push(await r0);
|
|
126
|
+
results.push(await r1);
|
|
127
|
+
|
|
128
|
+
expect(results[0]).toBeUndefined(); // error → undefined
|
|
129
|
+
expect(results[1]).toBe(1); // subsequent task ran
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
it("concurrency=0 — tasks are enqueued but never executed", async () => {
|
|
133
|
+
const fn = vi.fn(async () => "result");
|
|
134
|
+
const p = pool(0, fn);
|
|
135
|
+
|
|
136
|
+
// Queue a task — tryRun() bails immediately because _active(0) >= concurrency(0)
|
|
137
|
+
void p();
|
|
138
|
+
await new Promise((r) => setTimeout(r, 0));
|
|
139
|
+
|
|
140
|
+
expect(fn).not.toHaveBeenCalled();
|
|
141
|
+
expect(p.pending()).toBe(1);
|
|
142
|
+
expect(p.loading()).toBe(false);
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
it("active() never exceeds concurrency", async () => {
|
|
146
|
+
const concurrency = 2;
|
|
147
|
+
let maxObservedActive = 0;
|
|
148
|
+
|
|
149
|
+
const p = pool(concurrency, async () => {
|
|
150
|
+
maxObservedActive = Math.max(maxObservedActive, p.active());
|
|
151
|
+
await new Promise((r) => setTimeout(r, 5));
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
await Promise.all([p(), p(), p(), p()]);
|
|
155
|
+
expect(maxObservedActive).toBeLessThanOrEqual(concurrency);
|
|
156
|
+
});
|
|
80
157
|
});
|
|
@@ -61,6 +61,31 @@ describe("queue", () => {
|
|
|
61
61
|
expect(q.error()?.message).toBe("boom");
|
|
62
62
|
});
|
|
63
63
|
|
|
64
|
+
it("wraps non-Error throws in an Error", async () => {
|
|
65
|
+
const q = queue(async () => {
|
|
66
|
+
// eslint-disable-next-line @typescript-eslint/no-throw-literal
|
|
67
|
+
throw "string error";
|
|
68
|
+
});
|
|
69
|
+
await expect(q()).rejects.toThrow("string error");
|
|
70
|
+
expect(q.error()?.message).toBe("string error");
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
it("error in one task does not prevent subsequent tasks from running", async () => {
|
|
74
|
+
const q = queue(async (n: unknown) => {
|
|
75
|
+
if (n === 0) throw new Error("task 0 failed");
|
|
76
|
+
return n as number;
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
const p0 = q(0); // will reject
|
|
80
|
+
const p1 = q(1); // should still run despite p0 failing
|
|
81
|
+
const p2 = q(2);
|
|
82
|
+
|
|
83
|
+
await expect(p0).rejects.toThrow("task 0 failed");
|
|
84
|
+
expect(await p1).toBe(1);
|
|
85
|
+
expect(await p2).toBe(2);
|
|
86
|
+
expect(q.error()?.message).toBe("task 0 failed");
|
|
87
|
+
});
|
|
88
|
+
|
|
64
89
|
it("clear() empties the pending queue", async () => {
|
|
65
90
|
let resolveFirst!: () => void;
|
|
66
91
|
const q = queue(
|
|
@@ -61,4 +61,77 @@ describe("task", () => {
|
|
|
61
61
|
expect(result).toBeUndefined();
|
|
62
62
|
expect(t.loading()).toBe(false);
|
|
63
63
|
});
|
|
64
|
+
|
|
65
|
+
it("cancelAll() during a failing task discards the error", async () => {
|
|
66
|
+
let reject!: (err: unknown) => void;
|
|
67
|
+
const t = task(() => new Promise<string>((_res, rej) => { reject = rej; }));
|
|
68
|
+
|
|
69
|
+
const p = t();
|
|
70
|
+
t.cancelAll();
|
|
71
|
+
reject(new Error("cancelled"));
|
|
72
|
+
const result = await p;
|
|
73
|
+
|
|
74
|
+
// The error was from a stale run — result is undefined, no error stored
|
|
75
|
+
expect(result).toBeUndefined();
|
|
76
|
+
expect(t.error()).toBeNull();
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
it("wraps non-Error throws in an Error object", async () => {
|
|
80
|
+
const t = task(async () => {
|
|
81
|
+
// eslint-disable-next-line @typescript-eslint/only-throw-error
|
|
82
|
+
throw "string-error";
|
|
83
|
+
});
|
|
84
|
+
const result = await t();
|
|
85
|
+
expect(result).toBeUndefined();
|
|
86
|
+
expect(t.error()).toBeInstanceOf(Error);
|
|
87
|
+
expect(t.error()?.message).toBe("string-error");
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
it("second run while first is pending discards the first result", async () => {
|
|
91
|
+
let resolveFirst!: (v: string) => void;
|
|
92
|
+
let resolveSecond!: (v: string) => void;
|
|
93
|
+
|
|
94
|
+
const t = task((_run: unknown) =>
|
|
95
|
+
(_run === 1
|
|
96
|
+
? new Promise<string>((r) => { resolveFirst = r; })
|
|
97
|
+
: new Promise<string>((r) => { resolveSecond = r; })),
|
|
98
|
+
);
|
|
99
|
+
|
|
100
|
+
let run = 1;
|
|
101
|
+
const p1 = t(run++); // run 1
|
|
102
|
+
const p2 = t(run++); // run 2 — increments _runId, making run 1 stale
|
|
103
|
+
|
|
104
|
+
resolveSecond("result-2");
|
|
105
|
+
resolveFirst("result-1"); // stale
|
|
106
|
+
|
|
107
|
+
const [r1, r2] = await Promise.all([p1, p2]);
|
|
108
|
+
expect(r2).toBe("result-2");
|
|
109
|
+
expect(r1).toBeUndefined(); // stale run discarded
|
|
110
|
+
expect(t.lastResult()).toBe("result-2");
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
it("synchronous function (non-async) resolves correctly via await", async () => {
|
|
114
|
+
// await on a non-Promise simply resolves the value
|
|
115
|
+
const t = task((() => 42) as unknown as () => Promise<number>);
|
|
116
|
+
const result = await t();
|
|
117
|
+
expect(result).toBe(42);
|
|
118
|
+
expect(t.lastResult()).toBe(42);
|
|
119
|
+
expect(t.loading()).toBe(false);
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
it("cancelAll() followed by a new run works correctly", async () => {
|
|
123
|
+
const t = task(async () => "fresh");
|
|
124
|
+
let resolve!: (v: string) => void;
|
|
125
|
+
const staleTask = task(() => new Promise<string>((r) => { resolve = r; }));
|
|
126
|
+
|
|
127
|
+
const p = staleTask();
|
|
128
|
+
staleTask.cancelAll();
|
|
129
|
+
resolve("stale");
|
|
130
|
+
await p;
|
|
131
|
+
|
|
132
|
+
// Now run a fresh task after cancelAll
|
|
133
|
+
const result = await t();
|
|
134
|
+
expect(result).toBe("fresh");
|
|
135
|
+
expect(t.loading()).toBe(false);
|
|
136
|
+
});
|
|
64
137
|
});
|