tywrap 0.1.2 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +11 -4
- package/dist/index.d.ts +20 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +22 -2
- 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-protocol.d.ts +167 -0
- package/dist/runtime/bridge-protocol.d.ts.map +1 -0
- package/dist/runtime/bridge-protocol.js +247 -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/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 +47 -13
- package/dist/runtime/http.d.ts.map +1 -1
- package/dist/runtime/http.js +55 -74
- package/dist/runtime/http.js.map +1 -1
- package/dist/runtime/node.d.ts +142 -28
- package/dist/runtime/node.d.ts.map +1 -1
- package/dist/runtime/node.js +321 -168
- package/dist/runtime/node.js.map +1 -1
- package/dist/runtime/optimized-node.d.ts +19 -125
- package/dist/runtime/optimized-node.d.ts.map +1 -1
- package/dist/runtime/optimized-node.js +19 -550
- package/dist/runtime/optimized-node.js.map +1 -1
- package/dist/runtime/pooled-transport.d.ts +131 -0
- package/dist/runtime/pooled-transport.d.ts.map +1 -0
- package/dist/runtime/pooled-transport.js +175 -0
- package/dist/runtime/pooled-transport.js.map +1 -0
- package/dist/runtime/process-io.d.ts +204 -0
- package/dist/runtime/process-io.d.ts.map +1 -0
- package/dist/runtime/process-io.js +695 -0
- package/dist/runtime/process-io.js.map +1 -0
- package/dist/runtime/pyodide-io.d.ts +155 -0
- package/dist/runtime/pyodide-io.d.ts.map +1 -0
- package/dist/runtime/pyodide-io.js +397 -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 +81 -0
- package/dist/runtime/safe-codec.d.ts.map +1 -0
- package/dist/runtime/safe-codec.js +345 -0
- package/dist/runtime/safe-codec.js.map +1 -0
- package/dist/runtime/transport.d.ts +186 -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 +131 -0
- package/dist/runtime/validators.d.ts.map +1 -0
- package/dist/runtime/validators.js +219 -0
- package/dist/runtime/validators.js.map +1 -0
- package/dist/runtime/worker-pool.d.ts +196 -0
- package/dist/runtime/worker-pool.d.ts.map +1 -0
- package/dist/runtime/worker-pool.js +371 -0
- package/dist/runtime/worker-pool.js.map +1 -0
- package/dist/utils/codec.d.ts.map +1 -1
- package/dist/utils/codec.js +120 -1
- package/dist/utils/codec.js.map +1 -1
- package/package.json +2 -2
- package/runtime/python_bridge.py +30 -3
- package/runtime/safe_codec.py +344 -0
- package/src/index.ts +48 -5
- package/src/runtime/base.ts +18 -26
- package/src/runtime/bounded-context.ts +608 -0
- package/src/runtime/bridge-protocol.ts +319 -0
- package/src/runtime/disposable.ts +65 -0
- package/src/runtime/http-io.ts +244 -0
- package/src/runtime/http.ts +71 -117
- package/src/runtime/node.ts +460 -217
- package/src/runtime/optimized-node.ts +19 -761
- package/src/runtime/pooled-transport.ts +252 -0
- package/src/runtime/process-io.ts +902 -0
- package/src/runtime/pyodide-io.ts +485 -0
- package/src/runtime/pyodide.ts +75 -215
- package/src/runtime/safe-codec.ts +443 -0
- package/src/runtime/transport.ts +273 -0
- package/src/runtime/validators.ts +241 -0
- package/src/runtime/worker-pool.ts +498 -0
- package/src/utils/codec.ts +126 -1
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PooledTransport - Transport adapter that wraps WorkerPool for multi-process support.
|
|
3
|
+
*
|
|
4
|
+
* This transport implements the Transport interface by delegating to a WorkerPool
|
|
5
|
+
* of ProcessIO transports. Each send() acquires a worker, sends the message,
|
|
6
|
+
* and releases the worker back to the pool.
|
|
7
|
+
*
|
|
8
|
+
* @see https://github.com/bbopen/tywrap/issues/149
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import { BoundedContext } from './bounded-context.js';
|
|
12
|
+
import { BridgeDisposedError, BridgeExecutionError } from './errors.js';
|
|
13
|
+
import type { Transport } from './transport.js';
|
|
14
|
+
import { WorkerPool, type PooledWorker } from './worker-pool.js';
|
|
15
|
+
|
|
16
|
+
// =============================================================================
|
|
17
|
+
// TYPES
|
|
18
|
+
// =============================================================================
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Options for creating a PooledTransport.
|
|
22
|
+
*/
|
|
23
|
+
export interface PooledTransportOptions {
|
|
24
|
+
/** Factory function to create transports for each worker */
|
|
25
|
+
createTransport: () => Transport;
|
|
26
|
+
|
|
27
|
+
/** Maximum number of workers in the pool. Default: 1 */
|
|
28
|
+
maxWorkers?: number;
|
|
29
|
+
|
|
30
|
+
/** Minimum number of workers to pre-spawn during init. Default: 0 (lazy) */
|
|
31
|
+
minWorkers?: number;
|
|
32
|
+
|
|
33
|
+
/** Timeout for waiting in queue (ms). Default: 30000 */
|
|
34
|
+
queueTimeoutMs?: number;
|
|
35
|
+
|
|
36
|
+
/** Maximum concurrent requests per worker. Default: 10 */
|
|
37
|
+
maxConcurrentPerWorker?: number;
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Callback invoked after each worker is created and initialized.
|
|
41
|
+
* Use this for per-worker warmup (e.g., importing modules, running setup).
|
|
42
|
+
*/
|
|
43
|
+
onWorkerReady?: (worker: PooledWorker) => Promise<void>;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// =============================================================================
|
|
47
|
+
// POOLED TRANSPORT
|
|
48
|
+
// =============================================================================
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Transport adapter that wraps WorkerPool for multi-process message handling.
|
|
52
|
+
*
|
|
53
|
+
* PooledTransport presents a single Transport interface while internally
|
|
54
|
+
* distributing requests across multiple worker transports (typically ProcessIO).
|
|
55
|
+
*
|
|
56
|
+
* Features:
|
|
57
|
+
* - Lazy worker creation (transports created on demand)
|
|
58
|
+
* - Configurable pool size and concurrency per worker
|
|
59
|
+
* - Automatic worker acquisition and release
|
|
60
|
+
* - Queue timeout for backpressure management
|
|
61
|
+
*
|
|
62
|
+
* @example
|
|
63
|
+
* ```typescript
|
|
64
|
+
* const transport = new PooledTransport({
|
|
65
|
+
* createTransport: () => new ProcessIO({
|
|
66
|
+
* bridgeScript: '/path/to/bridge.py',
|
|
67
|
+
* }),
|
|
68
|
+
* maxWorkers: 4,
|
|
69
|
+
* maxConcurrentPerWorker: 2,
|
|
70
|
+
* });
|
|
71
|
+
*
|
|
72
|
+
* await transport.init();
|
|
73
|
+
*
|
|
74
|
+
* // send() automatically uses pool
|
|
75
|
+
* const response = await transport.send(message, timeout);
|
|
76
|
+
*
|
|
77
|
+
* await transport.dispose();
|
|
78
|
+
* ```
|
|
79
|
+
*/
|
|
80
|
+
export class PooledTransport extends BoundedContext implements Transport {
|
|
81
|
+
private readonly poolOptions: Omit<Required<PooledTransportOptions>, 'onWorkerReady'> & {
|
|
82
|
+
onWorkerReady?: (worker: PooledWorker) => Promise<void>;
|
|
83
|
+
};
|
|
84
|
+
private pool?: WorkerPool;
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Create a new PooledTransport.
|
|
88
|
+
*
|
|
89
|
+
* @param options - Pool configuration options
|
|
90
|
+
*/
|
|
91
|
+
constructor(options: PooledTransportOptions) {
|
|
92
|
+
super();
|
|
93
|
+
|
|
94
|
+
if (typeof options.createTransport !== 'function') {
|
|
95
|
+
throw new BridgeExecutionError('createTransport must be a function');
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
this.poolOptions = {
|
|
99
|
+
createTransport: options.createTransport,
|
|
100
|
+
maxWorkers: options.maxWorkers ?? 1,
|
|
101
|
+
minWorkers: options.minWorkers ?? 0,
|
|
102
|
+
queueTimeoutMs: options.queueTimeoutMs ?? 30000,
|
|
103
|
+
maxConcurrentPerWorker: options.maxConcurrentPerWorker ?? 10,
|
|
104
|
+
onWorkerReady: options.onWorkerReady,
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// ===========================================================================
|
|
109
|
+
// LIFECYCLE
|
|
110
|
+
// ===========================================================================
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Initialize the pooled transport.
|
|
114
|
+
*
|
|
115
|
+
* Creates and initializes the internal WorkerPool.
|
|
116
|
+
* If minWorkers > 0, workers are pre-spawned during init.
|
|
117
|
+
*/
|
|
118
|
+
protected async doInit(): Promise<void> {
|
|
119
|
+
this.pool = new WorkerPool({
|
|
120
|
+
createTransport: this.poolOptions.createTransport,
|
|
121
|
+
maxWorkers: this.poolOptions.maxWorkers,
|
|
122
|
+
minWorkers: this.poolOptions.minWorkers,
|
|
123
|
+
queueTimeoutMs: this.poolOptions.queueTimeoutMs,
|
|
124
|
+
maxConcurrentPerWorker: this.poolOptions.maxConcurrentPerWorker,
|
|
125
|
+
onWorkerReady: this.poolOptions.onWorkerReady,
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
await this.pool.init();
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Dispose the pooled transport.
|
|
133
|
+
*
|
|
134
|
+
* Disposes the internal WorkerPool, which disposes all workers.
|
|
135
|
+
*/
|
|
136
|
+
protected async doDispose(): Promise<void> {
|
|
137
|
+
if (this.pool) {
|
|
138
|
+
await this.pool.dispose();
|
|
139
|
+
this.pool = undefined;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// ===========================================================================
|
|
144
|
+
// TRANSPORT INTERFACE
|
|
145
|
+
// ===========================================================================
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Send a message through a pooled worker.
|
|
149
|
+
*
|
|
150
|
+
* This method:
|
|
151
|
+
* 1. Acquires a worker from the pool (waiting if necessary)
|
|
152
|
+
* 2. Sends the message through the worker's transport
|
|
153
|
+
* 3. Releases the worker back to the pool
|
|
154
|
+
*
|
|
155
|
+
* @param message - The JSON-encoded protocol message
|
|
156
|
+
* @param timeoutMs - Timeout in milliseconds (0 = no timeout)
|
|
157
|
+
* @param signal - Optional AbortSignal for cancellation
|
|
158
|
+
* @returns The raw JSON response string
|
|
159
|
+
*
|
|
160
|
+
* @throws BridgeDisposedError if transport is disposed
|
|
161
|
+
* @throws BridgeTimeoutError if queue timeout or request timeout expires
|
|
162
|
+
*/
|
|
163
|
+
async send(message: string, timeoutMs: number, signal?: AbortSignal): Promise<string> {
|
|
164
|
+
if (this.isDisposed || !this.pool) {
|
|
165
|
+
throw new BridgeDisposedError('Transport has been disposed');
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
return this.pool.withWorker(async worker => {
|
|
169
|
+
return worker.transport.send(message, timeoutMs, signal);
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
// ===========================================================================
|
|
174
|
+
// POOL STATISTICS
|
|
175
|
+
// ===========================================================================
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* Current number of workers in the pool.
|
|
179
|
+
*/
|
|
180
|
+
get workerCount(): number {
|
|
181
|
+
return this.pool?.workerCount ?? 0;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* Number of callers waiting in the queue.
|
|
186
|
+
*/
|
|
187
|
+
get queueLength(): number {
|
|
188
|
+
return this.pool?.queueLength ?? 0;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* Total number of in-flight requests across all workers.
|
|
193
|
+
*/
|
|
194
|
+
get totalInFlight(): number {
|
|
195
|
+
return this.pool?.totalInFlight ?? 0;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
// ===========================================================================
|
|
199
|
+
// RUNTIME EXECUTION (Not implemented - PooledTransport is just a transport)
|
|
200
|
+
// ===========================================================================
|
|
201
|
+
|
|
202
|
+
/**
|
|
203
|
+
* Not implemented - PooledTransport is a transport, use BridgeProtocol.
|
|
204
|
+
*/
|
|
205
|
+
async call<T = unknown>(
|
|
206
|
+
_module: string,
|
|
207
|
+
_functionName: string,
|
|
208
|
+
_args: unknown[],
|
|
209
|
+
_kwargs?: Record<string, unknown>
|
|
210
|
+
): Promise<T> {
|
|
211
|
+
throw new BridgeExecutionError(
|
|
212
|
+
'PooledTransport is a transport, use BridgeProtocol for operations'
|
|
213
|
+
);
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
/**
|
|
217
|
+
* Not implemented - PooledTransport is a transport, use BridgeProtocol.
|
|
218
|
+
*/
|
|
219
|
+
async instantiate<T = unknown>(
|
|
220
|
+
_module: string,
|
|
221
|
+
_className: string,
|
|
222
|
+
_args: unknown[],
|
|
223
|
+
_kwargs?: Record<string, unknown>
|
|
224
|
+
): Promise<T> {
|
|
225
|
+
throw new BridgeExecutionError(
|
|
226
|
+
'PooledTransport is a transport, use BridgeProtocol for operations'
|
|
227
|
+
);
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
/**
|
|
231
|
+
* Not implemented - PooledTransport is a transport, use BridgeProtocol.
|
|
232
|
+
*/
|
|
233
|
+
async callMethod<T = unknown>(
|
|
234
|
+
_handle: string,
|
|
235
|
+
_methodName: string,
|
|
236
|
+
_args: unknown[],
|
|
237
|
+
_kwargs?: Record<string, unknown>
|
|
238
|
+
): Promise<T> {
|
|
239
|
+
throw new BridgeExecutionError(
|
|
240
|
+
'PooledTransport is a transport, use BridgeProtocol for operations'
|
|
241
|
+
);
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
/**
|
|
245
|
+
* Not implemented - PooledTransport is a transport, use BridgeProtocol.
|
|
246
|
+
*/
|
|
247
|
+
async disposeInstance(_handle: string): Promise<void> {
|
|
248
|
+
throw new BridgeExecutionError(
|
|
249
|
+
'PooledTransport is a transport, use BridgeProtocol for operations'
|
|
250
|
+
);
|
|
251
|
+
}
|
|
252
|
+
}
|