tywrap 0.2.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +65 -31
- package/dist/cli.js +49 -2
- package/dist/cli.js.map +1 -1
- package/dist/config/index.d.ts +11 -7
- package/dist/config/index.d.ts.map +1 -1
- package/dist/config/index.js +43 -7
- package/dist/config/index.js.map +1 -1
- package/dist/core/analyzer.d.ts +1 -0
- package/dist/core/analyzer.d.ts.map +1 -1
- package/dist/core/analyzer.js +47 -12
- package/dist/core/analyzer.js.map +1 -1
- package/dist/core/annotation-parser.d.ts +8 -0
- package/dist/core/annotation-parser.d.ts.map +1 -0
- package/dist/core/annotation-parser.js +409 -0
- package/dist/core/annotation-parser.js.map +1 -0
- package/dist/core/discovery.d.ts +1 -0
- package/dist/core/discovery.d.ts.map +1 -1
- package/dist/core/discovery.js +9 -9
- package/dist/core/discovery.js.map +1 -1
- package/dist/core/generator.d.ts +9 -1
- package/dist/core/generator.d.ts.map +1 -1
- package/dist/core/generator.js +738 -104
- package/dist/core/generator.js.map +1 -1
- package/dist/core/mapper.d.ts +9 -7
- package/dist/core/mapper.d.ts.map +1 -1
- package/dist/core/mapper.js +129 -44
- package/dist/core/mapper.js.map +1 -1
- package/dist/index.d.ts +23 -7
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +23 -3
- package/dist/index.js.map +1 -1
- package/dist/runtime/base.d.ts +17 -7
- package/dist/runtime/base.d.ts.map +1 -1
- package/dist/runtime/base.js +18 -1
- package/dist/runtime/base.js.map +1 -1
- package/dist/runtime/bounded-context.d.ts +252 -0
- package/dist/runtime/bounded-context.d.ts.map +1 -0
- package/dist/runtime/bounded-context.js +454 -0
- package/dist/runtime/bounded-context.js.map +1 -0
- package/dist/runtime/bridge-core.d.ts +1 -0
- package/dist/runtime/bridge-core.d.ts.map +1 -1
- package/dist/runtime/bridge-core.js +52 -17
- package/dist/runtime/bridge-core.js.map +1 -1
- package/dist/runtime/bridge-protocol.d.ts +184 -0
- package/dist/runtime/bridge-protocol.d.ts.map +1 -0
- package/dist/runtime/bridge-protocol.js +344 -0
- package/dist/runtime/bridge-protocol.js.map +1 -0
- package/dist/runtime/disposable.d.ts +40 -0
- package/dist/runtime/disposable.d.ts.map +1 -0
- package/dist/runtime/disposable.js +49 -0
- package/dist/runtime/disposable.js.map +1 -0
- package/dist/runtime/errors.d.ts +10 -0
- package/dist/runtime/errors.d.ts.map +1 -1
- package/dist/runtime/errors.js +9 -0
- package/dist/runtime/errors.js.map +1 -1
- package/dist/runtime/http-io.d.ts +91 -0
- package/dist/runtime/http-io.d.ts.map +1 -0
- package/dist/runtime/http-io.js +195 -0
- package/dist/runtime/http-io.js.map +1 -0
- package/dist/runtime/http.d.ts +48 -13
- package/dist/runtime/http.d.ts.map +1 -1
- package/dist/runtime/http.js +60 -73
- package/dist/runtime/http.js.map +1 -1
- package/dist/runtime/node.d.ts +97 -130
- package/dist/runtime/node.d.ts.map +1 -1
- package/dist/runtime/node.js +392 -521
- package/dist/runtime/node.js.map +1 -1
- package/dist/runtime/optimized-node.d.ts +1 -1
- package/dist/runtime/optimized-node.d.ts.map +1 -1
- package/dist/runtime/optimized-node.js +1 -1
- package/dist/runtime/optimized-node.js.map +1 -1
- package/dist/runtime/pooled-transport.d.ts +135 -0
- package/dist/runtime/pooled-transport.d.ts.map +1 -0
- package/dist/runtime/pooled-transport.js +177 -0
- package/dist/runtime/pooled-transport.js.map +1 -0
- package/dist/runtime/process-io.d.ts +209 -0
- package/dist/runtime/process-io.d.ts.map +1 -0
- package/dist/runtime/process-io.js +729 -0
- package/dist/runtime/process-io.js.map +1 -0
- package/dist/runtime/pyodide-io.d.ts +154 -0
- package/dist/runtime/pyodide-io.d.ts.map +1 -0
- package/dist/runtime/pyodide-io.js +459 -0
- package/dist/runtime/pyodide-io.js.map +1 -0
- package/dist/runtime/pyodide.d.ts +51 -19
- package/dist/runtime/pyodide.d.ts.map +1 -1
- package/dist/runtime/pyodide.js +57 -186
- package/dist/runtime/pyodide.js.map +1 -1
- package/dist/runtime/safe-codec.d.ts +103 -0
- package/dist/runtime/safe-codec.d.ts.map +1 -0
- package/dist/runtime/safe-codec.js +519 -0
- package/dist/runtime/safe-codec.js.map +1 -0
- package/dist/runtime/transport.d.ts +191 -0
- package/dist/runtime/transport.d.ts.map +1 -0
- package/dist/runtime/transport.js +86 -0
- package/dist/runtime/transport.js.map +1 -0
- package/dist/runtime/validators.d.ts +120 -0
- package/dist/runtime/validators.d.ts.map +1 -0
- package/dist/runtime/validators.js +229 -0
- package/dist/runtime/validators.js.map +1 -0
- package/dist/runtime/worker-pool.d.ts +208 -0
- package/dist/runtime/worker-pool.d.ts.map +1 -0
- package/dist/runtime/worker-pool.js +419 -0
- package/dist/runtime/worker-pool.js.map +1 -0
- package/dist/types/index.d.ts +51 -1
- package/dist/types/index.d.ts.map +1 -1
- package/dist/tywrap.d.ts.map +1 -1
- package/dist/tywrap.js +227 -328
- package/dist/tywrap.js.map +1 -1
- package/dist/utils/cache.d.ts.map +1 -1
- package/dist/utils/cache.js +53 -5
- package/dist/utils/cache.js.map +1 -1
- package/dist/utils/codec.d.ts.map +1 -1
- package/dist/utils/codec.js +114 -1
- package/dist/utils/codec.js.map +1 -1
- package/dist/utils/ir-cache.d.ts +28 -0
- package/dist/utils/ir-cache.d.ts.map +1 -0
- package/dist/utils/ir-cache.js +29 -0
- package/dist/utils/ir-cache.js.map +1 -0
- package/dist/utils/parallel-processor.d.ts +1 -1
- package/dist/utils/parallel-processor.d.ts.map +1 -1
- package/dist/utils/parallel-processor.js +111 -40
- package/dist/utils/parallel-processor.js.map +1 -1
- package/dist/utils/runtime.d.ts +5 -1
- package/dist/utils/runtime.d.ts.map +1 -1
- package/dist/utils/runtime.js +112 -18
- package/dist/utils/runtime.js.map +1 -1
- package/package.json +40 -18
- package/runtime/python_bridge.py +108 -15
- package/runtime/safe_codec.py +344 -0
- package/src/cli.ts +61 -2
- package/src/config/index.ts +63 -17
- package/src/core/analyzer.ts +52 -15
- package/src/core/annotation-parser.ts +500 -0
- package/src/core/discovery.ts +26 -12
- package/src/core/generator.ts +956 -116
- package/src/core/mapper.ts +158 -51
- package/src/index.ts +78 -6
- package/src/runtime/base.ts +18 -26
- package/src/runtime/bounded-context.ts +608 -0
- package/src/runtime/bridge-core.ts +58 -18
- package/src/runtime/bridge-protocol.ts +483 -0
- package/src/runtime/disposable.ts +65 -0
- package/src/runtime/errors.ts +14 -0
- package/src/runtime/http-io.ts +245 -0
- package/src/runtime/http.ts +76 -115
- package/src/runtime/node.ts +563 -676
- package/src/runtime/optimized-node.ts +4 -1
- package/src/runtime/pooled-transport.ts +263 -0
- package/src/runtime/process-io.ts +930 -0
- package/src/runtime/pyodide-io.ts +551 -0
- package/src/runtime/pyodide.ts +75 -215
- package/src/runtime/safe-codec.ts +651 -0
- package/src/runtime/transport.ts +278 -0
- package/src/runtime/validators.ts +252 -0
- package/src/runtime/worker-pool.ts +559 -0
- package/src/types/global.d.ts +11 -1
- package/src/types/index.ts +63 -0
- package/src/tywrap.ts +279 -358
- package/src/utils/cache.ts +59 -5
- package/src/utils/codec.ts +122 -1
- package/src/utils/ir-cache.ts +51 -0
- package/src/utils/parallel-processor.ts +119 -43
- package/src/utils/runtime.ts +129 -18
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WorkerPool - Manages multiple Transport instances for concurrent request handling.
|
|
3
|
+
*
|
|
4
|
+
* Provides semaphore-based concurrency control with configurable limits per worker
|
|
5
|
+
* and a wait queue for callers when all workers are at capacity.
|
|
6
|
+
*
|
|
7
|
+
* @see https://github.com/bbopen/tywrap/issues/149
|
|
8
|
+
*/
|
|
9
|
+
import { BoundedContext } from './bounded-context.js';
|
|
10
|
+
import type { Transport } from './transport.js';
|
|
11
|
+
/**
|
|
12
|
+
* Configuration options for the WorkerPool.
|
|
13
|
+
*/
|
|
14
|
+
export interface WorkerPoolOptions {
|
|
15
|
+
/** Factory function to create transports */
|
|
16
|
+
createTransport: () => Transport;
|
|
17
|
+
/** Maximum number of workers in the pool */
|
|
18
|
+
maxWorkers: number;
|
|
19
|
+
/** Minimum number of workers to pre-spawn during init. Default: 0 (lazy) */
|
|
20
|
+
minWorkers?: number;
|
|
21
|
+
/** Timeout for waiting in queue (ms). Default: 30000 */
|
|
22
|
+
queueTimeoutMs?: number;
|
|
23
|
+
/** Maximum concurrent requests per worker. Default: 1 */
|
|
24
|
+
maxConcurrentPerWorker?: number;
|
|
25
|
+
/**
|
|
26
|
+
* Callback invoked after each worker is created and initialized.
|
|
27
|
+
* Use this for per-worker warmup (e.g., importing modules, running setup).
|
|
28
|
+
*/
|
|
29
|
+
onWorkerReady?: (worker: PooledWorker) => Promise<void>;
|
|
30
|
+
/**
|
|
31
|
+
* Optional callback used only for background replacement workers after a
|
|
32
|
+
* fatal timeout/crash. This lets callers publish a replacement only after it
|
|
33
|
+
* is proven ready, without charging hidden work to normal request startup.
|
|
34
|
+
*/
|
|
35
|
+
onReplacementWorkerReady?: (worker: PooledWorker) => Promise<void>;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* A pooled worker with its transport and current in-flight request count.
|
|
39
|
+
*/
|
|
40
|
+
export interface PooledWorker {
|
|
41
|
+
/** The underlying transport instance */
|
|
42
|
+
transport: Transport;
|
|
43
|
+
/** Number of requests currently being processed by this worker */
|
|
44
|
+
inFlightCount: number;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Pool of Transport workers with semaphore-based concurrency control.
|
|
48
|
+
*
|
|
49
|
+
* Features:
|
|
50
|
+
* - Lazy worker creation (workers created on demand)
|
|
51
|
+
* - Configurable concurrency per worker
|
|
52
|
+
* - Wait queue with timeout for callers when pool is at capacity
|
|
53
|
+
* - Automatic cleanup of timers and workers on disposal
|
|
54
|
+
*
|
|
55
|
+
* @example
|
|
56
|
+
* ```typescript
|
|
57
|
+
* const pool = new WorkerPool({
|
|
58
|
+
* createTransport: () => new ProcessIO({ pythonPath: 'python3' }),
|
|
59
|
+
* maxWorkers: 4,
|
|
60
|
+
* maxConcurrentPerWorker: 2,
|
|
61
|
+
* queueTimeoutMs: 5000,
|
|
62
|
+
* });
|
|
63
|
+
*
|
|
64
|
+
* await pool.init();
|
|
65
|
+
*
|
|
66
|
+
* // Use withWorker for automatic acquire/release
|
|
67
|
+
* const result = await pool.withWorker(async (worker) => {
|
|
68
|
+
* return worker.transport.send(message, timeout);
|
|
69
|
+
* });
|
|
70
|
+
*
|
|
71
|
+
* await pool.dispose();
|
|
72
|
+
* ```
|
|
73
|
+
*/
|
|
74
|
+
export declare class WorkerPool extends BoundedContext {
|
|
75
|
+
private readonly options;
|
|
76
|
+
private readonly workers;
|
|
77
|
+
private readonly waitQueue;
|
|
78
|
+
/** Tracks workers being created to prevent race condition in acquire() */
|
|
79
|
+
private pendingCreations;
|
|
80
|
+
/**
|
|
81
|
+
* Create a new WorkerPool.
|
|
82
|
+
*
|
|
83
|
+
* @param options - Pool configuration options
|
|
84
|
+
*/
|
|
85
|
+
constructor(options: WorkerPoolOptions);
|
|
86
|
+
/**
|
|
87
|
+
* Initialize the pool.
|
|
88
|
+
*
|
|
89
|
+
* If minWorkers > 0, pre-spawns workers during initialization.
|
|
90
|
+
* Otherwise, workers are created lazily on demand.
|
|
91
|
+
*/
|
|
92
|
+
protected doInit(): Promise<void>;
|
|
93
|
+
/**
|
|
94
|
+
* Dispose the pool and all workers.
|
|
95
|
+
*
|
|
96
|
+
* - Rejects all waiters in the queue
|
|
97
|
+
* - Disposes all transport instances
|
|
98
|
+
* - Clears internal state
|
|
99
|
+
*/
|
|
100
|
+
protected doDispose(): Promise<void>;
|
|
101
|
+
/**
|
|
102
|
+
* Acquire a worker from the pool.
|
|
103
|
+
*
|
|
104
|
+
* This method:
|
|
105
|
+
* - Returns an available worker if one exists (inFlightCount < maxConcurrentPerWorker)
|
|
106
|
+
* - Creates a new worker if under the maxWorkers limit
|
|
107
|
+
* - Waits in queue if all workers are at capacity
|
|
108
|
+
*
|
|
109
|
+
* @returns Promise resolving to a pooled worker
|
|
110
|
+
* @throws BridgeTimeoutError if queue timeout expires
|
|
111
|
+
* @throws BridgeExecutionError if pool is disposed while waiting
|
|
112
|
+
*/
|
|
113
|
+
acquire(): Promise<PooledWorker>;
|
|
114
|
+
/**
|
|
115
|
+
* Release a worker back to the pool.
|
|
116
|
+
*
|
|
117
|
+
* Decrements the worker's in-flight count and notifies any waiters
|
|
118
|
+
* that a worker may be available.
|
|
119
|
+
*
|
|
120
|
+
* @param worker - The worker to release
|
|
121
|
+
*/
|
|
122
|
+
release(worker: PooledWorker): void;
|
|
123
|
+
/**
|
|
124
|
+
* Execute a function with an acquired worker, automatically releasing afterward.
|
|
125
|
+
*
|
|
126
|
+
* This is the recommended way to use the pool, as it ensures proper cleanup
|
|
127
|
+
* even if the function throws an error.
|
|
128
|
+
*
|
|
129
|
+
* @param fn - Async function to execute with the worker
|
|
130
|
+
* @returns Promise resolving to the function's return value
|
|
131
|
+
*
|
|
132
|
+
* @example
|
|
133
|
+
* ```typescript
|
|
134
|
+
* const result = await pool.withWorker(async (worker) => {
|
|
135
|
+
* return worker.transport.send(message, timeout);
|
|
136
|
+
* });
|
|
137
|
+
* ```
|
|
138
|
+
*/
|
|
139
|
+
withWorker<T>(fn: (worker: PooledWorker) => Promise<T>): Promise<T>;
|
|
140
|
+
/**
|
|
141
|
+
* Check if an error indicates the worker is dead and should be removed.
|
|
142
|
+
*
|
|
143
|
+
* Fatal errors include:
|
|
144
|
+
* - Process not running
|
|
145
|
+
* - Process exited unexpectedly
|
|
146
|
+
* - Pipe errors (EPIPE)
|
|
147
|
+
* - Connection reset errors (ECONNRESET)
|
|
148
|
+
* - Request timeouts (the worker may still be busy with an uncancellable request)
|
|
149
|
+
*/
|
|
150
|
+
private isFatalWorkerError;
|
|
151
|
+
/**
|
|
152
|
+
* Remove a worker from the pool.
|
|
153
|
+
*
|
|
154
|
+
* This is called when a worker is detected as dead (crashed, pipe error, etc.).
|
|
155
|
+
* The worker's transport is disposed in the background.
|
|
156
|
+
*/
|
|
157
|
+
private removeWorker;
|
|
158
|
+
/**
|
|
159
|
+
* Current number of workers in the pool.
|
|
160
|
+
*/
|
|
161
|
+
get workerCount(): number;
|
|
162
|
+
/**
|
|
163
|
+
* Number of callers waiting in the queue.
|
|
164
|
+
*/
|
|
165
|
+
get queueLength(): number;
|
|
166
|
+
/**
|
|
167
|
+
* Total number of in-flight requests across all workers.
|
|
168
|
+
*/
|
|
169
|
+
get totalInFlight(): number;
|
|
170
|
+
/**
|
|
171
|
+
* Find an available worker with capacity for another request.
|
|
172
|
+
*/
|
|
173
|
+
private findAvailableWorker;
|
|
174
|
+
/**
|
|
175
|
+
* Replace a removed worker in the background so the next caller does not pay
|
|
176
|
+
* the full worker cold-start penalty after a timeout or crash.
|
|
177
|
+
*/
|
|
178
|
+
private scheduleReplacementWorker;
|
|
179
|
+
/**
|
|
180
|
+
* Create a new worker and add it to the pool.
|
|
181
|
+
*
|
|
182
|
+
* If onWorkerReady is configured, calls it after the transport is initialized.
|
|
183
|
+
* This is useful for per-worker warmup (importing modules, running setup).
|
|
184
|
+
*/
|
|
185
|
+
private createWorker;
|
|
186
|
+
/**
|
|
187
|
+
* Wait in queue for a worker to become available.
|
|
188
|
+
*/
|
|
189
|
+
private waitForWorker;
|
|
190
|
+
/**
|
|
191
|
+
* Not implemented - WorkerPool does not execute Python calls directly.
|
|
192
|
+
* Use the BridgeProtocol layer with a pooled worker's transport.
|
|
193
|
+
*/
|
|
194
|
+
call<T = unknown>(_module: string, _functionName: string, _args: unknown[], _kwargs?: Record<string, unknown>): Promise<T>;
|
|
195
|
+
/**
|
|
196
|
+
* Not implemented - WorkerPool does not execute Python calls directly.
|
|
197
|
+
*/
|
|
198
|
+
instantiate<T = unknown>(_module: string, _className: string, _args: unknown[], _kwargs?: Record<string, unknown>): Promise<T>;
|
|
199
|
+
/**
|
|
200
|
+
* Not implemented - WorkerPool does not execute Python calls directly.
|
|
201
|
+
*/
|
|
202
|
+
callMethod<T = unknown>(_handle: string, _methodName: string, _args: unknown[], _kwargs?: Record<string, unknown>): Promise<T>;
|
|
203
|
+
/**
|
|
204
|
+
* Not implemented - WorkerPool does not execute Python calls directly.
|
|
205
|
+
*/
|
|
206
|
+
disposeInstance(_handle: string): Promise<void>;
|
|
207
|
+
}
|
|
208
|
+
//# sourceMappingURL=worker-pool.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"worker-pool.d.ts","sourceRoot":"","sources":["../../src/runtime/worker-pool.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,419 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WorkerPool - Manages multiple Transport instances for concurrent request handling.
|
|
3
|
+
*
|
|
4
|
+
* Provides semaphore-based concurrency control with configurable limits per worker
|
|
5
|
+
* and a wait queue for callers when all workers are at capacity.
|
|
6
|
+
*
|
|
7
|
+
* @see https://github.com/bbopen/tywrap/issues/149
|
|
8
|
+
*/
|
|
9
|
+
import { BoundedContext } from './bounded-context.js';
|
|
10
|
+
import { BridgeTimeoutError, BridgeExecutionError, BridgeProtocolError } from './errors.js';
|
|
11
|
+
// =============================================================================
|
|
12
|
+
// WORKER POOL
|
|
13
|
+
// =============================================================================
|
|
14
|
+
/**
|
|
15
|
+
* Pool of Transport workers with semaphore-based concurrency control.
|
|
16
|
+
*
|
|
17
|
+
* Features:
|
|
18
|
+
* - Lazy worker creation (workers created on demand)
|
|
19
|
+
* - Configurable concurrency per worker
|
|
20
|
+
* - Wait queue with timeout for callers when pool is at capacity
|
|
21
|
+
* - Automatic cleanup of timers and workers on disposal
|
|
22
|
+
*
|
|
23
|
+
* @example
|
|
24
|
+
* ```typescript
|
|
25
|
+
* const pool = new WorkerPool({
|
|
26
|
+
* createTransport: () => new ProcessIO({ pythonPath: 'python3' }),
|
|
27
|
+
* maxWorkers: 4,
|
|
28
|
+
* maxConcurrentPerWorker: 2,
|
|
29
|
+
* queueTimeoutMs: 5000,
|
|
30
|
+
* });
|
|
31
|
+
*
|
|
32
|
+
* await pool.init();
|
|
33
|
+
*
|
|
34
|
+
* // Use withWorker for automatic acquire/release
|
|
35
|
+
* const result = await pool.withWorker(async (worker) => {
|
|
36
|
+
* return worker.transport.send(message, timeout);
|
|
37
|
+
* });
|
|
38
|
+
*
|
|
39
|
+
* await pool.dispose();
|
|
40
|
+
* ```
|
|
41
|
+
*/
|
|
42
|
+
export class WorkerPool extends BoundedContext {
|
|
43
|
+
options;
|
|
44
|
+
workers = [];
|
|
45
|
+
waitQueue = [];
|
|
46
|
+
/** Tracks workers being created to prevent race condition in acquire() */
|
|
47
|
+
pendingCreations = 0;
|
|
48
|
+
/**
|
|
49
|
+
* Create a new WorkerPool.
|
|
50
|
+
*
|
|
51
|
+
* @param options - Pool configuration options
|
|
52
|
+
*/
|
|
53
|
+
constructor(options) {
|
|
54
|
+
super();
|
|
55
|
+
// Validate required options
|
|
56
|
+
if (typeof options.createTransport !== 'function') {
|
|
57
|
+
throw new BridgeExecutionError('createTransport must be a function');
|
|
58
|
+
}
|
|
59
|
+
if (typeof options.maxWorkers !== 'number' || options.maxWorkers < 1) {
|
|
60
|
+
throw new BridgeExecutionError('maxWorkers must be a positive number');
|
|
61
|
+
}
|
|
62
|
+
const minWorkers = options.minWorkers ?? 0;
|
|
63
|
+
if (minWorkers > options.maxWorkers) {
|
|
64
|
+
throw new BridgeExecutionError('minWorkers cannot exceed maxWorkers');
|
|
65
|
+
}
|
|
66
|
+
this.options = {
|
|
67
|
+
createTransport: options.createTransport,
|
|
68
|
+
maxWorkers: options.maxWorkers,
|
|
69
|
+
minWorkers,
|
|
70
|
+
queueTimeoutMs: options.queueTimeoutMs ?? 30000,
|
|
71
|
+
maxConcurrentPerWorker: options.maxConcurrentPerWorker ?? 1,
|
|
72
|
+
onWorkerReady: options.onWorkerReady,
|
|
73
|
+
onReplacementWorkerReady: options.onReplacementWorkerReady,
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
// ===========================================================================
|
|
77
|
+
// LIFECYCLE
|
|
78
|
+
// ===========================================================================
|
|
79
|
+
/**
|
|
80
|
+
* Initialize the pool.
|
|
81
|
+
*
|
|
82
|
+
* If minWorkers > 0, pre-spawns workers during initialization.
|
|
83
|
+
* Otherwise, workers are created lazily on demand.
|
|
84
|
+
*/
|
|
85
|
+
async doInit() {
|
|
86
|
+
// Pre-spawn minimum workers if configured
|
|
87
|
+
if (this.options.minWorkers > 0) {
|
|
88
|
+
const spawns = [];
|
|
89
|
+
for (let i = 0; i < this.options.minWorkers; i++) {
|
|
90
|
+
spawns.push(this.createWorker());
|
|
91
|
+
}
|
|
92
|
+
await Promise.all(spawns);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Dispose the pool and all workers.
|
|
97
|
+
*
|
|
98
|
+
* - Rejects all waiters in the queue
|
|
99
|
+
* - Disposes all transport instances
|
|
100
|
+
* - Clears internal state
|
|
101
|
+
*/
|
|
102
|
+
async doDispose() {
|
|
103
|
+
// Reject all waiters in the queue
|
|
104
|
+
for (const waiter of this.waitQueue) {
|
|
105
|
+
clearTimeout(waiter.timer);
|
|
106
|
+
waiter.reject(new BridgeExecutionError('Pool disposed'));
|
|
107
|
+
}
|
|
108
|
+
this.waitQueue.length = 0;
|
|
109
|
+
// Dispose all workers
|
|
110
|
+
const errors = [];
|
|
111
|
+
for (const worker of this.workers) {
|
|
112
|
+
try {
|
|
113
|
+
await worker.transport.dispose();
|
|
114
|
+
}
|
|
115
|
+
catch (e) {
|
|
116
|
+
errors.push(e instanceof Error ? e : new Error(String(e)));
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
this.workers.length = 0;
|
|
120
|
+
// Report errors if any
|
|
121
|
+
if (errors.length === 1) {
|
|
122
|
+
throw errors[0];
|
|
123
|
+
}
|
|
124
|
+
if (errors.length > 1) {
|
|
125
|
+
throw new AggregateError(errors, 'Multiple errors during worker disposal');
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
// ===========================================================================
|
|
129
|
+
// WORKER MANAGEMENT
|
|
130
|
+
// ===========================================================================
|
|
131
|
+
/**
|
|
132
|
+
* Acquire a worker from the pool.
|
|
133
|
+
*
|
|
134
|
+
* This method:
|
|
135
|
+
* - Returns an available worker if one exists (inFlightCount < maxConcurrentPerWorker)
|
|
136
|
+
* - Creates a new worker if under the maxWorkers limit
|
|
137
|
+
* - Waits in queue if all workers are at capacity
|
|
138
|
+
*
|
|
139
|
+
* @returns Promise resolving to a pooled worker
|
|
140
|
+
* @throws BridgeTimeoutError if queue timeout expires
|
|
141
|
+
* @throws BridgeExecutionError if pool is disposed while waiting
|
|
142
|
+
*/
|
|
143
|
+
async acquire() {
|
|
144
|
+
// Check for disposed state
|
|
145
|
+
if (this.isDisposed) {
|
|
146
|
+
throw new BridgeExecutionError('Pool has been disposed');
|
|
147
|
+
}
|
|
148
|
+
// Find an available worker (one with capacity)
|
|
149
|
+
const availableWorker = this.findAvailableWorker();
|
|
150
|
+
if (availableWorker) {
|
|
151
|
+
availableWorker.inFlightCount++;
|
|
152
|
+
return availableWorker;
|
|
153
|
+
}
|
|
154
|
+
// Create a new worker if under the limit
|
|
155
|
+
// Include pendingCreations to prevent race condition where multiple
|
|
156
|
+
// concurrent acquire() calls all pass the length check before any
|
|
157
|
+
// worker is actually added to the array
|
|
158
|
+
if (this.workers.length + this.pendingCreations < this.options.maxWorkers) {
|
|
159
|
+
this.pendingCreations++;
|
|
160
|
+
try {
|
|
161
|
+
const newWorker = await this.createWorker();
|
|
162
|
+
newWorker.inFlightCount++;
|
|
163
|
+
return newWorker;
|
|
164
|
+
}
|
|
165
|
+
finally {
|
|
166
|
+
this.pendingCreations--;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
// All workers at capacity - wait in queue
|
|
170
|
+
return this.waitForWorker();
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* Release a worker back to the pool.
|
|
174
|
+
*
|
|
175
|
+
* Decrements the worker's in-flight count and notifies any waiters
|
|
176
|
+
* that a worker may be available.
|
|
177
|
+
*
|
|
178
|
+
* @param worker - The worker to release
|
|
179
|
+
*/
|
|
180
|
+
release(worker) {
|
|
181
|
+
// Validate the worker belongs to this pool
|
|
182
|
+
if (!this.workers.includes(worker)) {
|
|
183
|
+
return;
|
|
184
|
+
}
|
|
185
|
+
// Decrement in-flight count (minimum 0)
|
|
186
|
+
worker.inFlightCount = Math.max(0, worker.inFlightCount - 1);
|
|
187
|
+
// If there are waiters and this worker has capacity, fulfill the first waiter
|
|
188
|
+
if (this.waitQueue.length > 0 && worker.inFlightCount < this.options.maxConcurrentPerWorker) {
|
|
189
|
+
const waiter = this.waitQueue.shift();
|
|
190
|
+
if (waiter) {
|
|
191
|
+
clearTimeout(waiter.timer);
|
|
192
|
+
worker.inFlightCount++;
|
|
193
|
+
waiter.resolve(worker);
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
/**
|
|
198
|
+
* Execute a function with an acquired worker, automatically releasing afterward.
|
|
199
|
+
*
|
|
200
|
+
* This is the recommended way to use the pool, as it ensures proper cleanup
|
|
201
|
+
* even if the function throws an error.
|
|
202
|
+
*
|
|
203
|
+
* @param fn - Async function to execute with the worker
|
|
204
|
+
* @returns Promise resolving to the function's return value
|
|
205
|
+
*
|
|
206
|
+
* @example
|
|
207
|
+
* ```typescript
|
|
208
|
+
* const result = await pool.withWorker(async (worker) => {
|
|
209
|
+
* return worker.transport.send(message, timeout);
|
|
210
|
+
* });
|
|
211
|
+
* ```
|
|
212
|
+
*/
|
|
213
|
+
async withWorker(fn) {
|
|
214
|
+
const worker = await this.acquire();
|
|
215
|
+
let workerRemoved = false;
|
|
216
|
+
try {
|
|
217
|
+
return await fn(worker);
|
|
218
|
+
}
|
|
219
|
+
catch (error) {
|
|
220
|
+
// If this is a fatal error indicating the worker is dead, remove it from the pool
|
|
221
|
+
if (this.isFatalWorkerError(error)) {
|
|
222
|
+
this.removeWorker(worker);
|
|
223
|
+
workerRemoved = true;
|
|
224
|
+
}
|
|
225
|
+
throw error;
|
|
226
|
+
}
|
|
227
|
+
finally {
|
|
228
|
+
// Only release if worker wasn't removed due to fatal error
|
|
229
|
+
if (!workerRemoved) {
|
|
230
|
+
this.release(worker);
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
// ===========================================================================
|
|
235
|
+
// WORKER HEALTH
|
|
236
|
+
// ===========================================================================
|
|
237
|
+
/**
|
|
238
|
+
* Check if an error indicates the worker is dead and should be removed.
|
|
239
|
+
*
|
|
240
|
+
* Fatal errors include:
|
|
241
|
+
* - Process not running
|
|
242
|
+
* - Process exited unexpectedly
|
|
243
|
+
* - Pipe errors (EPIPE)
|
|
244
|
+
* - Connection reset errors (ECONNRESET)
|
|
245
|
+
* - Request timeouts (the worker may still be busy with an uncancellable request)
|
|
246
|
+
*/
|
|
247
|
+
isFatalWorkerError(error) {
|
|
248
|
+
// If a request times out, the underlying transport may still be executing it.
|
|
249
|
+
// Quarantine this worker so subsequent requests don't get stuck behind it.
|
|
250
|
+
if (error instanceof BridgeTimeoutError) {
|
|
251
|
+
return true;
|
|
252
|
+
}
|
|
253
|
+
if (error instanceof BridgeProtocolError) {
|
|
254
|
+
const msg = error.message.toLowerCase();
|
|
255
|
+
return (msg.includes('not running') ||
|
|
256
|
+
msg.includes('process exited') ||
|
|
257
|
+
msg.includes('epipe') ||
|
|
258
|
+
msg.includes('econnreset'));
|
|
259
|
+
}
|
|
260
|
+
return false;
|
|
261
|
+
}
|
|
262
|
+
/**
|
|
263
|
+
* Remove a worker from the pool.
|
|
264
|
+
*
|
|
265
|
+
* This is called when a worker is detected as dead (crashed, pipe error, etc.).
|
|
266
|
+
* The worker's transport is disposed in the background.
|
|
267
|
+
*/
|
|
268
|
+
removeWorker(worker) {
|
|
269
|
+
const index = this.workers.indexOf(worker);
|
|
270
|
+
if (index !== -1) {
|
|
271
|
+
this.workers.splice(index, 1);
|
|
272
|
+
// Dispose transport in background - don't await to avoid blocking
|
|
273
|
+
worker.transport.dispose().catch(() => {
|
|
274
|
+
// Ignore disposal errors for dead workers
|
|
275
|
+
});
|
|
276
|
+
this.scheduleReplacementWorker();
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
// ===========================================================================
|
|
280
|
+
// POOL STATISTICS
|
|
281
|
+
// ===========================================================================
|
|
282
|
+
/**
|
|
283
|
+
* Current number of workers in the pool.
|
|
284
|
+
*/
|
|
285
|
+
get workerCount() {
|
|
286
|
+
return this.workers.length;
|
|
287
|
+
}
|
|
288
|
+
/**
|
|
289
|
+
* Number of callers waiting in the queue.
|
|
290
|
+
*/
|
|
291
|
+
get queueLength() {
|
|
292
|
+
return this.waitQueue.length;
|
|
293
|
+
}
|
|
294
|
+
/**
|
|
295
|
+
* Total number of in-flight requests across all workers.
|
|
296
|
+
*/
|
|
297
|
+
get totalInFlight() {
|
|
298
|
+
return this.workers.reduce((sum, w) => sum + w.inFlightCount, 0);
|
|
299
|
+
}
|
|
300
|
+
// ===========================================================================
|
|
301
|
+
// PRIVATE HELPERS
|
|
302
|
+
// ===========================================================================
|
|
303
|
+
/**
|
|
304
|
+
* Find an available worker with capacity for another request.
|
|
305
|
+
*/
|
|
306
|
+
findAvailableWorker() {
|
|
307
|
+
return this.workers.find(w => w.inFlightCount < this.options.maxConcurrentPerWorker);
|
|
308
|
+
}
|
|
309
|
+
/**
|
|
310
|
+
* Replace a removed worker in the background so the next caller does not pay
|
|
311
|
+
* the full worker cold-start penalty after a timeout or crash.
|
|
312
|
+
*/
|
|
313
|
+
scheduleReplacementWorker() {
|
|
314
|
+
if (this.state !== 'ready') {
|
|
315
|
+
return;
|
|
316
|
+
}
|
|
317
|
+
if (this.workers.length + this.pendingCreations >= this.options.maxWorkers) {
|
|
318
|
+
return;
|
|
319
|
+
}
|
|
320
|
+
this.pendingCreations++;
|
|
321
|
+
const replacementReady = this.options.onReplacementWorkerReady ?? this.options.onWorkerReady;
|
|
322
|
+
this.createWorker(replacementReady)
|
|
323
|
+
.then(worker => {
|
|
324
|
+
// Reuse release() to wake queued callers if one is waiting.
|
|
325
|
+
this.release(worker);
|
|
326
|
+
})
|
|
327
|
+
.catch(() => {
|
|
328
|
+
// Ignore background replacement failures. A later acquire() can retry.
|
|
329
|
+
})
|
|
330
|
+
.finally(() => {
|
|
331
|
+
this.pendingCreations = Math.max(0, this.pendingCreations - 1);
|
|
332
|
+
});
|
|
333
|
+
}
|
|
334
|
+
/**
|
|
335
|
+
* Create a new worker and add it to the pool.
|
|
336
|
+
*
|
|
337
|
+
* If onWorkerReady is configured, calls it after the transport is initialized.
|
|
338
|
+
* This is useful for per-worker warmup (importing modules, running setup).
|
|
339
|
+
*/
|
|
340
|
+
async createWorker(onWorkerReady = this.options.onWorkerReady) {
|
|
341
|
+
const transport = this.options.createTransport();
|
|
342
|
+
// Initialize the transport
|
|
343
|
+
await transport.init();
|
|
344
|
+
const worker = {
|
|
345
|
+
transport,
|
|
346
|
+
inFlightCount: 0,
|
|
347
|
+
};
|
|
348
|
+
try {
|
|
349
|
+
// Call onWorkerReady callback if provided
|
|
350
|
+
if (onWorkerReady) {
|
|
351
|
+
await onWorkerReady(worker);
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
catch (error) {
|
|
355
|
+
// Ensure partially initialized workers do not leak when warmup fails.
|
|
356
|
+
await transport.dispose().catch(() => {
|
|
357
|
+
// Ignore disposal failures during warmup failure handling.
|
|
358
|
+
});
|
|
359
|
+
throw error;
|
|
360
|
+
}
|
|
361
|
+
if (this.state === 'disposing' || this.state === 'disposed') {
|
|
362
|
+
await transport.dispose().catch(() => {
|
|
363
|
+
// Ignore disposal failures if the pool was torn down mid-creation.
|
|
364
|
+
});
|
|
365
|
+
throw new BridgeExecutionError('Pool disposed during worker creation');
|
|
366
|
+
}
|
|
367
|
+
this.workers.push(worker);
|
|
368
|
+
return worker;
|
|
369
|
+
}
|
|
370
|
+
/**
|
|
371
|
+
* Wait in queue for a worker to become available.
|
|
372
|
+
*/
|
|
373
|
+
waitForWorker() {
|
|
374
|
+
return new Promise((resolve, reject) => {
|
|
375
|
+
const timer = setTimeout(() => {
|
|
376
|
+
// Remove this waiter from the queue
|
|
377
|
+
const index = this.waitQueue.findIndex(w => w.timer === timer);
|
|
378
|
+
if (index !== -1) {
|
|
379
|
+
this.waitQueue.splice(index, 1);
|
|
380
|
+
}
|
|
381
|
+
reject(new BridgeTimeoutError(`Timed out waiting for available worker after ${this.options.queueTimeoutMs}ms`));
|
|
382
|
+
}, this.options.queueTimeoutMs);
|
|
383
|
+
// Unref the timer so it doesn't keep the Node.js process alive
|
|
384
|
+
if (typeof timer.unref === 'function') {
|
|
385
|
+
timer.unref();
|
|
386
|
+
}
|
|
387
|
+
this.waitQueue.push({ resolve, reject, timer });
|
|
388
|
+
});
|
|
389
|
+
}
|
|
390
|
+
// ===========================================================================
|
|
391
|
+
// RUNTIME EXECUTION (Not implemented - WorkerPool is just for worker management)
|
|
392
|
+
// ===========================================================================
|
|
393
|
+
/**
|
|
394
|
+
* Not implemented - WorkerPool does not execute Python calls directly.
|
|
395
|
+
* Use the BridgeProtocol layer with a pooled worker's transport.
|
|
396
|
+
*/
|
|
397
|
+
async call(_module, _functionName, _args, _kwargs) {
|
|
398
|
+
throw new BridgeExecutionError('WorkerPool does not implement call() - use withWorker() to get a transport');
|
|
399
|
+
}
|
|
400
|
+
/**
|
|
401
|
+
* Not implemented - WorkerPool does not execute Python calls directly.
|
|
402
|
+
*/
|
|
403
|
+
async instantiate(_module, _className, _args, _kwargs) {
|
|
404
|
+
throw new BridgeExecutionError('WorkerPool does not implement instantiate() - use withWorker() to get a transport');
|
|
405
|
+
}
|
|
406
|
+
/**
|
|
407
|
+
* Not implemented - WorkerPool does not execute Python calls directly.
|
|
408
|
+
*/
|
|
409
|
+
async callMethod(_handle, _methodName, _args, _kwargs) {
|
|
410
|
+
throw new BridgeExecutionError('WorkerPool does not implement callMethod() - use withWorker() to get a transport');
|
|
411
|
+
}
|
|
412
|
+
/**
|
|
413
|
+
* Not implemented - WorkerPool does not execute Python calls directly.
|
|
414
|
+
*/
|
|
415
|
+
async disposeInstance(_handle) {
|
|
416
|
+
throw new BridgeExecutionError('WorkerPool does not implement disposeInstance() - use withWorker() to get a transport');
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
//# sourceMappingURL=worker-pool.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"worker-pool.js","sourceRoot":"","sources":["../../src/runtime/worker-pool.ts"],"names":[],"mappings":"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"}
|