@nimbus-sh/worker 0.2.3 → 0.4.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/dist/_shared/session-router.d.ts +8 -0
- package/dist/_shared/session-router.d.ts.map +1 -1
- package/dist/_shared/session-router.js +8 -0
- package/dist/esbuild-wasm-bundle.generated.d.ts +1 -1
- package/dist/esbuild-wasm-bundle.generated.js +1 -1
- package/dist/facets/cirrus-real.js +1 -1
- package/dist/facets/manager.d.ts +43 -129
- package/dist/facets/manager.d.ts.map +1 -1
- package/dist/facets/manager.js +107 -318
- package/dist/facets/opencode-staging.d.ts +1 -1
- package/dist/facets/opencode-staging.d.ts.map +1 -1
- package/dist/facets/opencode-staging.js +3 -0
- package/dist/facets/real-vite-hmr.js +1 -1
- package/dist/facets/vite-dev-server.d.ts +4 -4
- package/dist/facets/vite-dev-server.js +5 -5
- package/dist/git/commands.d.ts +8 -0
- package/dist/git/commands.d.ts.map +1 -1
- package/dist/git/commands.js +41 -9
- package/dist/git/network-facet.d.ts +1 -1
- package/dist/git/network-facet.d.ts.map +1 -1
- package/dist/git/network-facet.js +39 -15
- package/dist/git-bundle.generated.d.ts +2 -2
- package/dist/git-bundle.generated.d.ts.map +1 -1
- package/dist/git-bundle.generated.js +3 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +9 -1
- package/dist/loaders/child-process/spawn-facet.js +1 -1
- package/dist/loaders/child-process/spawn-pool.d.ts.map +1 -1
- package/dist/loaders/child-process/spawn-pool.js +2 -2
- package/dist/loaders/generated-workers.d.ts +2 -2
- package/dist/loaders/generated-workers.d.ts.map +1 -1
- package/dist/loaders/generated-workers.js +3 -3
- package/dist/loaders/npm-resolve-preamble.d.ts +3 -3
- package/dist/loaders/npm-resolve-preamble.js +3 -3
- package/dist/loaders/pre-bundle-preamble.d.ts +5 -5
- package/dist/loaders/pre-bundle-preamble.js +6 -6
- package/dist/loaders/process-host.d.ts +6 -107
- package/dist/loaders/process-host.d.ts.map +1 -1
- package/dist/loaders/process-host.js +6 -405
- package/dist/npm/install-batch-facet.d.ts +1 -1
- package/dist/npm/install-batch-facet.js +1 -1
- package/dist/npm/installer.d.ts +6 -6
- package/dist/npm/installer.d.ts.map +1 -1
- package/dist/npm/installer.js +28 -27
- package/dist/npm/pre-bundle-facet.d.ts +2 -2
- package/dist/npm/pre-bundle-facet.js +5 -5
- package/dist/npm/r2-cache.d.ts +1 -1
- package/dist/npm/resolve-facet.d.ts +1 -1
- package/dist/npm/resolve-facet.js +1 -1
- package/dist/npm/resolve-one-facet.d.ts +5 -5
- package/dist/npm/resolve-one-facet.js +5 -5
- package/dist/router/index.js +2 -2
- package/dist/router/remote-api.js +9 -1
- package/dist/runtime/bun-repl.d.ts +1 -1
- package/dist/runtime/bun-repl.js +3 -3
- package/dist/runtime/esbuild-wasm-bytes.js +1 -1
- package/dist/runtime/facet-loader-host.d.ts +5 -8
- package/dist/runtime/facet-loader-host.d.ts.map +1 -1
- package/dist/runtime/facet-loader-host.js +7 -11
- package/dist/runtime/node-repl.js +2 -2
- package/dist/runtime/node-shims-artifact.js +1 -1
- package/dist/runtime/node-shims.js +2 -1
- package/dist/runtime/opencode-artifact.js +1 -1
- package/dist/runtime/opentui-wasm-bytes.js +1 -1
- package/dist/runtime/python-repl.js +3 -3
- package/dist/runtime/ruby-repl.js +2 -2
- package/dist/runtime/ruby-resident.js +1 -1
- package/dist/runtime/sqlite-wasm-bytes.js +1 -1
- package/dist/session/diag.js +1 -1
- package/dist/session/hibernation.d.ts +20 -53
- package/dist/session/hibernation.d.ts.map +1 -1
- package/dist/session/hibernation.js +57 -194
- package/dist/session/init-phases.d.ts +2 -3
- package/dist/session/init-phases.d.ts.map +1 -1
- package/dist/session/init-phases.js +3 -2
- package/dist/session/init.d.ts.map +1 -1
- package/dist/session/init.js +8 -4
- package/dist/session/keys.d.ts +14 -37
- package/dist/session/keys.d.ts.map +1 -1
- package/dist/session/keys.js +18 -37
- package/dist/session/nimbus-session.d.ts +10 -15
- package/dist/session/nimbus-session.d.ts.map +1 -1
- package/dist/session/nimbus-session.js +28 -31
- package/dist/session/port-capability.d.ts +43 -0
- package/dist/session/port-capability.d.ts.map +1 -0
- package/dist/session/port-capability.js +49 -0
- package/dist/session/programmatic.d.ts +39 -5
- package/dist/session/programmatic.d.ts.map +1 -1
- package/dist/session/programmatic.js +150 -19
- package/dist/session/routes.d.ts +2 -0
- package/dist/session/routes.d.ts.map +1 -1
- package/dist/session/routes.js +96 -20
- package/dist/session/rpc.d.ts +36 -9
- package/dist/session/rpc.d.ts.map +1 -1
- package/dist/session/rpc.js +84 -24
- package/dist/session/start-real-vite.d.ts.map +1 -1
- package/dist/session/start-real-vite.js +3 -1
- package/dist/session/state-store.d.ts +3 -2
- package/dist/session/state-store.d.ts.map +1 -1
- package/dist/session/state-store.js +3 -2
- package/dist/session/supervisor-rpc.d.ts.map +1 -1
- package/dist/session/supervisor-rpc.js +7 -4
- package/dist/session/ws.d.ts +1 -3
- package/dist/session/ws.d.ts.map +1 -1
- package/dist/session/ws.js +4 -3
- package/dist/wrangler/nimbus-wrangler.js +1 -1
- package/package.json +4 -2
- package/scripts/bundle-esbuild-wasm.mjs +2 -2
- package/scripts/bundle-facet-workers.mjs +5 -7
- package/scripts/bundle-sqlite-wasm.mjs +1 -1
- package/dist/facets/inner-do-registry.d.ts +0 -41
- package/dist/facets/inner-do-registry.d.ts.map +0 -1
- package/dist/facets/inner-do-registry.js +0 -51
- package/dist/facets/launch-pacer.d.ts +0 -111
- package/dist/facets/launch-pacer.d.ts.map +0 -1
- package/dist/facets/launch-pacer.js +0 -130
- package/dist/loaders/fanout-pool.d.ts +0 -207
- package/dist/loaders/fanout-pool.d.ts.map +0 -1
- package/dist/loaders/fanout-pool.js +0 -363
- package/dist/loaders/loader-pool.d.ts +0 -294
- package/dist/loaders/loader-pool.d.ts.map +0 -1
- package/dist/loaders/loader-pool.js +0 -642
- package/dist/loaders/process-fabric.d.ts +0 -509
- package/dist/loaders/process-fabric.d.ts.map +0 -1
- package/dist/loaders/process-fabric.js +0 -360
- package/dist/loaders/vendor/errors.d.ts +0 -24
- package/dist/loaders/vendor/errors.d.ts.map +0 -1
- package/dist/loaders/vendor/errors.js +0 -46
- package/dist/loaders/vendor/serialize.d.ts +0 -3
- package/dist/loaders/vendor/serialize.d.ts.map +0 -1
- package/dist/loaders/vendor/serialize.js +0 -25
- package/dist/loaders/vendor/types.d.ts +0 -69
- package/dist/loaders/vendor/types.d.ts.map +0 -1
- package/dist/loaders/vendor/types.js +0 -4
- package/dist/loaders/workerd-facet-host.d.ts +0 -141
- package/dist/loaders/workerd-facet-host.d.ts.map +0 -1
- package/dist/loaders/workerd-facet-host.js +0 -284
- package/dist/session/bindings.d.ts +0 -209
- package/dist/session/bindings.d.ts.map +0 -1
- package/dist/session/bindings.js +0 -680
- package/dist/session/ctx-exports.d.ts +0 -16
- package/dist/session/ctx-exports.d.ts.map +0 -1
- package/dist/session/ctx-exports.js +0 -22
- package/dist/session/ws-hibernation-config.d.ts +0 -64
- package/dist/session/ws-hibernation-config.d.ts.map +0 -1
- package/dist/session/ws-hibernation-config.js +0 -89
|
@@ -1,363 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Two-tier fan-out primitive for work that must execute in Worker Loader
|
|
3
|
-
* facets without tripping workerd's per-DO dynamic-worker ceiling.
|
|
4
|
-
*
|
|
5
|
-
* A single Durable Object method can drive at most four concurrent
|
|
6
|
-
* Worker Loader fetches before extra dispatches serialize or fail. Small
|
|
7
|
-
* batches therefore run in the coordinator DO through NimbusLoaderPool.
|
|
8
|
-
* Wider batches are sharded across sibling NimbusSession DOs, each of
|
|
9
|
-
* which owns its own four-loader budget.
|
|
10
|
-
*
|
|
11
|
-
* Routing is deterministic: each task has a stable key, and the key maps
|
|
12
|
-
* to a sibling DO shard. There is no silent fallback to width-1 execution;
|
|
13
|
-
* missing LOADER or NIMBUS_SESSION bindings fail loudly so install and
|
|
14
|
-
* runtime operations do not appear successful after partial dispatch.
|
|
15
|
-
*/
|
|
16
|
-
import { serializeFunction } from './vendor/serialize.js';
|
|
17
|
-
import { BindingError } from './vendor/errors.js';
|
|
18
|
-
import { NimbusLoaderPool } from './loader-pool.js';
|
|
19
|
-
import { disposeRpcResource } from '@nimbus-sh/core/_shared/rpc-dispose.js';
|
|
20
|
-
import { describeError, isDoOverloaded, isTransientDoReset } from '@nimbus-sh/core/observability/oom-classify.js';
|
|
21
|
-
/**
|
|
22
|
-
* Threshold at which routing switches from coordinator-local loaders to
|
|
23
|
-
* sibling Durable Objects.
|
|
24
|
-
*
|
|
25
|
-
* Set to **5** so the in-DO path stays below the V8 4-loaders-per-method
|
|
26
|
-
* cap by construction. width < 5 stays local; width >= 5 uses sibling DOs.
|
|
27
|
-
*/
|
|
28
|
-
export const IN_DO_THRESHOLD = 5;
|
|
29
|
-
/**
|
|
30
|
-
* Hard cap on concurrent peer DOs per single submitMany call. Throughput stays
|
|
31
|
-
* flat through this width while keeping per-request scheduler pressure bounded.
|
|
32
|
-
*/
|
|
33
|
-
export const MAX_PEER_FANOUT = 32;
|
|
34
|
-
/**
|
|
35
|
-
* Bounded retries for a peer-DO shard dispatch that rejects with a
|
|
36
|
-
* transient platform reset (code roll-over, storage cold-start hiccup).
|
|
37
|
-
* Sibling DOs are addressed by stable name, so the retry re-dispatches
|
|
38
|
-
* the SAME shard to the re-provisioning object; the fanned-out work
|
|
39
|
-
* (packument resolution, tarball materialisation) is idempotent, so
|
|
40
|
-
* re-running a shard is safe. Budget mirrors the resolve-facet's own
|
|
41
|
-
* per-fetch retry policy so a single flaky cold start no longer fails a
|
|
42
|
-
* whole install. The same budget covers an overloaded peer, on the longer
|
|
43
|
-
* schedule below. Non-transient rejections (OOM, count mismatch, genuine
|
|
44
|
-
* task throw) are NOT retried — they propagate on the first hit.
|
|
45
|
-
*/
|
|
46
|
-
export const PEER_TRANSIENT_RESET_RETRIES = 3;
|
|
47
|
-
export const PEER_RETRY_BACKOFF_MS = [250, 750, 1500];
|
|
48
|
-
/**
|
|
49
|
-
* Backoff for a shard whose peer DO was shed as overloaded. The object is
|
|
50
|
-
* alive and the shard never ran; what it needs is time for the input-gate
|
|
51
|
-
* queue to drain, so the schedule is an order of magnitude longer than the
|
|
52
|
-
* reset schedule. A whole-batch abort here used to fail an entire install.
|
|
53
|
-
*/
|
|
54
|
-
export const PEER_OVERLOAD_BACKOFF_MS = [1000, 3000, 6000];
|
|
55
|
-
/**
|
|
56
|
-
* Peer shards dispatched per phase. Each phase is a barrier that costs its
|
|
57
|
-
* slowest member, so a wide fan-out pays ⌈shards / FANOUT_PHASE_SIZE⌉ serial
|
|
58
|
-
* round-trips; the size trades that serialization against simultaneous cold
|
|
59
|
-
* sibling DO starts.
|
|
60
|
-
*
|
|
61
|
-
* The six-barrier profile once measured on a 123-package install (21 shards of
|
|
62
|
-
* ~6 packages, 10.6/6.8/21.8/7.9/34.6/4.8 s) came from the shard count, not
|
|
63
|
-
* from this width. Capping install shards at INSTALL_PEER_CAP fixed it at the
|
|
64
|
-
* source and that install now clears in two phases. Widening to 8 on top of
|
|
65
|
-
* that bought one further barrier and doubled the simultaneous cold sibling-DO
|
|
66
|
-
* starts, which is the account-level pressure the phasing exists for: twelve
|
|
67
|
-
* concurrent Markflow installs went from 48 simultaneous peer starts to 96 and
|
|
68
|
-
* began timing out. Phasing does not change how many peers start, only how
|
|
69
|
-
* many start at once, so this width is set by the burst the scheduler
|
|
70
|
-
* tolerates rather than by the barrier count.
|
|
71
|
-
*/
|
|
72
|
-
export const FANOUT_PHASE_SIZE = 4;
|
|
73
|
-
function isNimbusFanoutPeerStub(value) {
|
|
74
|
-
if ((typeof value !== 'object' && typeof value !== 'function') || value === null) {
|
|
75
|
-
return false;
|
|
76
|
-
}
|
|
77
|
-
const execute = Reflect.get(value, '_rpcFanoutExecute');
|
|
78
|
-
return typeof execute === 'function';
|
|
79
|
-
}
|
|
80
|
-
function fanoutPeerStub(value) {
|
|
81
|
-
if ((typeof value !== 'object' && typeof value !== 'function') || value === null) {
|
|
82
|
-
throw new BindingError('NimbusFanoutPool: NIMBUS_SESSION.get() did not return a peer stub.');
|
|
83
|
-
}
|
|
84
|
-
if (!isNimbusFanoutPeerStub(value)) {
|
|
85
|
-
throw new BindingError('NimbusFanoutPool: peer stub does not expose _rpcFanoutExecute().');
|
|
86
|
-
}
|
|
87
|
-
return value;
|
|
88
|
-
}
|
|
89
|
-
/**
|
|
90
|
-
* Two-tier fan-out pool. Constructed by the supervisor DO; routes
|
|
91
|
-
* each `submitMany` call automatically based on width.
|
|
92
|
-
*
|
|
93
|
-
* Lifetime: cheap to construct (no async init). Multiple submitMany
|
|
94
|
-
* calls share NO state — each is dispatched fresh. The class
|
|
95
|
-
* exists primarily as a clean API surface; per-call dispatch state
|
|
96
|
-
* lives only inside submitMany's promise.
|
|
97
|
-
*/
|
|
98
|
-
export class NimbusFanoutPool {
|
|
99
|
-
env;
|
|
100
|
-
ctx;
|
|
101
|
-
opts;
|
|
102
|
-
coordDoId;
|
|
103
|
-
coordDoIdShort;
|
|
104
|
-
constructor(env, ctx, opts) {
|
|
105
|
-
// Hard-fail on missing LOADER. NimbusLoaderPool also enforces this,
|
|
106
|
-
// but we check up front so the diagnostic points at the fanout-pool
|
|
107
|
-
// construction site rather than the deferred loader-pool one.
|
|
108
|
-
if (!env?.LOADER || typeof env.LOADER.get !== 'function') {
|
|
109
|
-
throw new BindingError('NimbusFanoutPool: env.LOADER binding missing or invalid. ' +
|
|
110
|
-
'Add a [[worker_loaders]] entry to wrangler.jsonc.');
|
|
111
|
-
}
|
|
112
|
-
this.env = env;
|
|
113
|
-
this.ctx = ctx;
|
|
114
|
-
this.opts = opts;
|
|
115
|
-
this.coordDoId = ctx.id.toString();
|
|
116
|
-
this.coordDoIdShort = this.coordDoId.slice(0, 12);
|
|
117
|
-
}
|
|
118
|
-
/**
|
|
119
|
-
* Dispatch `tasks` across the appropriate topology and return
|
|
120
|
-
* results in input order.
|
|
121
|
-
*
|
|
122
|
-
* Routing:
|
|
123
|
-
* tasks.length < 5 -> coordinator-local NimbusLoaderPool
|
|
124
|
-
* tasks.length >= 5 -> sibling NimbusSession DOs
|
|
125
|
-
*
|
|
126
|
-
* Backpressure: if `tasks.length > MAX_PEER_FANOUT (32)`, tasks
|
|
127
|
-
* are sharded modulo `MAX_PEER_FANOUT` and each shard's bucket
|
|
128
|
-
* runs serially inside its assigned peer DO via the in-peer
|
|
129
|
-
* NimbusLoaderPool's concurrency (capped at 4 there too). A
|
|
130
|
-
* single submitMany call returns when ALL tasks complete (or any
|
|
131
|
-
* throws).
|
|
132
|
-
*
|
|
133
|
-
* `fn` is the user function executed per task. It runs INSIDE a
|
|
134
|
-
* Worker Loader isolate (in the in-DO path) or inside a peer DO's
|
|
135
|
-
* Worker Loader isolate (in the peer-DO path); same trust posture
|
|
136
|
-
* as NimbusLoaderPool.submit. The function is serialized via
|
|
137
|
-
* the vendored serializeFunction (same as NimbusLoaderPool#prepare).
|
|
138
|
-
*/
|
|
139
|
-
async submitMany(tasks, fn) {
|
|
140
|
-
if (tasks.length === 0)
|
|
141
|
-
return [];
|
|
142
|
-
if (tasks.length < IN_DO_THRESHOLD) {
|
|
143
|
-
return this._dispatchInDo(tasks, fn);
|
|
144
|
-
}
|
|
145
|
-
return this._dispatchPeerDo(tasks, fn);
|
|
146
|
-
}
|
|
147
|
-
/** Report which topology a task count uses without dispatching. */
|
|
148
|
-
topologyFor(taskCount) {
|
|
149
|
-
if (taskCount === 0)
|
|
150
|
-
return 'empty';
|
|
151
|
-
return taskCount < IN_DO_THRESHOLD ? 'in-do' : 'peer-do';
|
|
152
|
-
}
|
|
153
|
-
/**
|
|
154
|
-
* Compute the deterministic peer-DO id for a task key and peer count.
|
|
155
|
-
*
|
|
156
|
-
* Shape: `nbf:${tag}:${coordDoIdShort}:${shard}` where
|
|
157
|
-
* `shard = hash(key) mod peerCount`. Peer count is
|
|
158
|
-
* `min(tasks.length, MAX_PEER_FANOUT)`.
|
|
159
|
-
*/
|
|
160
|
-
peerSiblingId(key, peerCount) {
|
|
161
|
-
const shard = hashKeyToShard(key, peerCount);
|
|
162
|
-
return `nbf:${this.opts.tag}:${this.coordDoIdShort}:${shard}`;
|
|
163
|
-
}
|
|
164
|
-
// ── Private: in-DO dispatch (in-DO fanout) ──────────────────────────────
|
|
165
|
-
async _dispatchInDo(tasks, fn) {
|
|
166
|
-
// Use the existing NimbusLoaderPool. Concurrency = task count
|
|
167
|
-
// (capped at 4 by constructor — tasks.length is already < 5
|
|
168
|
-
// here, so the cap won't bite). Each task = one pool.submit;
|
|
169
|
-
// pool.map runs them with stable-slot reuse.
|
|
170
|
-
const concurrency = Math.min(tasks.length, IN_DO_THRESHOLD - 1);
|
|
171
|
-
const pool = new NimbusLoaderPool(this.env, this.ctx, {
|
|
172
|
-
concurrency,
|
|
173
|
-
timeoutMs: this.opts.timeoutMs,
|
|
174
|
-
tag: this.opts.tag,
|
|
175
|
-
preamble: this.opts.preamble,
|
|
176
|
-
wasmModules: this.opts.wasmModules,
|
|
177
|
-
extraBindings: this.opts.extraBindings,
|
|
178
|
-
omitSupervisor: this.opts.omitSupervisor,
|
|
179
|
-
supervisorPid: this.opts.supervisorPid,
|
|
180
|
-
});
|
|
181
|
-
try {
|
|
182
|
-
// pool.map runs the function over `items` with concurrency-bounded
|
|
183
|
-
// slot reuse. Each slot is one warm loader isolate; we get exactly
|
|
184
|
-
// `concurrency` loader isolates total — well under the 4-cap.
|
|
185
|
-
const items = tasks.map((t) => t.args);
|
|
186
|
-
const results = await pool.map(fn, items);
|
|
187
|
-
// pool.map returns Array<R | null> (null on per-item failure with
|
|
188
|
-
// onError='null'/'skip'). Default onError='throw' rejects on
|
|
189
|
-
// first failure, so successful settle here implies all R values.
|
|
190
|
-
return results;
|
|
191
|
-
}
|
|
192
|
-
finally {
|
|
193
|
-
try {
|
|
194
|
-
pool.dispose();
|
|
195
|
-
}
|
|
196
|
-
catch { /* best-effort */ }
|
|
197
|
-
}
|
|
198
|
-
}
|
|
199
|
-
// ── Private: peer-DO dispatch (peer-DO fanout) ────────────────────────────
|
|
200
|
-
async _dispatchPeerDo(tasks, fn) {
|
|
201
|
-
const ns = this.env?.NIMBUS_SESSION;
|
|
202
|
-
if (!ns || typeof ns.idFromName !== 'function' || typeof ns.get !== 'function') {
|
|
203
|
-
throw new BindingError('NimbusFanoutPool: env.NIMBUS_SESSION binding missing or invalid. ' +
|
|
204
|
-
'The peer-DO topology requires it. ' +
|
|
205
|
-
'Add the binding via durable_objects.bindings in wrangler.jsonc.');
|
|
206
|
-
}
|
|
207
|
-
// Serialize the user function ONCE here on the supervisor side.
|
|
208
|
-
// Each peer DO receives the same fnSource string; warm peer
|
|
209
|
-
// loader isolates (keyed on fnHash) reuse across calls with
|
|
210
|
-
// identical fns.
|
|
211
|
-
const fnSource = serializeFunction(fn);
|
|
212
|
-
// Cap peer count at MAX_PEER_FANOUT. Tasks beyond N=32 are
|
|
213
|
-
// bucketed into existing shards — each shard's peer DO then
|
|
214
|
-
// runs its bucket through its in-DO NimbusLoaderPool.map
|
|
215
|
-
// (concurrency capped at 4 there).
|
|
216
|
-
const peerCount = Math.min(tasks.length, this.opts.maxPeers ?? MAX_PEER_FANOUT);
|
|
217
|
-
// Group tasks by deterministic shard. Same key → same shard, so
|
|
218
|
-
// tests can predict which peer handles which task.
|
|
219
|
-
const shards = new Map();
|
|
220
|
-
for (const t of tasks) {
|
|
221
|
-
const shard = hashKeyToShard(t.key, peerCount);
|
|
222
|
-
let bucket = shards.get(shard);
|
|
223
|
-
if (!bucket) {
|
|
224
|
-
bucket = [];
|
|
225
|
-
shards.set(shard, bucket);
|
|
226
|
-
}
|
|
227
|
-
bucket.push(t);
|
|
228
|
-
}
|
|
229
|
-
// Dispatch each shard to its peer DO. Build a map from
|
|
230
|
-
// task → its place in the original tasks array so we can
|
|
231
|
-
// reassemble results in input order.
|
|
232
|
-
const taskIndex = new Map();
|
|
233
|
-
tasks.forEach((t, i) => taskIndex.set(t, i));
|
|
234
|
-
const results = new Array(tasks.length);
|
|
235
|
-
// Build one async dispatcher per shard (closure capturing siblingName,
|
|
236
|
-
// bucket). NOT eagerly-started — wrapped in a thunk so we can stagger
|
|
237
|
-
// dispatch via Promise chains without forcing all shards to start
|
|
238
|
-
// simultaneously.
|
|
239
|
-
const dispatchers = [];
|
|
240
|
-
for (const [shard, bucket] of shards) {
|
|
241
|
-
const siblingName = `nbf:${this.opts.tag}:${this.coordDoIdShort}:${shard}`;
|
|
242
|
-
const id = ns.idFromName(siblingName);
|
|
243
|
-
const peerArgs = bucket.map((t) => t.args);
|
|
244
|
-
dispatchers.push(async () => {
|
|
245
|
-
for (let attempt = 0;; attempt++) {
|
|
246
|
-
// Fresh stub per attempt: after a transient reset the previous
|
|
247
|
-
// stub points at a torn-down object, so a retry re-resolves the
|
|
248
|
-
// sibling by its stable id.
|
|
249
|
-
const peerStub = ns.get(id);
|
|
250
|
-
const stub = fanoutPeerStub(peerStub);
|
|
251
|
-
try {
|
|
252
|
-
// Each peer DO RPC call uses ONE LOADER worker on its side.
|
|
253
|
-
// Supervisor → peer DO is a stub.fetch / RPC method call,
|
|
254
|
-
// NOT an env.LOADER.get(); that's the cap-sidestep that
|
|
255
|
-
// makes peer-DO fanout work.
|
|
256
|
-
const rpcResp = await stub._rpcFanoutExecute(fnSource, peerArgs, {
|
|
257
|
-
tag: this.opts.tag,
|
|
258
|
-
timeoutMs: this.opts.timeoutMs,
|
|
259
|
-
preamble: this.opts.preamble,
|
|
260
|
-
wasmModules: this.opts.wasmModules,
|
|
261
|
-
extraBindings: this.opts.extraBindings,
|
|
262
|
-
omitSupervisor: this.opts.omitSupervisor,
|
|
263
|
-
// INSTALL-HONESTY: forward the COORDINATOR's full doId so
|
|
264
|
-
// the peer's NimbusLoaderPool can mint a SUPERVISOR
|
|
265
|
-
// binding that routes back HERE (the user's session DO),
|
|
266
|
-
// not to the peer DO itself. Without this, peer DOs'
|
|
267
|
-
// env.SUPERVISOR.writeBatch / writeBatchStream / stdout /
|
|
268
|
-
// ... write into the peer's own VFS — invisible to the
|
|
269
|
-
// user. See INSTALL-HONESTY-retro.md.
|
|
270
|
-
coordinatorDoId: this.coordDoId,
|
|
271
|
-
// Credential source for peer-side writeBatchStream — the
|
|
272
|
-
// invoking process pid, so package writes are authorized
|
|
273
|
-
// as the user (not rejected as pid:0).
|
|
274
|
-
supervisorPid: this.opts.supervisorPid,
|
|
275
|
-
});
|
|
276
|
-
try {
|
|
277
|
-
const peerResults = rpcResp.results ?? [];
|
|
278
|
-
if (peerResults.length !== bucket.length) {
|
|
279
|
-
throw new Error(`peer DO returned ${peerResults.length} results for ${bucket.length} tasks ` +
|
|
280
|
-
`(siblingName=${siblingName})`);
|
|
281
|
-
}
|
|
282
|
-
// Place each result back into its original input slot.
|
|
283
|
-
for (let i = 0; i < bucket.length; i++) {
|
|
284
|
-
const origIdx = taskIndex.get(bucket[i]);
|
|
285
|
-
if (origIdx === undefined) {
|
|
286
|
-
throw new Error(`peer DO result had no original task index (siblingName=${siblingName})`);
|
|
287
|
-
}
|
|
288
|
-
results[origIdx] = peerResults[i];
|
|
289
|
-
}
|
|
290
|
-
}
|
|
291
|
-
finally {
|
|
292
|
-
disposeRpcResource(rpcResp);
|
|
293
|
-
}
|
|
294
|
-
return;
|
|
295
|
-
}
|
|
296
|
-
catch (err) {
|
|
297
|
-
const schedule = isTransientDoReset(err) ? PEER_RETRY_BACKOFF_MS
|
|
298
|
-
: isDoOverloaded(err) ? PEER_OVERLOAD_BACKOFF_MS
|
|
299
|
-
: null;
|
|
300
|
-
if (schedule && attempt < PEER_TRANSIENT_RESET_RETRIES) {
|
|
301
|
-
const backoff = schedule[Math.min(attempt, schedule.length - 1)];
|
|
302
|
-
await new Promise((r) => setTimeout(r, backoff));
|
|
303
|
-
continue;
|
|
304
|
-
}
|
|
305
|
-
// Re-throwing bare loses everything only this frame knows: which
|
|
306
|
-
// sibling ran the shard, how wide it was, and how many attempts
|
|
307
|
-
// it already cost. Callers report the message, so a rejection the
|
|
308
|
-
// platform words as `internal error` arrived at the user with no
|
|
309
|
-
// way to tell a one-off peer from a shard that had exhausted its
|
|
310
|
-
// retries. `cause` keeps the original for anything that inspects
|
|
311
|
-
// errors rather than reads them.
|
|
312
|
-
throw new Error(`peer shard ${siblingName} (${bucket.length} task${bucket.length === 1 ? '' : 's'}) `
|
|
313
|
-
+ `failed after ${attempt + 1} attempt${attempt === 0 ? '' : 's'}: ${describeError(err)}`, { cause: err });
|
|
314
|
-
}
|
|
315
|
-
finally {
|
|
316
|
-
disposeRpcResource(peerStub);
|
|
317
|
-
}
|
|
318
|
-
}
|
|
319
|
-
});
|
|
320
|
-
}
|
|
321
|
-
// Dispatch peer shards in bounded phases. A single Promise.all across all
|
|
322
|
-
// shards can create too many simultaneous cold sibling DO starts under
|
|
323
|
-
// concurrent installs. Promise-chain phasing limits scheduler pressure
|
|
324
|
-
// without sleeps, timers, or idle gaps between phases.
|
|
325
|
-
//
|
|
326
|
-
// A phase is a hard barrier: no shard in phase N+1 starts until every
|
|
327
|
-
// shard in phase N returns, so `width@ms` per phase is what separates
|
|
328
|
-
// "the shards are slow" from "there are too many barriers".
|
|
329
|
-
for (let i = 0; i < dispatchers.length; i += FANOUT_PHASE_SIZE) {
|
|
330
|
-
const phase = dispatchers.slice(i, i + FANOUT_PHASE_SIZE);
|
|
331
|
-
const phaseStartedAt = Date.now();
|
|
332
|
-
await Promise.all(phase.map((d) => d()));
|
|
333
|
-
this.opts.onDispatchPhase?.(phase.length, Date.now() - phaseStartedAt);
|
|
334
|
-
}
|
|
335
|
-
return results;
|
|
336
|
-
}
|
|
337
|
-
}
|
|
338
|
-
/**
|
|
339
|
-
* Stable hash → shard. Uses a fresh djb2 over the key (NOT
|
|
340
|
-
* hashSource) and modulos by peerCount.
|
|
341
|
-
*
|
|
342
|
-
* Why not reuse hashSource: hashSource returns a base-36 string,
|
|
343
|
-
* NOT hex — its alphabet is `[0-9a-z]`. parseInt(str, 16) on a
|
|
344
|
-
* base-36 string aborts at the first non-hex char (any of g-z),
|
|
345
|
-
* which produces extremely poor distribution: keys with the same
|
|
346
|
-
* leading-hex-prefix collide regardless of their suffix. (Seen in
|
|
347
|
-
* the wild: `task-0 .. task-7` all collided onto shard 4.)
|
|
348
|
-
*
|
|
349
|
-
* Deterministic: same key + same peerCount → same shard, every run.
|
|
350
|
-
* Tests use this to predict placement.
|
|
351
|
-
*/
|
|
352
|
-
export function hashKeyToShard(key, peerCount) {
|
|
353
|
-
if (peerCount <= 1)
|
|
354
|
-
return 0;
|
|
355
|
-
// djb2, returning an unsigned 32-bit integer — full 2^32 range,
|
|
356
|
-
// no string-format conversion gotchas. peerCount <= MAX_PEER_FANOUT
|
|
357
|
-
// (32) << 2^32, so the modulo distributes uniformly for any input.
|
|
358
|
-
let h = 5381;
|
|
359
|
-
for (let i = 0; i < key.length; i++) {
|
|
360
|
-
h = ((h << 5) + h + key.charCodeAt(i)) | 0;
|
|
361
|
-
}
|
|
362
|
-
return (h >>> 0) % peerCount;
|
|
363
|
-
}
|
|
@@ -1,294 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* loader-pool.ts — Nimbus loader-isolate pool based on cloudflare-parallel.
|
|
3
|
-
*
|
|
4
|
-
* Adds Nimbus-specific behavior to the upstream pool design:
|
|
5
|
-
* 1. **Stable-slot isolate reuse**. Upstream's #counter++ gives every
|
|
6
|
-
* dispatch a fresh isolate — fine for one-off AI calls, terrible for
|
|
7
|
-
* running 67 npm tarball extractions (cold-start dominates). We pin
|
|
8
|
-
* each job to `slot = cursor % concurrency` and use stable loader
|
|
9
|
-
* IDs `nfp:${fnHash}:slot-${i}:g${generation}`, so a pool of
|
|
10
|
-
* concurrency=4 keeps at most 4 warm isolates rather than N fresh ones.
|
|
11
|
-
* 2. **Nimbus defaults**: compatibilityDate = CF_COMPAT_DATE (matches
|
|
12
|
-
* the supervisor worker), compatibilityFlags = ['nodejs_compat'],
|
|
13
|
-
* globalOutbound = undefined (inherit parent network so the facet can
|
|
14
|
-
* reach https://registry.npmjs.org without a proxy binding).
|
|
15
|
-
* 3. **SupervisorRPC autoinjection**. The pool grabs a SupervisorRPC
|
|
16
|
-
* stub from `getCtxExports()` and forwards it as `env.SUPERVISOR` to
|
|
17
|
-
* every facet, same pattern as git-network-facet.ts. Callers can add
|
|
18
|
-
* more bindings via `extraBindings`.
|
|
19
|
-
* 4. **Fail-loud defaults**: timeout 60s, retries 0, onError 'throw'.
|
|
20
|
-
* Caller opts in to leniency.
|
|
21
|
-
*
|
|
22
|
-
* The vendored directory contains only the upstream serialization, error,
|
|
23
|
-
* and binding types used by this implementation.
|
|
24
|
-
*/
|
|
25
|
-
/** Options handed to NimbusLoaderPool's constructor. */
|
|
26
|
-
export interface NimbusLoaderPoolOptions {
|
|
27
|
-
/** Maximum concurrent in-flight facets. Default 4. */
|
|
28
|
-
concurrency?: number;
|
|
29
|
-
/** Per-task timeout in ms. Default 60_000. */
|
|
30
|
-
timeoutMs?: number;
|
|
31
|
-
/**
|
|
32
|
-
* Per-task retry attempts AFTER the initial failure. Default 0.
|
|
33
|
-
* Set to a small number only if transient RPC errors are common.
|
|
34
|
-
*/
|
|
35
|
-
retries?: number;
|
|
36
|
-
/**
|
|
37
|
-
* Additional bindings forwarded to each facet. These merge on top of the
|
|
38
|
-
* default `{ SUPERVISOR: SupervisorRPC({ doId, pid:0 }) }`. Use this to
|
|
39
|
-
* give facets access to KV, R2, AI, or additional supervisor-level APIs.
|
|
40
|
-
*/
|
|
41
|
-
extraBindings?: Record<string, unknown>;
|
|
42
|
-
/**
|
|
43
|
-
* Optional tag used in loader IDs for debugging (e.g. "npm-install").
|
|
44
|
-
* Does NOT affect isolate identity — same fn + same tag = same slot.
|
|
45
|
-
*/
|
|
46
|
-
tag?: string;
|
|
47
|
-
/**
|
|
48
|
-
* If true, omit the default SupervisorRPC binding. Use this for pools
|
|
49
|
-
* that don't need DO callbacks (e.g. a pure CPU compute pool).
|
|
50
|
-
*/
|
|
51
|
-
omitSupervisor?: boolean;
|
|
52
|
-
/**
|
|
53
|
-
* Loader cache scope. Defaults to `session`, which bakes the owning DO id
|
|
54
|
-
* into the loader key so stateful facets cannot leak bindings or globals
|
|
55
|
-
* across sessions. Use `global` only for stateless compute modules that do
|
|
56
|
-
* not receive a Supervisor binding and do not retain user state.
|
|
57
|
-
*/
|
|
58
|
-
cacheScope?: 'session' | 'global';
|
|
59
|
-
/**
|
|
60
|
-
* Override the `doId` baked into the auto-injected SUPERVISOR binding.
|
|
61
|
-
* Default: `ctx.id.toString()` (the DO that constructs the pool).
|
|
62
|
-
*
|
|
63
|
-
* Used by NimbusFanoutPool's peer-DO branch (peer-DO fanout): peer DOs
|
|
64
|
-
* construct their per-task NimbusLoaderPool from inside
|
|
65
|
-
* `_rpcFanoutExecute`, where `ctx` is the PEER DO's ctx. Without this
|
|
66
|
-
* override the peer's auto-injected SUPERVISOR routes back to the
|
|
67
|
-
* peer DO itself — so writes (e.g. install-batch-facet's
|
|
68
|
-
* writeBatchStream) land in the peer's VFS instead of the
|
|
69
|
-
* COORDINATOR's. The user's terminal session is on the coordinator;
|
|
70
|
-
* writes-to-peer are invisible. See INSTALL-HONESTY-retro.md.
|
|
71
|
-
*
|
|
72
|
-
* When set, the auto-injected SupervisorRPC uses this string as the
|
|
73
|
-
* `props.doId`, routing all SUPERVISOR.* calls back to the
|
|
74
|
-
* coordinator. Effective only when `omitSupervisor !== true`.
|
|
75
|
-
*/
|
|
76
|
-
supervisorDoIdOverride?: string;
|
|
77
|
-
/**
|
|
78
|
-
* Process pid baked into the auto-injected SUPERVISOR binding's props.
|
|
79
|
-
* The supervisor derives the write credential from this pid
|
|
80
|
-
* (`SupervisorRPC._pid()` → `processes.cred(pid)`), so any facet that
|
|
81
|
-
* calls a filesystem RPC (`writeBatchStream`, `writeFile`, …) must be
|
|
82
|
-
* dispatched with the invoking process's real pid — otherwise the RPC
|
|
83
|
-
* throws "missing or invalid process pid in props". npm install threads
|
|
84
|
-
* the shell command's `ctx.pid` here so package files land as the user.
|
|
85
|
-
* Left 0 (default) for pools whose facets touch only cache/registry RPCs
|
|
86
|
-
* (npm resolve, pre-bundle), which never call `_pid()`.
|
|
87
|
-
*/
|
|
88
|
-
supervisorPid?: number;
|
|
89
|
-
/**
|
|
90
|
-
* Raw JavaScript source prepended to every generated worker module.
|
|
91
|
-
* Lets callers inject bundled helpers, such as a tar parser. The user
|
|
92
|
-
* function can reference top-level names declared in the preamble as if
|
|
93
|
-
* they were in lexical scope.
|
|
94
|
-
*
|
|
95
|
-
* Example: `preamble: 'export const parse = ...; const helper = ...;'`
|
|
96
|
-
* — the preamble runs at module-load time; any side effects happen
|
|
97
|
-
* inside the facet isolate.
|
|
98
|
-
*
|
|
99
|
-
* Preamble text is bytes-stable for a given pool — it's part of the
|
|
100
|
-
* loader-cache key (fnHash), so changing the preamble invalidates all
|
|
101
|
-
* warm slots.
|
|
102
|
-
*/
|
|
103
|
-
preamble?: string;
|
|
104
|
-
/**
|
|
105
|
-
* WebAssembly modules to ship into the facet via the LOADER's
|
|
106
|
-
* `modules` map. Map keys are module specifier paths (e.g.
|
|
107
|
-
* `'esbuild.wasm'`); values are the raw bytes.
|
|
108
|
-
*
|
|
109
|
-
* Workerd registers each entry as `{ wasm: ArrayBuffer }` in the
|
|
110
|
-
* worker's modules map. The pool prepends a static
|
|
111
|
-
* `import __NIMBUS_WASM_<id> from './<key>';` to the generated
|
|
112
|
-
* worker.js so workerd compiles each at module-load (startup phase,
|
|
113
|
-
* where wasm code generation is permitted). The compiled Modules
|
|
114
|
-
* are exposed via `globalThis.__NIMBUS_WASM[<key>]` for the user
|
|
115
|
-
* function to read at request time.
|
|
116
|
-
*
|
|
117
|
-
* Why this works when other paths don't:
|
|
118
|
-
* - request-time `WebAssembly.compile()` — disallowed by workerd
|
|
119
|
-
* in this deploy.
|
|
120
|
-
* - request-time RPC of a pre-compiled Module — workerd
|
|
121
|
-
* structured-clone refuses ("Unable to deserialize cloned data").
|
|
122
|
-
* - inlining bytes in the preamble — 16 MiB string per dispatch
|
|
123
|
-
* OOMs the supervisor at module-source allocation time.
|
|
124
|
-
* - LOADER modules-map (this) — bytes ride INSIDE the worker code
|
|
125
|
-
* blob; workerd compiles wasm during its own startup pipeline,
|
|
126
|
-
* never crossing structured-clone, never executing JS eval.
|
|
127
|
-
*
|
|
128
|
-
* The bytes ARE part of the loader-cache key (workerd hashes the
|
|
129
|
-
* whole WorkerCode), so changing the wasm bytes invalidates warm
|
|
130
|
-
* slots — desirable when the bundled wasm version changes.
|
|
131
|
-
*/
|
|
132
|
-
wasmModules?: Record<string, ArrayBuffer>;
|
|
133
|
-
}
|
|
134
|
-
/** Per-call override (merged with pool defaults). */
|
|
135
|
-
export interface NimbusLoaderCallOptions {
|
|
136
|
-
timeoutMs?: number;
|
|
137
|
-
retries?: number;
|
|
138
|
-
/**
|
|
139
|
-
* Per-call WebAssembly modules. Merged with the pool's
|
|
140
|
-
* constructor-time `wasmModules` at dispatch time and shipped via
|
|
141
|
-
* the LOADER's modules map (same `{ wasm: ArrayBuffer }` shape).
|
|
142
|
-
*
|
|
143
|
-
* Shipping path validated empirically against prod (see
|
|
144
|
-
* `WebAssembly.instantiate(bytes)` is blocked at request-time but
|
|
145
|
-
* the LOADER-modules path compiles bytes during the inner
|
|
146
|
-
* worker's module-load phase, where wasm code generation IS
|
|
147
|
-
* permitted. The bytes ride INSIDE the worker code blob; workerd
|
|
148
|
-
* never crosses structured-clone, never executes user-eval.
|
|
149
|
-
*
|
|
150
|
-
* Cache key impact: per-call bytes are fingerprinted (length +
|
|
151
|
-
* first/last byte per module) and folded into the loader cache
|
|
152
|
-
* key. Identical bytes on the same slot → warm reuse; different
|
|
153
|
-
* bytes → fresh isolate. The pool's existing `wasmHash` field
|
|
154
|
-
* captures CONSTRUCTOR-time bytes only; per-call bytes get an
|
|
155
|
-
* independent fingerprint mixed into the slot id at dispatch.
|
|
156
|
-
*
|
|
157
|
-
* Naming collision rule: a per-call key MUST NOT collide with a
|
|
158
|
-
* constructor-time key (after identifier sanitisation). The
|
|
159
|
-
* dispatch path throws BindingError if it does — silently
|
|
160
|
-
* shadowing the constructor's wasm would break the cache-key
|
|
161
|
-
* invariant downstream callers rely on.
|
|
162
|
-
*
|
|
163
|
-
* Used by the `wasm-runner` shell command in src/runtime/
|
|
164
|
-
* wasm-runner.ts to ship user-supplied .wasm bytes from VFS into
|
|
165
|
-
* a fresh facet isolate per invocation.
|
|
166
|
-
*/
|
|
167
|
-
wasmModules?: Record<string, ArrayBuffer>;
|
|
168
|
-
}
|
|
169
|
-
/** Per-map override. Adds onError strategy for partial failures. */
|
|
170
|
-
export interface NimbusLoaderMapOptions extends NimbusLoaderCallOptions {
|
|
171
|
-
/** Concurrency override for this call. Defaults to pool's concurrency. */
|
|
172
|
-
concurrency?: number;
|
|
173
|
-
/**
|
|
174
|
-
* What to do when an individual item fails:
|
|
175
|
-
* - 'throw' (default): reject whole map on first failure.
|
|
176
|
-
* - 'null': replace failed items with null in the result array.
|
|
177
|
-
* - 'skip': omit failed items from the result array.
|
|
178
|
-
* We default to 'throw' — install-time failures are not silently ignored.
|
|
179
|
-
*/
|
|
180
|
-
onError?: 'throw' | 'null' | 'skip';
|
|
181
|
-
}
|
|
182
|
-
export interface LoaderWorkerModuleSourceOptions {
|
|
183
|
-
fnSource: string;
|
|
184
|
-
preamble?: string;
|
|
185
|
-
wasmEntries?: ReadonlyArray<{
|
|
186
|
-
name: string;
|
|
187
|
-
id: string;
|
|
188
|
-
}>;
|
|
189
|
-
hasBindings: boolean;
|
|
190
|
-
}
|
|
191
|
-
/** Assemble the exact JavaScript module parsed by a dynamic loader worker. */
|
|
192
|
-
export declare function assembleLoaderWorkerModuleSource(options: LoaderWorkerModuleSourceOptions): string;
|
|
193
|
-
/**
|
|
194
|
-
* Nimbus-scoped parallel dispatch over `env.LOADER`. Tasks are pure
|
|
195
|
-
* functions whose last argument is an `env` object containing the
|
|
196
|
-
* forwarded bindings (default: `{ SUPERVISOR }`).
|
|
197
|
-
*
|
|
198
|
-
* Typical use:
|
|
199
|
-
*
|
|
200
|
-
* const pool = new NimbusLoaderPool(env, ctx, {
|
|
201
|
-
* concurrency: 4,
|
|
202
|
-
* tag: 'npm-install',
|
|
203
|
-
* });
|
|
204
|
-
* const results = await pool.map(
|
|
205
|
-
* async (pkg, env) => env.SUPERVISOR.writeBatch(buildPayload(pkg)),
|
|
206
|
-
* toFetch,
|
|
207
|
-
* );
|
|
208
|
-
*/
|
|
209
|
-
export declare class NimbusLoaderPool {
|
|
210
|
-
#private;
|
|
211
|
-
private readonly loader;
|
|
212
|
-
private readonly concurrency;
|
|
213
|
-
private readonly defaultTimeoutMs;
|
|
214
|
-
private readonly defaultRetries;
|
|
215
|
-
private readonly tag;
|
|
216
|
-
private readonly slotGenerations;
|
|
217
|
-
private bindings;
|
|
218
|
-
private readonly preamble;
|
|
219
|
-
private readonly preambleHash;
|
|
220
|
-
/**
|
|
221
|
-
* WASM modules to ship in the LOADER `modules` map. See
|
|
222
|
-
* NimbusLoaderPoolOptions.wasmModules for the rationale. Stored in
|
|
223
|
-
* insertion order so the per-import preamble we generate matches
|
|
224
|
-
* across pool dispatches (cache-key stability).
|
|
225
|
-
*/
|
|
226
|
-
private readonly wasmModules;
|
|
227
|
-
/** Hash of (name + byte length + first/last bytes) of every wasm
|
|
228
|
-
* module, folded into the loader cache key so changes invalidate
|
|
229
|
-
* warm slots. Hashing the FULL bytes would be O(20+ MiB) per dispatch
|
|
230
|
-
* and is unnecessary — wasm bytes are pinned at deploy time, the
|
|
231
|
-
* length+endpoints are a strong-enough fingerprint. */
|
|
232
|
-
private readonly wasmHash;
|
|
233
|
-
/**
|
|
234
|
-
* Short prefix of the owning DO's id, baked into the loader.get()
|
|
235
|
-
* cache key so warm isolates are scoped to ONE session. Without this,
|
|
236
|
-
* session A's pool and session B's pool (same `tag` + `fnHash`) share
|
|
237
|
-
* an isolate — which means B's writeBatch RPCs routed through A's
|
|
238
|
-
* env.SUPERVISOR binding (minted with A's doId at construction
|
|
239
|
-
* time). B's install reports success but the writes land in A's VFS,
|
|
240
|
-
* leaving B with only the git-clone seed files (~119 instead of ~1491).
|
|
241
|
-
* 12 chars is enough entropy for DO ids to collide-free per process.
|
|
242
|
-
*/
|
|
243
|
-
private readonly doIdShort;
|
|
244
|
-
constructor(env: any, ctx: DurableObjectState, opts?: NimbusLoaderPoolOptions);
|
|
245
|
-
/** Effective concurrency used when no per-call override is supplied. */
|
|
246
|
-
get defaultConcurrency(): number;
|
|
247
|
-
/**
|
|
248
|
-
* Run `fn` once with `arg` on a slot isolate. Returns the result or
|
|
249
|
-
* throws TimeoutError / RetryExhaustedError / ExecutionError.
|
|
250
|
-
*/
|
|
251
|
-
submit<T, R>(fn: (arg: T, env: any) => R | Promise<R>, arg: T, opts?: NimbusLoaderCallOptions): Promise<Awaited<R>>;
|
|
252
|
-
/**
|
|
253
|
-
* Run `fn` on every item in `items`, at most `concurrency` at a time,
|
|
254
|
-
* pinned to stable slots so warm isolates are reused.
|
|
255
|
-
*
|
|
256
|
-
* Results are returned in input order. Failure handling per `onError`.
|
|
257
|
-
*/
|
|
258
|
-
map<T, R>(fn: (item: T, env: any) => R | Promise<R>, items: T[], opts?: NimbusLoaderMapOptions): Promise<Array<Awaited<R> | null>>;
|
|
259
|
-
/**
|
|
260
|
-
* Same shape as `map`, but accepts a pre-serialized function source
|
|
261
|
-
* string instead of a live function reference. Used by
|
|
262
|
-
* `NimbusFanoutPool`'s peer-DO leg, where the function was already
|
|
263
|
-
* serialized on the coordinator side and forwarded over RPC.
|
|
264
|
-
*
|
|
265
|
-
* The fnSource MUST be the output of `serializeFunction(fn)`
|
|
266
|
-
* (typically forwarded directly from a coordinator RPC). Bytes-
|
|
267
|
-
* stable invariants:
|
|
268
|
-
* - `fnHash = hashSource(fnSource)` must be deterministic so
|
|
269
|
-
* warm slots are correctly keyed.
|
|
270
|
-
* - `fnSource` must NOT reference `this` — same rule as
|
|
271
|
-
* `serializeFunction`.
|
|
272
|
-
*
|
|
273
|
-
* No fn-validation runs here (it already ran on the coordinator);
|
|
274
|
-
* the peer trusts the caller to forward a valid serialization.
|
|
275
|
-
*/
|
|
276
|
-
mapSource<T, R>(fnSource: string, items: T[], opts?: NimbusLoaderMapOptions): Promise<Array<Awaited<R> | null>>;
|
|
277
|
-
/**
|
|
278
|
-
* Release any RPC stubs held by the pool. Call this once the caller
|
|
279
|
-
* is done with the pool (post-`map`/`submit`) so the underlying
|
|
280
|
-
* stubs don't linger in workerd's deferred-destruction queue.
|
|
281
|
-
*
|
|
282
|
-
* Primary target: the SUPERVISOR binding stub we minted at
|
|
283
|
-
* construction time (via `ctxExports.SupervisorRPC({props})`). It's
|
|
284
|
-
* a cross-isolate RPC stub — without explicit disposal it stays
|
|
285
|
-
* referenced until the parent isolate's event-handler context
|
|
286
|
-
* finishes, which during npm install means "until the whole install
|
|
287
|
-
* completes" — long enough to accumulate alongside other leaked
|
|
288
|
-
* stubs and trip the QueueState::ACTIVE fatal.
|
|
289
|
-
*
|
|
290
|
-
* Safe to call more than once; idempotent.
|
|
291
|
-
*/
|
|
292
|
-
dispose(): void;
|
|
293
|
-
}
|
|
294
|
-
//# sourceMappingURL=loader-pool.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"loader-pool.d.ts","sourceRoot":"","sources":["../../src/loaders/loader-pool.ts"],"names":[],"mappings":"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"}
|