@glubean/runner 0.5.0 → 0.8.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/engine-bridge.d.ts +55 -0
- package/dist/engine-bridge.d.ts.map +1 -0
- package/dist/engine-bridge.js +219 -0
- package/dist/engine-bridge.js.map +1 -0
- package/dist/executor.d.ts +70 -2
- package/dist/executor.d.ts.map +1 -1
- package/dist/executor.js +21 -226
- package/dist/executor.js.map +1 -1
- package/dist/generate_summary.d.ts +15 -0
- package/dist/generate_summary.d.ts.map +1 -1
- package/dist/generate_summary.js +52 -1
- package/dist/generate_summary.js.map +1 -1
- package/dist/harness.js +257 -21
- package/dist/harness.js.map +1 -1
- package/dist/index.d.ts +24 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +24 -0
- package/dist/index.js.map +1 -1
- package/dist/load/continuation-pool.d.ts +82 -0
- package/dist/load/continuation-pool.d.ts.map +1 -0
- package/dist/load/continuation-pool.js +154 -0
- package/dist/load/continuation-pool.js.map +1 -0
- package/dist/load/execute-iteration.d.ts +126 -0
- package/dist/load/execute-iteration.d.ts.map +1 -0
- package/dist/load/execute-iteration.js +367 -0
- package/dist/load/execute-iteration.js.map +1 -0
- package/dist/load/histogram.d.ts +63 -0
- package/dist/load/histogram.d.ts.map +1 -0
- package/dist/load/histogram.js +149 -0
- package/dist/load/histogram.js.map +1 -0
- package/dist/load/orchestrator.d.ts +55 -0
- package/dist/load/orchestrator.d.ts.map +1 -0
- package/dist/load/orchestrator.js +571 -0
- package/dist/load/orchestrator.js.map +1 -0
- package/dist/load/reducer.d.ts +109 -0
- package/dist/load/reducer.d.ts.map +1 -0
- package/dist/load/reducer.js +718 -0
- package/dist/load/reducer.js.map +1 -0
- package/dist/load/route-key.d.ts +38 -0
- package/dist/load/route-key.d.ts.map +1 -0
- package/dist/load/route-key.js +107 -0
- package/dist/load/route-key.js.map +1 -0
- package/dist/load/samples.d.ts +83 -0
- package/dist/load/samples.d.ts.map +1 -0
- package/dist/load/samples.js +269 -0
- package/dist/load/samples.js.map +1 -0
- package/dist/load/sink.d.ts +127 -0
- package/dist/load/sink.d.ts.map +1 -0
- package/dist/load/sink.js +351 -0
- package/dist/load/sink.js.map +1 -0
- package/dist/load/subprocess.d.ts +83 -0
- package/dist/load/subprocess.d.ts.map +1 -0
- package/dist/load/subprocess.js +229 -0
- package/dist/load/subprocess.js.map +1 -0
- package/dist/load/threshold.d.ts +44 -0
- package/dist/load/threshold.d.ts.map +1 -0
- package/dist/load/threshold.js +197 -0
- package/dist/load/threshold.js.map +1 -0
- package/dist/load/timeline.d.ts +36 -0
- package/dist/load/timeline.d.ts.map +1 -0
- package/dist/load/timeline.js +158 -0
- package/dist/load/timeline.js.map +1 -0
- package/dist/load-harness.d.ts +2 -0
- package/dist/load-harness.d.ts.map +1 -0
- package/dist/load-harness.js +105 -0
- package/dist/load-harness.js.map +1 -0
- package/dist/resolve.d.ts +10 -11
- package/dist/resolve.d.ts.map +1 -1
- package/dist/resolve.js +28 -9
- package/dist/resolve.js.map +1 -1
- package/dist/runner-resolve.d.ts +53 -0
- package/dist/runner-resolve.d.ts.map +1 -0
- package/dist/runner-resolve.js +264 -0
- package/dist/runner-resolve.js.map +1 -0
- package/dist/workflow/event-timeline.d.ts +3 -0
- package/dist/workflow/event-timeline.d.ts.map +1 -0
- package/dist/workflow/event-timeline.js +72 -0
- package/dist/workflow/event-timeline.js.map +1 -0
- package/dist/workflow/execute.d.ts +267 -0
- package/dist/workflow/execute.d.ts.map +1 -0
- package/dist/workflow/execute.js +1475 -0
- package/dist/workflow/execute.js.map +1 -0
- package/package.json +8 -4
|
@@ -0,0 +1,571 @@
|
|
|
1
|
+
import { parseDurationMs } from "@glubean/sdk/load";
|
|
2
|
+
import { createEngineCore } from "../engine-bridge.js";
|
|
3
|
+
import { compileLoadScenario, startLoadIteration, } from "./execute-iteration.js";
|
|
4
|
+
import { ContinuationPool } from "./continuation-pool.js";
|
|
5
|
+
import { createLoadReducer } from "./reducer.js";
|
|
6
|
+
import { LoadSink } from "./sink.js";
|
|
7
|
+
import { evaluateThresholds } from "./threshold.js";
|
|
8
|
+
/**
|
|
9
|
+
* Ramp-up start offset (ms) for a slot. `rampUp` is the time to reach FULL
|
|
10
|
+
* concurrency, so slots spread evenly across `[0, rampUp]` with the LAST slot
|
|
11
|
+
* starting at the end of the window (slot 0 at 0, slot N-1 at `rampUp`). A single
|
|
12
|
+
* slot (or no ramp) starts immediately.
|
|
13
|
+
*/
|
|
14
|
+
export function rampDelayMs(slotIndex, concurrency, rampUpMs) {
|
|
15
|
+
if (concurrency <= 1 || rampUpMs <= 0)
|
|
16
|
+
return 0;
|
|
17
|
+
return (slotIndex / (concurrency - 1)) * rampUpMs;
|
|
18
|
+
}
|
|
19
|
+
/** Deep-clone the base session for one iteration — copy-on-write isolation that
|
|
20
|
+
* also covers nested values, so a mutation in one iteration never leaks into
|
|
21
|
+
* another. (structuredClone is available on the Node runtime the runner targets.) */
|
|
22
|
+
function cloneSession(base) {
|
|
23
|
+
return structuredClone(base);
|
|
24
|
+
}
|
|
25
|
+
/** Resolve a scenario reference (un-built builder → built scenario). */
|
|
26
|
+
function resolveScenario(ref) {
|
|
27
|
+
const r = ref;
|
|
28
|
+
if (r.__glubean_type === "load-scenario-builder" && typeof r.build === "function") {
|
|
29
|
+
return r.build();
|
|
30
|
+
}
|
|
31
|
+
return ref;
|
|
32
|
+
}
|
|
33
|
+
/** Normalize a pacing config's thinkTime to ms (number or {min,max}). */
|
|
34
|
+
function normalizeThinkTime(pacing) {
|
|
35
|
+
const tt = pacing?.thinkTime;
|
|
36
|
+
if (tt === undefined)
|
|
37
|
+
return undefined;
|
|
38
|
+
if (typeof tt === "object") {
|
|
39
|
+
const min = parseDurationMs(tt.min);
|
|
40
|
+
const max = parseDurationMs(tt.max);
|
|
41
|
+
if (max < min) {
|
|
42
|
+
throw new Error(`pacing.thinkTime range is inverted: min (${min}ms) must be <= max (${max}ms)`);
|
|
43
|
+
}
|
|
44
|
+
return { min, max };
|
|
45
|
+
}
|
|
46
|
+
return parseDurationMs(tt);
|
|
47
|
+
}
|
|
48
|
+
/** A single think-time delay (random within [min,max] for a range). */
|
|
49
|
+
function thinkDelay(thinkTimeMs) {
|
|
50
|
+
if (thinkTimeMs === undefined)
|
|
51
|
+
return 0;
|
|
52
|
+
if (typeof thinkTimeMs === "number")
|
|
53
|
+
return thinkTimeMs;
|
|
54
|
+
const { min, max } = thinkTimeMs;
|
|
55
|
+
return min + Math.random() * Math.max(0, max - min);
|
|
56
|
+
}
|
|
57
|
+
function isMixConfig(config) {
|
|
58
|
+
return "scenarios" in config;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Drain the in-flight continuations from released iterations before the run
|
|
62
|
+
* finalizes. With a `drainTimeoutMs`, stop waiting once it elapses and return how
|
|
63
|
+
* many were still unsettled (abandoned) — so a continuation that never settles
|
|
64
|
+
* (e.g. an unbounded poll) can't hang an otherwise-bounded run. With no timeout,
|
|
65
|
+
* wait for them all (continuations are expected to be self-bounded via poll
|
|
66
|
+
* timeouts). The abandoned continuations keep running but are no longer awaited.
|
|
67
|
+
*/
|
|
68
|
+
async function drainContinuations(continuations, drainTimeoutMs) {
|
|
69
|
+
const inflight = [...continuations]; // snapshot the still-in-flight continuations
|
|
70
|
+
if (inflight.length === 0)
|
|
71
|
+
return 0;
|
|
72
|
+
if (drainTimeoutMs === undefined) {
|
|
73
|
+
await Promise.allSettled(inflight);
|
|
74
|
+
return 0;
|
|
75
|
+
}
|
|
76
|
+
// Track settlement so we can count what the timeout abandons.
|
|
77
|
+
let settled = 0;
|
|
78
|
+
const tracked = inflight.map((p) => p.then(() => { settled += 1; }, () => { settled += 1; }));
|
|
79
|
+
let timer;
|
|
80
|
+
const timeout = new Promise((resolve) => { timer = setTimeout(resolve, drainTimeoutMs); });
|
|
81
|
+
await Promise.race([Promise.allSettled(tracked), timeout]);
|
|
82
|
+
if (timer !== undefined)
|
|
83
|
+
clearTimeout(timer);
|
|
84
|
+
return inflight.length - settled;
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Resolve the continuation (bounded-open) config to its ms-normalized artifact
|
|
88
|
+
* form, applying the documented default backlog policy. Present only when the user
|
|
89
|
+
* configured `continuation`; the producer-release scheduling that consumes it is
|
|
90
|
+
* M6 (a bare `primaryComplete` without `releaseProducerSlot` ignores it).
|
|
91
|
+
*/
|
|
92
|
+
function resolveContinuationConfig(c) {
|
|
93
|
+
if (c === undefined)
|
|
94
|
+
return undefined;
|
|
95
|
+
return {
|
|
96
|
+
...(c.maxOutstanding !== undefined ? { maxOutstanding: c.maxOutstanding } : {}),
|
|
97
|
+
...(c.maxConcurrent !== undefined ? { maxConcurrent: c.maxConcurrent } : {}),
|
|
98
|
+
...(c.minPollInterval !== undefined ? { minPollIntervalMs: parseDurationMs(c.minPollInterval) } : {}),
|
|
99
|
+
...(c.drainTimeout !== undefined ? { drainTimeoutMs: parseDurationMs(c.drainTimeout) } : {}),
|
|
100
|
+
// When a configured backlog bound is hit the default is to back-pressure the
|
|
101
|
+
// producer (`await primaryComplete` waits for capacity); `fail-iteration` is opt-in.
|
|
102
|
+
onBacklogFull: c.onBacklogFull ?? "block-producer",
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Run a load plan locally and return its finalized `LoadArtifact`. Handles BOTH a
|
|
107
|
+
* single-scenario run and a traffic mix (`scenarios[]`): each is lowered to a list of
|
|
108
|
+
* weighted `Workload`s, and every iteration picks one (weighted-random for a mix, the
|
|
109
|
+
* sole workload otherwise). Throws on a plan with neither `duration` nor `iterations`
|
|
110
|
+
* (it would run forever). Closed model; continuation / pacing / thresholds are
|
|
111
|
+
* run-level (shared across a mix), per-scenario results attributed via each entry id.
|
|
112
|
+
*/
|
|
113
|
+
export async function runLoad(plan, opts = {}) {
|
|
114
|
+
const config = plan.config;
|
|
115
|
+
const projection = plan.projection;
|
|
116
|
+
const { concurrency, durationMs, iterations, rampUpMs } = projection;
|
|
117
|
+
if (durationMs === undefined && iterations === undefined) {
|
|
118
|
+
throw new Error(`loadRunner "${plan.id}": set \`duration\` and/or \`iterations\` — a load run needs a termination bound`);
|
|
119
|
+
}
|
|
120
|
+
if (!Number.isInteger(concurrency) || concurrency < 1) {
|
|
121
|
+
throw new Error(`loadRunner "${plan.id}": concurrency must be a positive integer (got ${concurrency})`);
|
|
122
|
+
}
|
|
123
|
+
if (iterations !== undefined && (!Number.isInteger(iterations) || iterations < 1)) {
|
|
124
|
+
throw new Error(`loadRunner "${plan.id}": iterations must be a positive integer (got ${iterations})`);
|
|
125
|
+
}
|
|
126
|
+
if (durationMs !== undefined && (!Number.isFinite(durationMs) || durationMs <= 0)) {
|
|
127
|
+
throw new Error(`loadRunner "${plan.id}": duration must resolve to a positive number of ms (got ${durationMs})`);
|
|
128
|
+
}
|
|
129
|
+
const continuationCfg = resolveContinuationConfig(config.continuation);
|
|
130
|
+
if (continuationCfg?.maxOutstanding !== undefined && (!Number.isInteger(continuationCfg.maxOutstanding) || continuationCfg.maxOutstanding < 1)) {
|
|
131
|
+
throw new Error(`loadRunner "${plan.id}": continuation.maxOutstanding must be a positive integer (got ${continuationCfg.maxOutstanding})`);
|
|
132
|
+
}
|
|
133
|
+
if (continuationCfg?.maxConcurrent !== undefined && (!Number.isInteger(continuationCfg.maxConcurrent) || continuationCfg.maxConcurrent < 1)) {
|
|
134
|
+
throw new Error(`loadRunner "${plan.id}": continuation.maxConcurrent must be a positive integer (got ${continuationCfg.maxConcurrent})`);
|
|
135
|
+
}
|
|
136
|
+
// Report sample caps bound retained samples — a non-integer / negative / Infinity cap
|
|
137
|
+
// would break the bounded-sampling guarantee. 0 is allowed (disables that sample type).
|
|
138
|
+
const failureTraceCap = config.report?.failureTraces;
|
|
139
|
+
if (failureTraceCap !== undefined && (!Number.isInteger(failureTraceCap) || failureTraceCap < 0)) {
|
|
140
|
+
throw new Error(`loadRunner "${plan.id}": report.failureTraces must be a non-negative integer (got ${failureTraceCap})`);
|
|
141
|
+
}
|
|
142
|
+
const slowSummaryCap = config.report?.slowTransactionSummaries;
|
|
143
|
+
if (slowSummaryCap !== undefined && (!Number.isInteger(slowSummaryCap) || slowSummaryCap < 0)) {
|
|
144
|
+
throw new Error(`loadRunner "${plan.id}": report.slowTransactionSummaries must be a non-negative integer (got ${slowSummaryCap})`);
|
|
145
|
+
}
|
|
146
|
+
const now = opts.now ?? (() => Date.now());
|
|
147
|
+
const runnerId = opts.runnerId ?? plan.id;
|
|
148
|
+
const runId = opts.runId ?? runnerId;
|
|
149
|
+
const baseSession = opts.baseSession ?? {};
|
|
150
|
+
// Fail fast (once) with a clear message if the base session can't be deep-cloned,
|
|
151
|
+
// rather than throwing mid-run on the first iteration's copy.
|
|
152
|
+
try {
|
|
153
|
+
cloneSession(baseSession);
|
|
154
|
+
}
|
|
155
|
+
catch (e) {
|
|
156
|
+
throw new Error(`loadRunner "${plan.id}": baseSession must be structured-cloneable (no functions / class instances): ${e instanceof Error ? e.message : String(e)}`);
|
|
157
|
+
}
|
|
158
|
+
// Lower the plan to weighted workloads (one for a single scenario, one per mix entry).
|
|
159
|
+
// The runner-level `assertions.onFailure` default is shared; each entry's scenario /
|
|
160
|
+
// step meta can still override it during compilation.
|
|
161
|
+
const compileOpts = config.assertions?.onFailure !== undefined ? { defaultOnFailure: config.assertions.onFailure } : {};
|
|
162
|
+
// One stable counter key per SHARED feeder NAME, reused across the entries that draw it, so
|
|
163
|
+
// its draws advance run-globally. Keyed by name (not the binding) so two shared names that
|
|
164
|
+
// happen to reuse the same binding object stay independent slots (and single-scenario feeders
|
|
165
|
+
// each get their own per-name sequence regardless of binding reuse).
|
|
166
|
+
const sharedCounterKeys = new Map();
|
|
167
|
+
const sharedCounterKey = (name) => {
|
|
168
|
+
let key = sharedCounterKeys.get(name);
|
|
169
|
+
if (key === undefined) {
|
|
170
|
+
key = {};
|
|
171
|
+
sharedCounterKeys.set(name, key);
|
|
172
|
+
}
|
|
173
|
+
return key;
|
|
174
|
+
};
|
|
175
|
+
const makeWorkload = (ref, weight, scenarioRefId, sharedFeeders, entryFeeders, input) => {
|
|
176
|
+
const scenario = resolveScenario(ref);
|
|
177
|
+
const entry = entryFeeders ?? {};
|
|
178
|
+
const feeders = [];
|
|
179
|
+
// Shared (top-level) feeders the entry does NOT override: keyed per NAME, shared across
|
|
180
|
+
// the non-overriding entries → one run-global draw sequence. `Object.entries` +
|
|
181
|
+
// `hasOwnProperty` are own-prop only, so a feeder named `toString` survives (a
|
|
182
|
+
// `name in entry` check would drop it via Object.prototype).
|
|
183
|
+
for (const [name, binding] of Object.entries(sharedFeeders ?? {})) {
|
|
184
|
+
if (!Object.prototype.hasOwnProperty.call(entry, name)) {
|
|
185
|
+
feeders.push({ name, binding, counterKey: sharedCounterKey(name) });
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
// The entry's own feeders (entry wins a name clash): each gets a UNIQUE marker key, so
|
|
189
|
+
// two entries reusing the same binding object still draw independent per-entry sequences.
|
|
190
|
+
for (const [name, binding] of Object.entries(entry)) {
|
|
191
|
+
feeders.push({ name, binding, counterKey: {} });
|
|
192
|
+
}
|
|
193
|
+
return {
|
|
194
|
+
scenarioId: scenario.meta.id,
|
|
195
|
+
...(scenarioRefId !== undefined ? { scenarioRefId } : {}),
|
|
196
|
+
compiled: compileLoadScenario(scenario, compileOpts),
|
|
197
|
+
feeders,
|
|
198
|
+
input,
|
|
199
|
+
weight,
|
|
200
|
+
};
|
|
201
|
+
};
|
|
202
|
+
let workloads;
|
|
203
|
+
if (isMixConfig(config)) {
|
|
204
|
+
const mix = config;
|
|
205
|
+
if (!Array.isArray(mix.scenarios) || mix.scenarios.length === 0) {
|
|
206
|
+
throw new Error(`loadRunner "${plan.id}": a traffic mix needs at least one entry in \`scenarios\``);
|
|
207
|
+
}
|
|
208
|
+
const seenIds = new Set();
|
|
209
|
+
workloads = mix.scenarios.map((entry) => {
|
|
210
|
+
if (typeof entry.id !== "string" || entry.id === "") {
|
|
211
|
+
throw new Error(`loadRunner "${plan.id}": every traffic-mix entry needs a non-empty \`id\``);
|
|
212
|
+
}
|
|
213
|
+
if (seenIds.has(entry.id)) {
|
|
214
|
+
throw new Error(`loadRunner "${plan.id}": duplicate traffic-mix entry id "${entry.id}" — ids attribute per-scenario results, so they must be unique`);
|
|
215
|
+
}
|
|
216
|
+
seenIds.add(entry.id);
|
|
217
|
+
if (!Number.isFinite(entry.weight) || entry.weight <= 0) {
|
|
218
|
+
throw new Error(`loadRunner "${plan.id}": traffic-mix entry "${entry.id}" weight must be a positive number (got ${entry.weight})`);
|
|
219
|
+
}
|
|
220
|
+
// Top-level feeders are shared (run-global draws); the entry's own are per-entry.
|
|
221
|
+
return makeWorkload(entry.scenario, entry.weight, entry.id, mix.feeders, entry.feeders, entry.input);
|
|
222
|
+
});
|
|
223
|
+
}
|
|
224
|
+
else {
|
|
225
|
+
// Single scenario: all feeders are "shared" (run-global) so the indexing is exactly
|
|
226
|
+
// the pre-mix behavior; there are no per-entry feeders.
|
|
227
|
+
const single = config;
|
|
228
|
+
workloads = [makeWorkload(single.scenario, 1, undefined, single.feeders, undefined, single.input)];
|
|
229
|
+
}
|
|
230
|
+
// Weighted scenario selection for a mix; the sole workload for a single scenario (no
|
|
231
|
+
// RNG draw, so a single-scenario run is byte-identical to before).
|
|
232
|
+
const random = opts.random ?? Math.random;
|
|
233
|
+
const totalWeight = workloads.reduce((sum, w) => sum + w.weight, 0);
|
|
234
|
+
const selectWorkload = () => {
|
|
235
|
+
if (workloads.length === 1)
|
|
236
|
+
return workloads[0];
|
|
237
|
+
let r = random() * totalWeight;
|
|
238
|
+
for (const w of workloads) {
|
|
239
|
+
r -= w.weight;
|
|
240
|
+
if (r < 0)
|
|
241
|
+
return w;
|
|
242
|
+
}
|
|
243
|
+
return workloads[workloads.length - 1]; // float-rounding safety net
|
|
244
|
+
};
|
|
245
|
+
const thinkTimeMs = normalizeThinkTime(config.pacing);
|
|
246
|
+
const reducer = createLoadReducer({
|
|
247
|
+
maxFailureTraces: config.report?.failureTraces,
|
|
248
|
+
maxSlowTransactionSummaries: config.report?.slowTransactionSummaries,
|
|
249
|
+
});
|
|
250
|
+
const sink = new LoadSink(reducer, runId, runnerId, now);
|
|
251
|
+
const core = createEngineCore(sink.handleWire, {
|
|
252
|
+
vars: opts.vars ?? {},
|
|
253
|
+
secrets: opts.secrets ?? {},
|
|
254
|
+
abortMode: config.abort ?? "precise",
|
|
255
|
+
});
|
|
256
|
+
// Run-level abort, handed to every iteration's engine run. Fired once at finalization
|
|
257
|
+
// (see the `finally` below) to truly CANCEL any continuation tail still in flight —
|
|
258
|
+
// its in-flight HTTP and engine poll/retry waits stop at once, instead of running to
|
|
259
|
+
// completion in the background after the drain phase stopped awaiting them. (Opaque
|
|
260
|
+
// user async — a bare `setTimeout` in a step — still can't be cancelled.)
|
|
261
|
+
const runAbort = new AbortController();
|
|
262
|
+
// Continuation backlog for producer release (M6). The pool bound is the tighter of
|
|
263
|
+
// maxOutstanding / maxConcurrent (every in-flight continuation is concurrently
|
|
264
|
+
// scheduled, so the two coincide); unset on both → unbounded. Default backlog
|
|
265
|
+
// policy is block-producer (back-pressure). Continuations from released iterations
|
|
266
|
+
// are drained before the run finalizes.
|
|
267
|
+
const continuationBound = continuationCfg?.maxOutstanding !== undefined && continuationCfg?.maxConcurrent !== undefined
|
|
268
|
+
? Math.min(continuationCfg.maxOutstanding, continuationCfg.maxConcurrent)
|
|
269
|
+
: continuationCfg?.maxOutstanding ?? continuationCfg?.maxConcurrent;
|
|
270
|
+
const continuationPool = new ContinuationPool(continuationBound, continuationCfg?.onBacklogFull ?? "block-producer", continuationCfg?.drainTimeoutMs, now);
|
|
271
|
+
// In-flight continuations from released iterations. A Set with settle-time removal
|
|
272
|
+
// keeps only the CURRENTLY in-flight ones, so a long / high-rate run doesn't retain
|
|
273
|
+
// every released iteration's promise until the final drain.
|
|
274
|
+
const continuations = new Set();
|
|
275
|
+
// Peak concurrent continuation tails — including deadline-released ones the pool
|
|
276
|
+
// never admitted — so the reported backlog peak isn't understated.
|
|
277
|
+
let peakContinuations = 0;
|
|
278
|
+
const trackContinuation = (p) => {
|
|
279
|
+
continuations.add(p);
|
|
280
|
+
if (continuations.size > peakContinuations)
|
|
281
|
+
peakContinuations = continuations.size;
|
|
282
|
+
void p.finally(() => continuations.delete(p));
|
|
283
|
+
};
|
|
284
|
+
// Record the traffic-mix composition so the reducer can seed a 0-iteration aggregate for
|
|
285
|
+
// every configured entry (a low-weight entry that's never selected still shows up).
|
|
286
|
+
const mixScenarios = isMixConfig(config)
|
|
287
|
+
? workloads.map((w) => ({ scenarioRefId: w.scenarioRefId, scenarioId: w.scenarioId, weight: w.weight }))
|
|
288
|
+
: undefined;
|
|
289
|
+
const resolvedConfig = {
|
|
290
|
+
concurrency,
|
|
291
|
+
...(durationMs !== undefined ? { durationMs } : {}),
|
|
292
|
+
...(iterations !== undefined ? { iterations } : {}),
|
|
293
|
+
...(rampUpMs !== undefined ? { rampUpMs } : {}),
|
|
294
|
+
...(thinkTimeMs !== undefined ? { pacing: { thinkTimeMs } } : {}),
|
|
295
|
+
...(continuationCfg !== undefined ? { continuation: continuationCfg } : {}),
|
|
296
|
+
...(mixScenarios !== undefined ? { scenarios: mixScenarios } : {}),
|
|
297
|
+
};
|
|
298
|
+
const start = now();
|
|
299
|
+
sink.emitLoadStart(resolvedConfig);
|
|
300
|
+
// Run-end coordination. Ramp-up / think-time waits are CANCELLABLE real timers:
|
|
301
|
+
// while a slot legitimately waits, its timer is ref'd (so a standalone Node run
|
|
302
|
+
// can't exit before it resolves), but the moment the run ends — iterations cap
|
|
303
|
+
// reached, or the duration deadline fires — every pending wait is cleared and
|
|
304
|
+
// resolved at once, so a slot never overruns the bound (late ramped slots that
|
|
305
|
+
// will claim nothing, or a think-time after the final iteration, wake instantly).
|
|
306
|
+
let ended = false;
|
|
307
|
+
const activeWaiters = new Map();
|
|
308
|
+
// The wall-clock (duration) deadline `closeImmediate()`s the pool: every parked
|
|
309
|
+
// producer is cancelled at once (the run's hard bound is up) and any later park is
|
|
310
|
+
// rejected immediately. The per-park `drainTimeout` bound is always-on in the pool
|
|
311
|
+
// (armed from when each producer parks, even before the run ends — so an
|
|
312
|
+
// all-producers-blocked backlog can't hang an iterations-bounded run), so the
|
|
313
|
+
// iterations cap needs no pool action here: a parked release self-bounds by its
|
|
314
|
+
// drainTimeout, or — with no drainTimeout — waits for capacity until either a
|
|
315
|
+
// continuation frees a slot or a duration deadline (if any) closes the pool.
|
|
316
|
+
const markEnded = (wallClockUp = false) => {
|
|
317
|
+
const firstEnd = !ended;
|
|
318
|
+
if (firstEnd) {
|
|
319
|
+
ended = true;
|
|
320
|
+
for (const [timer, resolve] of activeWaiters) {
|
|
321
|
+
clearTimeout(timer);
|
|
322
|
+
resolve();
|
|
323
|
+
}
|
|
324
|
+
activeWaiters.clear();
|
|
325
|
+
}
|
|
326
|
+
if (wallClockUp)
|
|
327
|
+
continuationPool.closeImmediate();
|
|
328
|
+
};
|
|
329
|
+
// A duration deadline timer wakes ramp/think waiters at the bound even if no slot
|
|
330
|
+
// happens to claim (and thus re-check) right then.
|
|
331
|
+
let deadlineTimer;
|
|
332
|
+
if (durationMs !== undefined)
|
|
333
|
+
deadlineTimer = setTimeout(() => markEnded(true), durationMs);
|
|
334
|
+
/** Wait `ms`, returning early the instant the run ends (never overruns the bound). */
|
|
335
|
+
const pausedSleep = (ms) => {
|
|
336
|
+
if (ms <= 0 || ended)
|
|
337
|
+
return Promise.resolve();
|
|
338
|
+
return new Promise((resolve) => {
|
|
339
|
+
const timer = setTimeout(() => {
|
|
340
|
+
activeWaiters.delete(timer);
|
|
341
|
+
resolve();
|
|
342
|
+
}, ms);
|
|
343
|
+
activeWaiters.set(timer, resolve);
|
|
344
|
+
});
|
|
345
|
+
};
|
|
346
|
+
// The shared, monotonically-claimed global iteration counter. A slot claims the
|
|
347
|
+
// next index before running; -1 means the run is over. Single-threaded JS makes
|
|
348
|
+
// the claim atomic.
|
|
349
|
+
let claimed = 0;
|
|
350
|
+
const durationExpired = () => durationMs !== undefined && now() - start >= durationMs;
|
|
351
|
+
const claimIteration = () => {
|
|
352
|
+
// The deadline timer can flip `ended` independently of the (possibly frozen /
|
|
353
|
+
// injected) clock, so honour it directly — not just `durationExpired()`.
|
|
354
|
+
if (ended)
|
|
355
|
+
return -1;
|
|
356
|
+
if (durationExpired()) {
|
|
357
|
+
markEnded(true); // duration bound hit on a claim → wall-clock is up
|
|
358
|
+
return -1;
|
|
359
|
+
}
|
|
360
|
+
if (iterations !== undefined && claimed >= iterations) {
|
|
361
|
+
markEnded();
|
|
362
|
+
return -1;
|
|
363
|
+
}
|
|
364
|
+
const index = claimed++;
|
|
365
|
+
// Claiming the last iteration ends the run — wake any ramp/think waiters now.
|
|
366
|
+
if (iterations !== undefined && claimed >= iterations)
|
|
367
|
+
markEnded();
|
|
368
|
+
return index;
|
|
369
|
+
};
|
|
370
|
+
/**
|
|
371
|
+
* Start one iteration's PRIMARY phase. Returns its handle (the producer slot is
|
|
372
|
+
* freed when `primaryDone` resolves), or `"skip"` (feeder opt-out, not counted) /
|
|
373
|
+
* `"failed"` (a setup failure recorded as a started+failed iteration). The slot
|
|
374
|
+
* loop awaits the handle's `primaryDone`; with producer release that resolves at
|
|
375
|
+
* the boundary so the slot can start the next primary while the continuation runs.
|
|
376
|
+
*/
|
|
377
|
+
const startOneIteration = (slotIndex, producerSlotId, globalIteration, slotIteration, workload, feederSlotDraws) => {
|
|
378
|
+
const iterationId = `it-${globalIteration}`;
|
|
379
|
+
const producerSlot = { id: producerSlotId, index: slotIndex };
|
|
380
|
+
const iteration = { id: iterationId, index: globalIteration };
|
|
381
|
+
const envelope = {
|
|
382
|
+
scenarioId: workload.scenarioId,
|
|
383
|
+
...(workload.scenarioRefId !== undefined ? { scenarioRefId: workload.scenarioRefId } : {}),
|
|
384
|
+
producerSlotId,
|
|
385
|
+
iterationId,
|
|
386
|
+
};
|
|
387
|
+
// `globalIteration`/`slotIteration` keep their public contract — the REAL run-global and
|
|
388
|
+
// per-slot iteration indices (so a custom feeder reading them is unaffected by mix
|
|
389
|
+
// scheduling). The built-in feeders index by `drawIndex`/`slotDrawIndex` instead: ITS OWN
|
|
390
|
+
// per-binding draw count, so a binding shared across entries advances run-wide while a
|
|
391
|
+
// per-entry (or partially-overridden) binding advances only when its entry runs — correct
|
|
392
|
+
// even when only some entries override a shared name (codex). For a single scenario a
|
|
393
|
+
// feeder is drawn every iteration, so its draw count equals the iteration index.
|
|
394
|
+
const drawCtxFor = (counterKey) => {
|
|
395
|
+
const g = feederGlobalDraws.get(counterKey) ?? 0;
|
|
396
|
+
feederGlobalDraws.set(counterKey, g + 1);
|
|
397
|
+
const s = feederSlotDraws.get(counterKey) ?? 0;
|
|
398
|
+
feederSlotDraws.set(counterKey, s + 1);
|
|
399
|
+
return { producerSlot: slotIndex, producerCount: concurrency, slotIteration, globalIteration, drawIndex: g, slotDrawIndex: s };
|
|
400
|
+
};
|
|
401
|
+
const failSetup = () => {
|
|
402
|
+
// A setup-time failure (feeder exhausted / input threw) still counts as a
|
|
403
|
+
// started+failed iteration so the artifact reflects it.
|
|
404
|
+
sink.beginIteration(envelope);
|
|
405
|
+
sink.emitIterationStart(envelope, {});
|
|
406
|
+
sink.emitIterationEnd(envelope, { ok: false, durationMs: 0, errorKind: "setupError" });
|
|
407
|
+
sink.endIteration(iterationId);
|
|
408
|
+
return "failed";
|
|
409
|
+
};
|
|
410
|
+
// Feeder allocation + input resolution are the iteration's SETUP. Any failure
|
|
411
|
+
// here (a feeder exhausted under `fail`, a feeder `allocate()` that throws, or a
|
|
412
|
+
// throwing `input` fn) becomes a recorded failed iteration — it must never
|
|
413
|
+
// escape and reject the whole run.
|
|
414
|
+
const feed = {};
|
|
415
|
+
const feederKeys = {};
|
|
416
|
+
let input;
|
|
417
|
+
let skipped = false;
|
|
418
|
+
try {
|
|
419
|
+
for (const { name, binding, counterKey } of workload.feeders) {
|
|
420
|
+
const draw = binding.allocate(drawCtxFor(counterKey));
|
|
421
|
+
if (draw.outcome === "value") {
|
|
422
|
+
feed[name] = draw.value;
|
|
423
|
+
if (draw.key !== undefined)
|
|
424
|
+
feederKeys[name] = draw.key;
|
|
425
|
+
}
|
|
426
|
+
else if (draw.outcome === "skip" || draw.outcome === "wait") {
|
|
427
|
+
// `skip`/`wait`: the iteration opts out (wait-and-retry isn't modelled in
|
|
428
|
+
// the closed MVP — both just skip). Not a failure, not counted.
|
|
429
|
+
skipped = true;
|
|
430
|
+
break;
|
|
431
|
+
}
|
|
432
|
+
else {
|
|
433
|
+
return failSetup(); // exhausted (fail policy)
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
if (skipped)
|
|
437
|
+
return "skip";
|
|
438
|
+
input =
|
|
439
|
+
typeof workload.input === "function"
|
|
440
|
+
? workload.input({
|
|
441
|
+
row: plan.row,
|
|
442
|
+
feed,
|
|
443
|
+
producerSlot,
|
|
444
|
+
iteration,
|
|
445
|
+
})
|
|
446
|
+
: (workload.input ?? {});
|
|
447
|
+
}
|
|
448
|
+
catch {
|
|
449
|
+
return failSetup();
|
|
450
|
+
}
|
|
451
|
+
return startLoadIteration({
|
|
452
|
+
core,
|
|
453
|
+
sink,
|
|
454
|
+
scenario: workload.compiled,
|
|
455
|
+
envelope,
|
|
456
|
+
input,
|
|
457
|
+
producerSlot,
|
|
458
|
+
iteration,
|
|
459
|
+
session: cloneSession(baseSession), // copy-on-write: each iteration gets its own (deep)
|
|
460
|
+
...(Object.keys(feederKeys).length > 0 ? { feederKeys } : {}),
|
|
461
|
+
now,
|
|
462
|
+
continuation: { pool: continuationPool },
|
|
463
|
+
signal: runAbort.signal,
|
|
464
|
+
});
|
|
465
|
+
};
|
|
466
|
+
// Run-global per-feeder draw count, keyed by each feeder slot's `counterKey` (a shared
|
|
467
|
+
// feeder's binding object, or an entry feeder's unique marker — see WorkloadFeeder).
|
|
468
|
+
// Shared across slots, so a shared feeder advances run-wide while a per-entry slot advances
|
|
469
|
+
// only on its entry's turns. Feeds `drawIndex` (built-in uniquePerIteration / roundRobin).
|
|
470
|
+
const feederGlobalDraws = new Map();
|
|
471
|
+
const runSlot = async (slotIndex) => {
|
|
472
|
+
if (rampUpMs !== undefined) {
|
|
473
|
+
await pausedSleep(rampDelayMs(slotIndex, concurrency, rampUpMs));
|
|
474
|
+
}
|
|
475
|
+
sink.emitProducerSlotStart(slotIndex);
|
|
476
|
+
const producerSlotId = `p${slotIndex}`;
|
|
477
|
+
// Per-slot iteration index (the `slotIteration` public contract field), and per-slot
|
|
478
|
+
// per-feeder draw counts (what partitionByVu actually indexes by, via `slotDrawIndex`).
|
|
479
|
+
let slotIteration = 0;
|
|
480
|
+
const feederSlotDraws = new Map();
|
|
481
|
+
let primaryIterations = 0;
|
|
482
|
+
for (;;) {
|
|
483
|
+
const globalIteration = claimIteration();
|
|
484
|
+
if (globalIteration < 0)
|
|
485
|
+
break;
|
|
486
|
+
// Pick this iteration's workload (weighted-random for a mix, the sole one for a single
|
|
487
|
+
// scenario); the feeders it draws advance their own per-binding counters (see drawCtxFor).
|
|
488
|
+
const workload = selectWorkload();
|
|
489
|
+
const started = startOneIteration(slotIndex, producerSlotId, globalIteration, slotIteration, workload, feederSlotDraws);
|
|
490
|
+
slotIteration += 1;
|
|
491
|
+
if (started !== "skip") {
|
|
492
|
+
// A real (or failed-setup) primary iteration.
|
|
493
|
+
if (started !== "failed") {
|
|
494
|
+
// Hold the slot until the primary phase finishes: at the producer-release
|
|
495
|
+
// boundary (then the continuation drains in the background) or, with no
|
|
496
|
+
// release, at full completion (closed model).
|
|
497
|
+
const { released } = await started.primaryDone;
|
|
498
|
+
if (released)
|
|
499
|
+
trackContinuation(started.completed);
|
|
500
|
+
}
|
|
501
|
+
primaryIterations += 1;
|
|
502
|
+
}
|
|
503
|
+
// Pace EVERY slot turn — including a feeder skip/wait — so an exhausted
|
|
504
|
+
// skip/wait feeder doesn't spin the loop in a paced run.
|
|
505
|
+
if (thinkTimeMs !== undefined)
|
|
506
|
+
await pausedSleep(thinkDelay(thinkTimeMs));
|
|
507
|
+
}
|
|
508
|
+
sink.emitProducerSlotEnd(slotIndex, primaryIterations);
|
|
509
|
+
};
|
|
510
|
+
let abortedByDrainTimeout = 0;
|
|
511
|
+
try {
|
|
512
|
+
await Promise.all(Array.from({ length: concurrency }, (_, i) => runSlot(i)));
|
|
513
|
+
abortedByDrainTimeout = await drainContinuations(continuations, continuationCfg?.drainTimeoutMs);
|
|
514
|
+
}
|
|
515
|
+
finally {
|
|
516
|
+
if (deadlineTimer !== undefined)
|
|
517
|
+
clearTimeout(deadlineTimer);
|
|
518
|
+
// All primaries are done and the drain phase has run; abort whatever continuation
|
|
519
|
+
// tail is still in flight so its in-flight HTTP / engine poll waits stop NOW rather
|
|
520
|
+
// than running on in the background. A tail that already settled (drain awaited it,
|
|
521
|
+
// or there was no drainTimeout) makes this a no-op. The aborted tails settle on later
|
|
522
|
+
// microtasks — after the synchronous `seal()` below — so their late events are still
|
|
523
|
+
// dropped, leaving the artifact unchanged; only the wasted in-flight work is cut.
|
|
524
|
+
runAbort.abort();
|
|
525
|
+
}
|
|
526
|
+
const endReason = iterations !== undefined && claimed >= iterations ? "iterations" : durationMs !== undefined ? "duration" : "iterations";
|
|
527
|
+
sink.emitLoadEnd(endReason);
|
|
528
|
+
// Seal the sink so a continuation the drain timeout abandoned can't emit into the
|
|
529
|
+
// reducer after the artifact is built. The `runAbort.abort()` above already cancelled
|
|
530
|
+
// its in-flight HTTP / engine poll waits, so a tail settles promptly; seal is the
|
|
531
|
+
// backstop for the late events that abort can't pre-empt (e.g. a bare `setTimeout` in
|
|
532
|
+
// user code, which no signal can cancel) and for the settle that lands post-seal.
|
|
533
|
+
sink.seal();
|
|
534
|
+
const artifact = reducer.finalize();
|
|
535
|
+
// Continuations the drain timeout abandoned are still in flight at finalize —
|
|
536
|
+
// surface them (the reducer can't know the orchestrator's drain decision).
|
|
537
|
+
if (artifact.summary.continuation) {
|
|
538
|
+
const c = artifact.summary.continuation;
|
|
539
|
+
// The orchestrator saw the true peak of concurrent tails (incl. deadline-released
|
|
540
|
+
// ones the pool never admitted, so the reducer's maxBacklog can't see them).
|
|
541
|
+
c.maxBacklog = Math.max(c.maxBacklog, peakContinuations);
|
|
542
|
+
c.maxConcurrent = Math.max(c.maxConcurrent, peakContinuations);
|
|
543
|
+
if (abortedByDrainTimeout > 0) {
|
|
544
|
+
c.abortedByDrainTimeout = abortedByDrainTimeout;
|
|
545
|
+
c.backlog = abortedByDrainTimeout;
|
|
546
|
+
c.active = abortedByDrainTimeout;
|
|
547
|
+
artifact.runtime.continuationInFlight = abortedByDrainTimeout;
|
|
548
|
+
}
|
|
549
|
+
}
|
|
550
|
+
// Advisory: some iteration ran a long TAIL poll but didn't request producer release,
|
|
551
|
+
// so its slot stayed tied up for the whole tail (closed end-to-end scheduling), under-
|
|
552
|
+
// pressuring the upstream. The sink decides this PER ITERATION (`unreleasedTailPollRan`):
|
|
553
|
+
// - a TAIL poll (a step-scoped request before it, none after) — excludes a poll in an
|
|
554
|
+
// untaken branch (never runs) and a readiness/token poll before the primary request;
|
|
555
|
+
// - in an iteration that did NOT ask for release — a bare `primaryComplete()` still
|
|
556
|
+
// gets advised, but a requested-but-rejected release does not (they already asked),
|
|
557
|
+
// and a row that releases doesn't mute the advisory for a sibling row that doesn't.
|
|
558
|
+
if (sink.unreleasedTailPollRan) {
|
|
559
|
+
(artifact.summary.advisories ??= []).push("Most producer slot time is spent after the primary request; closed end-to-end scheduling may reduce upstream pressure. Call `await ctx.report.primaryComplete(..., { releaseProducerSlot: true })` after the primary load is issued if you want sustained ingress pressure.");
|
|
560
|
+
}
|
|
561
|
+
// Evaluate configured thresholds against the finalized artifact and refine the pass
|
|
562
|
+
// verdict (a crash-free run still fails if a threshold is breached). Thresholds are
|
|
563
|
+
// run-level — for a mix they apply to the aggregate, not per scenario.
|
|
564
|
+
if (config.thresholds !== undefined) {
|
|
565
|
+
const { thresholds, pass } = evaluateThresholds(artifact, config.thresholds);
|
|
566
|
+
artifact.summary.thresholds = thresholds;
|
|
567
|
+
artifact.summary.pass = pass;
|
|
568
|
+
}
|
|
569
|
+
return artifact;
|
|
570
|
+
}
|
|
571
|
+
//# sourceMappingURL=orchestrator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"orchestrator.js","sourceRoot":"","sources":["../../src/load/orchestrator.ts"],"names":[],"mappings":"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"}
|