@zukhruf/pool 0.0.0-stage → 0.3.43
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/LICENSE +21 -0
- package/README.md +45 -2
- package/dist/capacity.d.ts +2 -0
- package/dist/capacity.d.ts.map +1 -0
- package/dist/capacity.js +7 -0
- package/dist/capacity.js.map +1 -0
- package/dist/climbing.d.ts +19 -0
- package/dist/climbing.d.ts.map +1 -0
- package/dist/climbing.js +77 -0
- package/dist/climbing.js.map +1 -0
- package/dist/fixed.d.ts +9 -0
- package/dist/fixed.d.ts.map +1 -0
- package/dist/fixed.js +14 -0
- package/dist/fixed.js.map +1 -0
- package/dist/gradient.d.ts +7 -0
- package/dist/gradient.d.ts.map +1 -0
- package/dist/gradient.js +18 -0
- package/dist/gradient.js.map +1 -0
- package/dist/hill-climbing.d.ts +6 -0
- package/dist/hill-climbing.d.ts.map +1 -0
- package/dist/hill-climbing.js +13 -0
- package/dist/hill-climbing.js.map +1 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +10 -0
- package/dist/index.js.map +1 -0
- package/dist/leader-first.d.ts +7 -0
- package/dist/leader-first.d.ts.map +1 -0
- package/dist/leader-first.js +19 -0
- package/dist/leader-first.js.map +1 -0
- package/dist/on-demand.d.ts +6 -0
- package/dist/on-demand.d.ts.map +1 -0
- package/dist/on-demand.js +9 -0
- package/dist/on-demand.js.map +1 -0
- package/dist/ordered-ready.d.ts +7 -0
- package/dist/ordered-ready.d.ts.map +1 -0
- package/dist/ordered-ready.js +17 -0
- package/dist/ordered-ready.js.map +1 -0
- package/dist/parallel.d.ts +6 -0
- package/dist/parallel.d.ts.map +1 -0
- package/dist/parallel.js +8 -0
- package/dist/parallel.js.map +1 -0
- package/dist/pool.d.ts +15 -0
- package/dist/pool.d.ts.map +1 -0
- package/dist/pool.js +217 -0
- package/dist/pool.js.map +1 -0
- package/dist/resources.d.ts +11 -0
- package/dist/resources.d.ts.map +1 -0
- package/dist/resources.js +15 -0
- package/dist/resources.js.map +1 -0
- package/dist/sizing.d.ts +12 -0
- package/dist/sizing.d.ts.map +1 -0
- package/dist/sizing.js +2 -0
- package/dist/sizing.js.map +1 -0
- package/dist/startup.d.ts +5 -0
- package/dist/startup.d.ts.map +1 -0
- package/dist/startup.js +2 -0
- package/dist/startup.js.map +1 -0
- package/dist/worker.d.ts +7 -0
- package/dist/worker.d.ts.map +1 -0
- package/dist/worker.js +2 -0
- package/dist/worker.js.map +1 -0
- package/package.json +45 -4
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 ezzabuzaid
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,46 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @zukhruf/pool
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Lends long-lived workers to jobs, one job for each worker at a time. A worker is costly to start: a native helper that loads a model, or a command-line agent that keeps a session. The pool starts workers, lends them, replaces a worker that exits, and stops all of them when you dispose it. You choose two things from standard classes: when the workers start (a startup) and how many run (a sizing).
|
|
4
|
+
|
|
5
|
+
The words in these documents have one meaning each. See the glossary in [CONTEXT.md](./CONTEXT.md).
|
|
6
|
+
|
|
7
|
+
## Lend a worker to a job
|
|
8
|
+
|
|
9
|
+
```ts
|
|
10
|
+
import { Fixed, Parallel, Pool } from '@zukhruf/pool';
|
|
11
|
+
|
|
12
|
+
await using pool = new Pool({
|
|
13
|
+
size: new Fixed(2),
|
|
14
|
+
startup: new Parallel(),
|
|
15
|
+
create: () => new VisionWorker('/path/to/vision-worker'),
|
|
16
|
+
});
|
|
17
|
+
const text = await pool.use((worker) => worker.read('/tmp/receipt.png'));
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
A worker gives `exited()`, `kill()`, `close()`, and optionally `ready()`. A `Coprocess` of `@zukhruf/coprocess` has all of them. When a signal aborts a job that runs, the pool kills its worker. When a signal aborts a job whose worker still warms up, the warm-up continues for the next job.
|
|
21
|
+
|
|
22
|
+
## Choose when the workers start
|
|
23
|
+
|
|
24
|
+
| Startup | Starts |
|
|
25
|
+
| -------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
26
|
+
| `OnDemand` | a worker only when a job needs one |
|
|
27
|
+
| `Parallel` | every worker when you build the pool, all together |
|
|
28
|
+
| `OrderedReady` | every worker when you build the pool, one after the other, as Kubernetes starts an `OrderedReady` StatefulSet |
|
|
29
|
+
| `LeaderFirst` | the first worker alone, and the others together when it is ready. Use it when the first worker fills a cache that the others read, such as compiled models |
|
|
30
|
+
|
|
31
|
+
## Choose how many workers run
|
|
32
|
+
|
|
33
|
+
| Sizing | Runs |
|
|
34
|
+
| ----------------------------------- | ---------------------------------------------------------------------------------------------------------------------- |
|
|
35
|
+
| `Fixed(n)` | n workers |
|
|
36
|
+
| `Resources({ memoryPerWorker })` | one for each CPU, while each finds its memory free |
|
|
37
|
+
| `HillClimbing({ memoryPerWorker })` | two first, and one more while the last one added at least a tenth more jobs a second (as the .NET thread pool) |
|
|
38
|
+
| `Gradient({ memoryPerWorker })` | two first, and one more while a job takes at most half again the time it took with two (as Netflix concurrency-limits) |
|
|
39
|
+
|
|
40
|
+
The two sizings that learn measure only while jobs wait and every worker is ready, in windows of at least 20 jobs and 2 seconds. They learn once, and never pass what the computer can give. See [ADR 0002](./docs/adr/0002-a-sizing-that-learns-compares-one-more-worker-between-two-windows.md).
|
|
41
|
+
|
|
42
|
+
## Decisions
|
|
43
|
+
|
|
44
|
+
- [ADR 0001](./docs/adr/0001-startups-and-sizings-are-classes-that-a-caller-chooses.md): startups and sizings are classes that a caller chooses.
|
|
45
|
+
- [ADR 0002](./docs/adr/0002-a-sizing-that-learns-compares-one-more-worker-between-two-windows.md): a sizing that learns compares one more worker between two windows.
|
|
46
|
+
- [ADR 0003](./docs/adr/0003-the-pool-learns-that-a-worker-ended-from-its-exit.md): the pool learns that a worker ended from its exit.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"capacity.d.ts","sourceRoot":"","sources":["../src/capacity.ts"],"names":[],"mappings":"AAIA,wBAAgB,QAAQ,CAAC,eAAe,EAAE,MAAM,GAAG,MAAM,CAQxD"}
|
package/dist/capacity.js
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { availableParallelism } from 'node:os';
|
|
2
|
+
// The workers this Mac affords: one per CPU, as long as each still finds its
|
|
3
|
+
// memory free.
|
|
4
|
+
export function capacity(memoryPerWorker) {
|
|
5
|
+
return Math.max(1, Math.min(availableParallelism(), Math.floor(process.availableMemory() / memoryPerWorker)));
|
|
6
|
+
}
|
|
7
|
+
//# sourceMappingURL=capacity.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"capacity.js","sourceRoot":"","sources":["../src/capacity.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,MAAM,SAAS,CAAC;AAE/C,6EAA6E;AAC7E,eAAe;AACf,MAAM,UAAU,QAAQ,CAAC,eAAuB;IAC9C,OAAO,IAAI,CAAC,GAAG,CACb,CAAC,EACD,IAAI,CAAC,GAAG,CACN,oBAAoB,EAAE,EACtB,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,eAAe,EAAE,GAAG,eAAe,CAAC,CACxD,CACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { Sample, Sizing } from './sizing.ts';
|
|
2
|
+
export interface Window {
|
|
3
|
+
readonly jobs: number;
|
|
4
|
+
readonly span: number;
|
|
5
|
+
readonly busy: number;
|
|
6
|
+
}
|
|
7
|
+
export declare abstract class Climbing implements Sizing {
|
|
8
|
+
#private;
|
|
9
|
+
readonly ceiling: number;
|
|
10
|
+
constructor(options: {
|
|
11
|
+
memoryPerWorker: number;
|
|
12
|
+
});
|
|
13
|
+
get current(): number;
|
|
14
|
+
get kept(): number;
|
|
15
|
+
record({ started, finished, measurable }: Sample): void;
|
|
16
|
+
protected abstract measure(window: Window): number;
|
|
17
|
+
protected abstract pays(ratio: number): boolean;
|
|
18
|
+
}
|
|
19
|
+
//# sourceMappingURL=climbing.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"climbing.d.ts","sourceRoot":"","sources":["../src/climbing.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAQlD,MAAM,WAAW,MAAM;IACrB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAEtB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAEtB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB;AAUD,8BAAsB,QAAS,YAAW,MAAM;;IAC9C,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;gBASb,OAAO,EAAE;QAAE,eAAe,EAAE,MAAM,CAAA;KAAE;IAMhD,IAAI,OAAO,IAAI,MAAM,CAEpB;IAID,IAAI,IAAI,IAAI,MAAM,CAIjB;IAED,MAAM,CAAC,EAAE,OAAO,EAAE,QAAQ,EAAE,UAAU,EAAE,EAAE,MAAM,GAAG,IAAI;IAkCvD,SAAS,CAAC,QAAQ,CAAC,OAAO,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM;IAIlD,SAAS,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO;CAChD"}
|
package/dist/climbing.js
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { capacity } from "./capacity.js";
|
|
2
|
+
// A window of jobs ends after both, so the sizes of the files it held do not
|
|
3
|
+
// decide alone.
|
|
4
|
+
const jobs = 20;
|
|
5
|
+
const span = 2_000;
|
|
6
|
+
// Finds how many workers pay by trying one more. Work that changes while it
|
|
7
|
+
// is measured, as when files arrive grouped by kind, would decide a plain
|
|
8
|
+
// before and after, so each step measures in the order A, B, A: a window at
|
|
9
|
+
// the size that pays so far, one at a size larger, and one back at the first
|
|
10
|
+
// size. The larger size pays when its window compared to the mean of both
|
|
11
|
+
// first windows passes the variant's test. Pools start with two workers,
|
|
12
|
+
// learn once, and never pass the Mac's capacity. Variants say what a window
|
|
13
|
+
// measures and what passes.
|
|
14
|
+
export class Climbing {
|
|
15
|
+
ceiling;
|
|
16
|
+
#size;
|
|
17
|
+
#step;
|
|
18
|
+
#before = 0;
|
|
19
|
+
#more = 0;
|
|
20
|
+
#first = 0;
|
|
21
|
+
#count = 0;
|
|
22
|
+
#busy = 0;
|
|
23
|
+
constructor(options) {
|
|
24
|
+
this.ceiling = capacity(options.memoryPerWorker);
|
|
25
|
+
this.#size = Math.min(2, this.ceiling);
|
|
26
|
+
this.#step = this.#size < this.ceiling ? 'before' : 'settled';
|
|
27
|
+
}
|
|
28
|
+
get current() {
|
|
29
|
+
return this.#step === 'more' ? this.#size + 1 : this.#size;
|
|
30
|
+
}
|
|
31
|
+
// The worker the step tries stays alive while the step measures the size
|
|
32
|
+
// before it again.
|
|
33
|
+
get kept() {
|
|
34
|
+
return this.#step === 'more' || this.#step === 'after'
|
|
35
|
+
? this.#size + 1
|
|
36
|
+
: this.#size;
|
|
37
|
+
}
|
|
38
|
+
record({ started, finished, measurable }) {
|
|
39
|
+
if (this.#step === 'settled')
|
|
40
|
+
return;
|
|
41
|
+
if (!measurable) {
|
|
42
|
+
this.#restart();
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
if (this.#count === 0)
|
|
46
|
+
this.#first = finished;
|
|
47
|
+
this.#count++;
|
|
48
|
+
this.#busy += finished - started;
|
|
49
|
+
if (this.#count < jobs || finished - this.#first < span)
|
|
50
|
+
return;
|
|
51
|
+
const value = this.measure({
|
|
52
|
+
jobs: this.#count,
|
|
53
|
+
span: finished - this.#first,
|
|
54
|
+
busy: this.#busy,
|
|
55
|
+
});
|
|
56
|
+
this.#restart();
|
|
57
|
+
if (this.#step === 'before') {
|
|
58
|
+
this.#before = value;
|
|
59
|
+
this.#step = 'more';
|
|
60
|
+
}
|
|
61
|
+
else if (this.#step === 'more') {
|
|
62
|
+
this.#more = value;
|
|
63
|
+
this.#step = 'after';
|
|
64
|
+
}
|
|
65
|
+
else if (this.pays(this.#more / ((this.#before + value) / 2))) {
|
|
66
|
+
this.#size++;
|
|
67
|
+
this.#step = this.#size < this.ceiling ? 'before' : 'settled';
|
|
68
|
+
}
|
|
69
|
+
else
|
|
70
|
+
this.#step = 'settled';
|
|
71
|
+
}
|
|
72
|
+
#restart() {
|
|
73
|
+
this.#count = 0;
|
|
74
|
+
this.#busy = 0;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
//# sourceMappingURL=climbing.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"climbing.js","sourceRoot":"","sources":["../src/climbing.ts"],"names":[],"mappings":"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"}
|
package/dist/fixed.d.ts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { Sizing } from './sizing.ts';
|
|
2
|
+
export declare class Fixed implements Sizing {
|
|
3
|
+
readonly ceiling: number;
|
|
4
|
+
readonly current: number;
|
|
5
|
+
readonly kept: number;
|
|
6
|
+
constructor(workers: number);
|
|
7
|
+
record(): void;
|
|
8
|
+
}
|
|
9
|
+
//# sourceMappingURL=fixed.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fixed.d.ts","sourceRoot":"","sources":["../src/fixed.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAI1C,qBAAa,KAAM,YAAW,MAAM;IAClC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;gBAEV,OAAO,EAAE,MAAM;IAM3B,MAAM,IAAI,IAAI;CACf"}
|
package/dist/fixed.js
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
// Runs exactly the given number of workers, as Kubernetes runs a fixed number
|
|
2
|
+
// of replicas.
|
|
3
|
+
export class Fixed {
|
|
4
|
+
ceiling;
|
|
5
|
+
current;
|
|
6
|
+
kept;
|
|
7
|
+
constructor(workers) {
|
|
8
|
+
this.ceiling = workers;
|
|
9
|
+
this.current = workers;
|
|
10
|
+
this.kept = workers;
|
|
11
|
+
}
|
|
12
|
+
record() { }
|
|
13
|
+
}
|
|
14
|
+
//# sourceMappingURL=fixed.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fixed.js","sourceRoot":"","sources":["../src/fixed.ts"],"names":[],"mappings":"AAEA,8EAA8E;AAC9E,eAAe;AACf,MAAM,OAAO,KAAK;IACP,OAAO,CAAS;IAChB,OAAO,CAAS;IAChB,IAAI,CAAS;IAEtB,YAAY,OAAe;QACzB,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;QACvB,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;QACvB,IAAI,CAAC,IAAI,GAAG,OAAO,CAAC;IACtB,CAAC;IAED,MAAM,KAAU,CAAC;CAClB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gradient.d.ts","sourceRoot":"","sources":["../src/gradient.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,KAAK,MAAM,EAAE,MAAM,eAAe,CAAC;AAMtD,qBAAa,QAAS,SAAQ,QAAQ;;IAGpC,SAAS,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE,MAAM,GAAG,MAAM;IAIjD,SAAS,CAAC,IAAI,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO;CAKvC"}
|
package/dist/gradient.js
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { Climbing } from "./climbing.js";
|
|
2
|
+
// Finds how many workers pay by the time a job takes, as Netflix's
|
|
3
|
+
// concurrency-limits Gradient does: one more worker pays while a job takes at
|
|
4
|
+
// most half again the time it took with two. Past that, the workers queue for
|
|
5
|
+
// something they share.
|
|
6
|
+
export class Gradient extends Climbing {
|
|
7
|
+
#slowdown = 1;
|
|
8
|
+
measure({ jobs, busy }) {
|
|
9
|
+
return busy / jobs;
|
|
10
|
+
}
|
|
11
|
+
pays(ratio) {
|
|
12
|
+
if (this.#slowdown * ratio > 1.5)
|
|
13
|
+
return false;
|
|
14
|
+
this.#slowdown *= ratio;
|
|
15
|
+
return true;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=gradient.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gradient.js","sourceRoot":"","sources":["../src/gradient.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAe,MAAM,eAAe,CAAC;AAEtD,mEAAmE;AACnE,8EAA8E;AAC9E,8EAA8E;AAC9E,wBAAwB;AACxB,MAAM,OAAO,QAAS,SAAQ,QAAQ;IACpC,SAAS,GAAG,CAAC,CAAC;IAEJ,OAAO,CAAC,EAAE,IAAI,EAAE,IAAI,EAAU;QACtC,OAAO,IAAI,GAAG,IAAI,CAAC;IACrB,CAAC;IAES,IAAI,CAAC,KAAa;QAC1B,IAAI,IAAI,CAAC,SAAS,GAAG,KAAK,GAAG,GAAG;YAAE,OAAO,KAAK,CAAC;QAC/C,IAAI,CAAC,SAAS,IAAI,KAAK,CAAC;QACxB,OAAO,IAAI,CAAC;IACd,CAAC;CACF"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hill-climbing.d.ts","sourceRoot":"","sources":["../src/hill-climbing.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,KAAK,MAAM,EAAE,MAAM,eAAe,CAAC;AAKtD,qBAAa,YAAa,SAAQ,QAAQ;IACxC,SAAS,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE,MAAM,GAAG,MAAM;IAIjD,SAAS,CAAC,IAAI,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO;CAGvC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { Climbing } from "./climbing.js";
|
|
2
|
+
// Finds how many workers pay by their throughput, as the .NET thread pool
|
|
3
|
+
// does (Hellerstein, Morrison and Eilebrecht, 2008): one more worker pays
|
|
4
|
+
// while it adds at least a tenth more jobs a second.
|
|
5
|
+
export class HillClimbing extends Climbing {
|
|
6
|
+
measure({ jobs, span }) {
|
|
7
|
+
return jobs / span;
|
|
8
|
+
}
|
|
9
|
+
pays(ratio) {
|
|
10
|
+
return ratio >= 1.1;
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
//# sourceMappingURL=hill-climbing.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hill-climbing.js","sourceRoot":"","sources":["../src/hill-climbing.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAe,MAAM,eAAe,CAAC;AAEtD,0EAA0E;AAC1E,0EAA0E;AAC1E,qDAAqD;AACrD,MAAM,OAAO,YAAa,SAAQ,QAAQ;IAC9B,OAAO,CAAC,EAAE,IAAI,EAAE,IAAI,EAAU;QACtC,OAAO,IAAI,GAAG,IAAI,CAAC;IACrB,CAAC;IAES,IAAI,CAAC,KAAa;QAC1B,OAAO,KAAK,IAAI,GAAG,CAAC;IACtB,CAAC;CACF"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export { Fixed } from './fixed.ts';
|
|
2
|
+
export { Gradient } from './gradient.ts';
|
|
3
|
+
export { HillClimbing } from './hill-climbing.ts';
|
|
4
|
+
export { LeaderFirst } from './leader-first.ts';
|
|
5
|
+
export { OnDemand } from './on-demand.ts';
|
|
6
|
+
export { OrderedReady } from './ordered-ready.ts';
|
|
7
|
+
export { Parallel } from './parallel.ts';
|
|
8
|
+
export { Pool } from './pool.ts';
|
|
9
|
+
export { Resources } from './resources.ts';
|
|
10
|
+
export type { Sample, Sizing } from './sizing.ts';
|
|
11
|
+
export type { Startup } from './startup.ts';
|
|
12
|
+
export type { Worker } from './worker.ts';
|
|
13
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAC1C,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3C,YAAY,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAClD,YAAY,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAC5C,YAAY,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export { Fixed } from "./fixed.js";
|
|
2
|
+
export { Gradient } from "./gradient.js";
|
|
3
|
+
export { HillClimbing } from "./hill-climbing.js";
|
|
4
|
+
export { LeaderFirst } from "./leader-first.js";
|
|
5
|
+
export { OnDemand } from "./on-demand.js";
|
|
6
|
+
export { OrderedReady } from "./ordered-ready.js";
|
|
7
|
+
export { Parallel } from "./parallel.js";
|
|
8
|
+
export { Pool } from "./pool.js";
|
|
9
|
+
export { Resources } from "./resources.js";
|
|
10
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAC1C,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"leader-first.d.ts","sourceRoot":"","sources":["../src/leader-first.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAM5C,qBAAa,WAAY,YAAW,OAAO;;IACzC,QAAQ,CAAC,KAAK,QAAQ;IAStB,IAAI,CAAC,OAAO,EAAE,OAAO,CAAC,IAAI,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;CAG5C"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { Latch } from '@zukhruf/async';
|
|
2
|
+
// Starts every worker when the pool is constructed. The first starts alone and
|
|
3
|
+
// the others start together once it settles, as when the first worker fills a
|
|
4
|
+
// cache that the others then read instead of rebuilding it. A replacement
|
|
5
|
+
// after a crash starts at once, since the first creation has settled.
|
|
6
|
+
export class LeaderFirst {
|
|
7
|
+
eager = true;
|
|
8
|
+
#leader = new Latch();
|
|
9
|
+
// The first creation leads; every later one waits for it.
|
|
10
|
+
#turn = (settled) => {
|
|
11
|
+
void settled.then(() => this.#leader.open());
|
|
12
|
+
this.#turn = () => this.#leader.wait();
|
|
13
|
+
return Promise.resolve();
|
|
14
|
+
};
|
|
15
|
+
turn(settled) {
|
|
16
|
+
return this.#turn(settled);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
//# sourceMappingURL=leader-first.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"leader-first.js","sourceRoot":"","sources":["../src/leader-first.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAC;AAIvC,+EAA+E;AAC/E,8EAA8E;AAC9E,0EAA0E;AAC1E,sEAAsE;AACtE,MAAM,OAAO,WAAW;IACb,KAAK,GAAG,IAAI,CAAC;IACb,OAAO,GAAG,IAAI,KAAK,EAAE,CAAC;IAC/B,0DAA0D;IAC1D,KAAK,GAAG,CAAC,OAAsB,EAAiB,EAAE;QAChD,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC;QAC7C,IAAI,CAAC,KAAK,GAAG,GAAG,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC;QACvC,OAAO,OAAO,CAAC,OAAO,EAAE,CAAC;IAC3B,CAAC,CAAC;IAEF,IAAI,CAAC,OAAsB;QACzB,OAAO,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IAC7B,CAAC;CACF"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"on-demand.d.ts","sourceRoot":"","sources":["../src/on-demand.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAI5C,qBAAa,QAAS,YAAW,OAAO;IACtC,QAAQ,CAAC,KAAK,SAAS;IAEvB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;CAGtB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"on-demand.js","sourceRoot":"","sources":["../src/on-demand.ts"],"names":[],"mappings":"AAEA,yEAAyE;AACzE,WAAW;AACX,MAAM,OAAO,QAAQ;IACV,KAAK,GAAG,KAAK,CAAC;IAEvB,IAAI;QACF,OAAO,OAAO,CAAC,OAAO,EAAE,CAAC;IAC3B,CAAC;CACF"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ordered-ready.d.ts","sourceRoot":"","sources":["../src/ordered-ready.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAK5C,qBAAa,YAAa,YAAW,OAAO;;IAC1C,QAAQ,CAAC,KAAK,QAAQ;IAGtB,IAAI,CAAC,OAAO,EAAE,OAAO,CAAC,IAAI,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;CAQ5C"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import PQueue from 'p-queue';
|
|
2
|
+
// Starts every worker when the pool is constructed, one at a time: each
|
|
3
|
+
// creation waits until the previous one settles, as Kubernetes starts the
|
|
4
|
+
// pods of an OrderedReady StatefulSet.
|
|
5
|
+
export class OrderedReady {
|
|
6
|
+
eager = true;
|
|
7
|
+
#queue = new PQueue({ concurrency: 1 });
|
|
8
|
+
turn(settled) {
|
|
9
|
+
const turn = Promise.withResolvers();
|
|
10
|
+
void this.#queue.add(() => {
|
|
11
|
+
turn.resolve();
|
|
12
|
+
return settled;
|
|
13
|
+
});
|
|
14
|
+
return turn.promise;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=ordered-ready.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ordered-ready.js","sourceRoot":"","sources":["../src/ordered-ready.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,SAAS,CAAC;AAI7B,wEAAwE;AACxE,0EAA0E;AAC1E,uCAAuC;AACvC,MAAM,OAAO,YAAY;IACd,KAAK,GAAG,IAAI,CAAC;IACb,MAAM,GAAG,IAAI,MAAM,CAAC,EAAE,WAAW,EAAE,CAAC,EAAE,CAAC,CAAC;IAEjD,IAAI,CAAC,OAAsB;QACzB,MAAM,IAAI,GAAG,OAAO,CAAC,aAAa,EAAQ,CAAC;QAC3C,KAAK,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,EAAE;YACxB,IAAI,CAAC,OAAO,EAAE,CAAC;YACf,OAAO,OAAO,CAAC;QACjB,CAAC,CAAC,CAAC;QACH,OAAO,IAAI,CAAC,OAAO,CAAC;IACtB,CAAC;CACF"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parallel.d.ts","sourceRoot":"","sources":["../src/parallel.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAG5C,qBAAa,QAAS,YAAW,OAAO;IACtC,QAAQ,CAAC,KAAK,QAAQ;IAEtB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;CAGtB"}
|
package/dist/parallel.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parallel.js","sourceRoot":"","sources":["../src/parallel.ts"],"names":[],"mappings":"AAEA,0EAA0E;AAC1E,MAAM,OAAO,QAAQ;IACV,KAAK,GAAG,IAAI,CAAC;IAEtB,IAAI;QACF,OAAO,OAAO,CAAC,OAAO,EAAE,CAAC;IAC3B,CAAC;CACF"}
|
package/dist/pool.d.ts
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { Sizing } from './sizing.ts';
|
|
2
|
+
import type { Startup } from './startup.ts';
|
|
3
|
+
import type { Worker } from './worker.ts';
|
|
4
|
+
export declare class Pool<T extends Worker> implements AsyncDisposable {
|
|
5
|
+
#private;
|
|
6
|
+
constructor(options: {
|
|
7
|
+
size: Sizing;
|
|
8
|
+
startup: Startup;
|
|
9
|
+
create: () => T;
|
|
10
|
+
});
|
|
11
|
+
ready(): Promise<void>;
|
|
12
|
+
use<R>(job: (worker: T) => Promise<R>, signal?: AbortSignal): Promise<R>;
|
|
13
|
+
[Symbol.asyncDispose](): Promise<void>;
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=pool.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pool.d.ts","sourceRoot":"","sources":["../src/pool.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAC5C,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAuB1C,qBAAa,IAAI,CAAC,CAAC,SAAS,MAAM,CAAE,YAAW,eAAe;;gBAahD,OAAO,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,OAAO,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC,CAAA;KAAE;IAoBlE,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAO5B,GAAG,CAAC,CAAC,EAAE,GAAG,EAAE,CAAC,MAAM,EAAE,CAAC,KAAK,OAAO,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,CAAC,CAAC;IAwKlE,CAAC,MAAM,CAAC,YAAY,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC;CAM7C"}
|
package/dist/pool.js
ADDED
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
import PQueue from 'p-queue';
|
|
2
|
+
import { Latch, untilAborted } from '@zukhruf/async';
|
|
3
|
+
// Lends workers to jobs, one job per worker at a time. The sizing decides how
|
|
4
|
+
// many workers run and the startup when they start. A worker that exits is
|
|
5
|
+
// replaced: at once when the startup is eager and the worker was idle,
|
|
6
|
+
// otherwise when a job next needs its slot. The owner disposes the pool,
|
|
7
|
+
// which stops every worker.
|
|
8
|
+
export class Pool {
|
|
9
|
+
#create;
|
|
10
|
+
#startup;
|
|
11
|
+
#sizing;
|
|
12
|
+
#queue;
|
|
13
|
+
#slots;
|
|
14
|
+
#lent = new Set();
|
|
15
|
+
#workers = new Set();
|
|
16
|
+
#stopped = new AbortController();
|
|
17
|
+
#started = new Latch();
|
|
18
|
+
// When the pool last changed how many workers it runs.
|
|
19
|
+
#resized = performance.now();
|
|
20
|
+
constructor(options) {
|
|
21
|
+
this.#create = options.create;
|
|
22
|
+
this.#startup = options.startup;
|
|
23
|
+
this.#sizing = options.size;
|
|
24
|
+
this.#queue = new PQueue({ concurrency: this.#sizing.current });
|
|
25
|
+
this.#slots = Array.from({ length: this.#sizing.ceiling }, (_, index) => ({
|
|
26
|
+
index,
|
|
27
|
+
state: { kind: 'empty' },
|
|
28
|
+
}));
|
|
29
|
+
const outcomes = options.startup.eager
|
|
30
|
+
? this.#running().map((slot) => this.#spawn(slot))
|
|
31
|
+
: [];
|
|
32
|
+
Promise.all(outcomes.map((outcome) => settled(outcome))).then(() => this.#started.open({ status: 'fulfilled', value: undefined }), (reason) => this.#started.open({ status: 'rejected', reason }));
|
|
33
|
+
}
|
|
34
|
+
// Settles when the workers the startup starts with the pool are ready, and
|
|
35
|
+
// rejects when one of them fails to start.
|
|
36
|
+
async ready() {
|
|
37
|
+
const outcome = await this.#started.wait();
|
|
38
|
+
if (outcome.status === 'rejected')
|
|
39
|
+
throw outcome.reason;
|
|
40
|
+
}
|
|
41
|
+
// A job aborted while it runs kills its worker. A job aborted while its
|
|
42
|
+
// worker warms up leaves the warm-up running for the jobs after it.
|
|
43
|
+
use(job, signal) {
|
|
44
|
+
const stop = signal === undefined
|
|
45
|
+
? this.#stopped.signal
|
|
46
|
+
: AbortSignal.any([this.#stopped.signal, signal]);
|
|
47
|
+
if (stop.aborted)
|
|
48
|
+
return Promise.reject(stop.reason);
|
|
49
|
+
// The queue does not take the signal: on abort it would free the slot
|
|
50
|
+
// while the job still holds its worker.
|
|
51
|
+
return this.#queue.add(async () => {
|
|
52
|
+
stop.throwIfAborted();
|
|
53
|
+
const slot = this.#running().find((free) => !this.#lent.has(free));
|
|
54
|
+
this.#lent.add(slot);
|
|
55
|
+
try {
|
|
56
|
+
const worker = await untilAborted(this.#borrow(slot), stop);
|
|
57
|
+
const kill = () => {
|
|
58
|
+
worker.kill();
|
|
59
|
+
this.#lose(slot, worker);
|
|
60
|
+
};
|
|
61
|
+
stop.addEventListener('abort', kill, { once: true });
|
|
62
|
+
const started = performance.now();
|
|
63
|
+
try {
|
|
64
|
+
const result = await job(worker);
|
|
65
|
+
stop.throwIfAborted();
|
|
66
|
+
return result;
|
|
67
|
+
}
|
|
68
|
+
catch (error) {
|
|
69
|
+
stop.throwIfAborted();
|
|
70
|
+
throw error;
|
|
71
|
+
}
|
|
72
|
+
finally {
|
|
73
|
+
stop.removeEventListener('abort', kill);
|
|
74
|
+
if (!stop.aborted)
|
|
75
|
+
this.#record(started);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
finally {
|
|
79
|
+
this.#lent.delete(slot);
|
|
80
|
+
if (slot.index >= this.#sizing.kept)
|
|
81
|
+
this.#retire(slot);
|
|
82
|
+
}
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
#running() {
|
|
86
|
+
return this.#slots.slice(0, this.#sizing.current);
|
|
87
|
+
}
|
|
88
|
+
async #borrow(slot) {
|
|
89
|
+
const state = slot.state;
|
|
90
|
+
if (state.kind === 'ready')
|
|
91
|
+
return state.worker;
|
|
92
|
+
if (state.kind === 'lost') {
|
|
93
|
+
slot.state = { kind: 'empty' };
|
|
94
|
+
void this.#close(state.worker);
|
|
95
|
+
}
|
|
96
|
+
const worker = await settled(state.kind === 'starting' ? state.outcome : this.#spawn(slot));
|
|
97
|
+
const now = slot.state;
|
|
98
|
+
if (now.kind === 'ready' && now.worker === worker)
|
|
99
|
+
return worker;
|
|
100
|
+
// The worker exited between its start and this borrow.
|
|
101
|
+
return this.#borrow(slot);
|
|
102
|
+
}
|
|
103
|
+
// A job measures how many workers pay only if, since it started, the pool
|
|
104
|
+
// ran the same number of workers and each was ready, and another job waited
|
|
105
|
+
// when it finished.
|
|
106
|
+
#record(started) {
|
|
107
|
+
const steady = this.#steady();
|
|
108
|
+
this.#sizing.record({
|
|
109
|
+
started,
|
|
110
|
+
finished: performance.now(),
|
|
111
|
+
measurable: steady !== undefined && started >= steady && this.#queue.size > 0,
|
|
112
|
+
});
|
|
113
|
+
for (const slot of this.#slots.slice(this.#sizing.kept))
|
|
114
|
+
this.#retire(slot);
|
|
115
|
+
if (this.#sizing.current === this.#queue.concurrency)
|
|
116
|
+
return;
|
|
117
|
+
this.#queue.concurrency = this.#sizing.current;
|
|
118
|
+
this.#resized = performance.now();
|
|
119
|
+
for (const slot of this.#running())
|
|
120
|
+
if (slot.state.kind === 'empty')
|
|
121
|
+
this.#spawn(slot);
|
|
122
|
+
}
|
|
123
|
+
// Since when every slot the pool runs has had a ready worker, if they have.
|
|
124
|
+
#steady() {
|
|
125
|
+
let since = this.#resized;
|
|
126
|
+
for (const { state } of this.#running()) {
|
|
127
|
+
if (state.kind !== 'ready')
|
|
128
|
+
return undefined;
|
|
129
|
+
since = Math.max(since, state.since);
|
|
130
|
+
}
|
|
131
|
+
return since;
|
|
132
|
+
}
|
|
133
|
+
#spawn(slot) {
|
|
134
|
+
const outcome = new Latch();
|
|
135
|
+
slot.state = { kind: 'starting', outcome };
|
|
136
|
+
const turn = Promise.withResolvers();
|
|
137
|
+
this.#startup
|
|
138
|
+
.turn(turn.promise)
|
|
139
|
+
.then(async () => {
|
|
140
|
+
this.#stopped.signal.throwIfAborted();
|
|
141
|
+
const worker = this.#create();
|
|
142
|
+
this.#workers.add(worker);
|
|
143
|
+
try {
|
|
144
|
+
await worker.ready?.();
|
|
145
|
+
return worker;
|
|
146
|
+
}
|
|
147
|
+
catch (error) {
|
|
148
|
+
worker.kill();
|
|
149
|
+
await this.#close(worker);
|
|
150
|
+
throw error;
|
|
151
|
+
}
|
|
152
|
+
})
|
|
153
|
+
.then((worker) => {
|
|
154
|
+
if (slot.state.kind === 'starting' && slot.state.outcome === outcome)
|
|
155
|
+
slot.state = { kind: 'ready', worker, since: performance.now() };
|
|
156
|
+
outcome.open({ status: 'fulfilled', value: worker });
|
|
157
|
+
turn.resolve();
|
|
158
|
+
void worker.exited().then(() => this.#ended(slot, worker));
|
|
159
|
+
}, (reason) => {
|
|
160
|
+
if (slot.state.kind === 'starting' && slot.state.outcome === outcome)
|
|
161
|
+
slot.state = { kind: 'empty' };
|
|
162
|
+
outcome.open({ status: 'rejected', reason });
|
|
163
|
+
turn.resolve();
|
|
164
|
+
});
|
|
165
|
+
return outcome;
|
|
166
|
+
}
|
|
167
|
+
// The pool killed the worker of a slot: no job may borrow it any more.
|
|
168
|
+
#lose(slot, worker) {
|
|
169
|
+
if (slot.state.kind === 'ready' && slot.state.worker === worker)
|
|
170
|
+
slot.state = { kind: 'lost', worker };
|
|
171
|
+
}
|
|
172
|
+
#ended(slot, worker) {
|
|
173
|
+
const state = slot.state;
|
|
174
|
+
if ((state.kind !== 'ready' && state.kind !== 'lost') ||
|
|
175
|
+
state.worker !== worker)
|
|
176
|
+
return;
|
|
177
|
+
slot.state = { kind: 'lost', worker };
|
|
178
|
+
if (this.#lent.has(slot) ||
|
|
179
|
+
this.#stopped.signal.aborted ||
|
|
180
|
+
!this.#startup.eager)
|
|
181
|
+
return;
|
|
182
|
+
slot.state = { kind: 'empty' };
|
|
183
|
+
void this.#close(worker);
|
|
184
|
+
if (slot.index < this.#sizing.current)
|
|
185
|
+
this.#spawn(slot);
|
|
186
|
+
}
|
|
187
|
+
// Closes the worker of a slot the pool no longer keeps, once its job ends.
|
|
188
|
+
#retire(slot) {
|
|
189
|
+
if (this.#lent.has(slot))
|
|
190
|
+
return;
|
|
191
|
+
const state = slot.state;
|
|
192
|
+
slot.state = { kind: 'empty' };
|
|
193
|
+
if (state.kind === 'ready' || state.kind === 'lost')
|
|
194
|
+
void this.#close(state.worker);
|
|
195
|
+
else if (state.kind === 'starting')
|
|
196
|
+
void settled(state.outcome).then((worker) => this.#close(worker), () => undefined);
|
|
197
|
+
}
|
|
198
|
+
async #close(worker) {
|
|
199
|
+
await worker.close();
|
|
200
|
+
this.#workers.delete(worker);
|
|
201
|
+
}
|
|
202
|
+
async [Symbol.asyncDispose]() {
|
|
203
|
+
this.#stopped.abort();
|
|
204
|
+
for (const worker of this.#workers)
|
|
205
|
+
worker.kill();
|
|
206
|
+
await Promise.all([...this.#workers].map((worker) => worker.close()));
|
|
207
|
+
await this.#queue.onIdle();
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
// The worker a creation gave, or its failure.
|
|
211
|
+
async function settled(outcome) {
|
|
212
|
+
const result = await outcome.wait();
|
|
213
|
+
if (result.status === 'rejected')
|
|
214
|
+
throw result.reason;
|
|
215
|
+
return result.value;
|
|
216
|
+
}
|
|
217
|
+
//# sourceMappingURL=pool.js.map
|
package/dist/pool.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pool.js","sourceRoot":"","sources":["../src/pool.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { Sizing } from './sizing.ts';
|
|
2
|
+
export declare class Resources implements Sizing {
|
|
3
|
+
readonly ceiling: number;
|
|
4
|
+
readonly current: number;
|
|
5
|
+
readonly kept: number;
|
|
6
|
+
constructor(options: {
|
|
7
|
+
memoryPerWorker: number;
|
|
8
|
+
});
|
|
9
|
+
record(): void;
|
|
10
|
+
}
|
|
11
|
+
//# sourceMappingURL=resources.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resources.d.ts","sourceRoot":"","sources":["../src/resources.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAI1C,qBAAa,SAAU,YAAW,MAAM;IACtC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;gBAEV,OAAO,EAAE;QAAE,eAAe,EAAE,MAAM,CAAA;KAAE;IAMhD,MAAM,IAAI,IAAI;CACf"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { capacity } from "./capacity.js";
|
|
2
|
+
// Runs as many workers as the Mac affords when the pool is built: one per
|
|
3
|
+
// CPU, while each finds memoryPerWorker free.
|
|
4
|
+
export class Resources {
|
|
5
|
+
ceiling;
|
|
6
|
+
current;
|
|
7
|
+
kept;
|
|
8
|
+
constructor(options) {
|
|
9
|
+
this.ceiling = capacity(options.memoryPerWorker);
|
|
10
|
+
this.current = this.ceiling;
|
|
11
|
+
this.kept = this.ceiling;
|
|
12
|
+
}
|
|
13
|
+
record() { }
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=resources.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resources.js","sourceRoot":"","sources":["../src/resources.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAGzC,0EAA0E;AAC1E,8CAA8C;AAC9C,MAAM,OAAO,SAAS;IACX,OAAO,CAAS;IAChB,OAAO,CAAS;IAChB,IAAI,CAAS;IAEtB,YAAY,OAAoC;QAC9C,IAAI,CAAC,OAAO,GAAG,QAAQ,CAAC,OAAO,CAAC,eAAe,CAAC,CAAC;QACjD,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC;QAC5B,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC;IAC3B,CAAC;IAED,MAAM,KAAU,CAAC;CAClB"}
|
package/dist/sizing.d.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export interface Sample {
|
|
2
|
+
readonly started: number;
|
|
3
|
+
readonly finished: number;
|
|
4
|
+
readonly measurable: boolean;
|
|
5
|
+
}
|
|
6
|
+
export interface Sizing {
|
|
7
|
+
readonly ceiling: number;
|
|
8
|
+
readonly current: number;
|
|
9
|
+
readonly kept: number;
|
|
10
|
+
record(sample: Sample): void;
|
|
11
|
+
}
|
|
12
|
+
//# sourceMappingURL=sizing.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sizing.d.ts","sourceRoot":"","sources":["../src/sizing.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,MAAM;IACrB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAC;CAC9B;AAQD,MAAM,WAAW,MAAM;IACrB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;CAC9B"}
|
package/dist/sizing.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sizing.js","sourceRoot":"","sources":["../src/sizing.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"startup.d.ts","sourceRoot":"","sources":["../src/startup.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,OAAO;IACtB,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;IAGxB,IAAI,CAAC,OAAO,EAAE,OAAO,CAAC,IAAI,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC7C"}
|
package/dist/startup.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"startup.js","sourceRoot":"","sources":["../src/startup.ts"],"names":[],"mappings":""}
|
package/dist/worker.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"worker.d.ts","sourceRoot":"","sources":["../src/worker.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,MAAM;IACrB,KAAK,CAAC,IAAI,OAAO,CAAC,OAAO,CAAC,CAAC;IAC3B,MAAM,IAAI,OAAO,CAAC,OAAO,CAAC,CAAC;IAC3B,IAAI,IAAI,IAAI,CAAC;IACb,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACxB"}
|
package/dist/worker.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"worker.js","sourceRoot":"","sources":["../src/worker.ts"],"names":[],"mappings":""}
|
package/package.json
CHANGED
|
@@ -1,6 +1,47 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zukhruf/pool",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
3
|
+
"version": "0.3.43",
|
|
4
|
+
"description": "Lend long-lived workers, such as native helper processes, to one job at a time: startups that decide when workers start, sizings that decide how many run, and replacement of a worker that exits.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "https://github.com/JanuaryLabs/zukhruf",
|
|
9
|
+
"directory": "packages/pool"
|
|
10
|
+
},
|
|
11
|
+
"bugs": {
|
|
12
|
+
"url": "https://github.com/JanuaryLabs/zukhruf/issues"
|
|
13
|
+
},
|
|
14
|
+
"homepage": "https://github.com/JanuaryLabs/zukhruf/tree/main/packages/pool#readme",
|
|
15
|
+
"keywords": [
|
|
16
|
+
"pool",
|
|
17
|
+
"worker-pool",
|
|
18
|
+
"resource-pool",
|
|
19
|
+
"concurrency",
|
|
20
|
+
"hill-climbing",
|
|
21
|
+
"capacity",
|
|
22
|
+
"child-process"
|
|
23
|
+
],
|
|
24
|
+
"type": "module",
|
|
25
|
+
"exports": {
|
|
26
|
+
"./package.json": "./package.json",
|
|
27
|
+
".": {
|
|
28
|
+
"@zukhruf/source": "./src/index.ts",
|
|
29
|
+
"types": "./dist/index.d.ts",
|
|
30
|
+
"import": "./dist/index.js",
|
|
31
|
+
"default": "./dist/index.js"
|
|
32
|
+
}
|
|
33
|
+
},
|
|
34
|
+
"files": [
|
|
35
|
+
"dist",
|
|
36
|
+
"!dist/spec/**",
|
|
37
|
+
"!**/*.tsbuildinfo",
|
|
38
|
+
"!**/*.test.*"
|
|
39
|
+
],
|
|
40
|
+
"publishConfig": {
|
|
41
|
+
"access": "public"
|
|
42
|
+
},
|
|
43
|
+
"dependencies": {
|
|
44
|
+
"@zukhruf/async": "^0.3.43",
|
|
45
|
+
"p-queue": "10.0.0"
|
|
46
|
+
}
|
|
47
|
+
}
|