@glubean/runner 0.7.0 → 0.8.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/dist/engine-bridge.d.ts +4 -0
- package/dist/engine-bridge.d.ts.map +1 -1
- package/dist/engine-bridge.js +10 -1
- package/dist/engine-bridge.js.map +1 -1
- package/dist/executor.d.ts +2 -2
- package/dist/executor.d.ts.map +1 -1
- package/dist/executor.js +9 -226
- package/dist/executor.js.map +1 -1
- package/dist/harness.js +3 -79
- package/dist/harness.js.map +1 -1
- package/dist/index.d.ts +16 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +17 -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/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/package.json +4 -4
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* LoadSink — translates the engine's per-run wire events into the load
|
|
3
|
+
* `LoadEvent` fact stream and feeds the `LoadReducer`.
|
|
4
|
+
*
|
|
5
|
+
* One sink + one engine core serve every concurrent iteration: each iteration
|
|
6
|
+
* runs an engine TestDef whose `meta.id` is the unique iterationId, so wire
|
|
7
|
+
* events arrive tagged with `testId = iterationId` and the sink demuxes them
|
|
8
|
+
* back to the right iteration's attribution (no per-iteration core needed).
|
|
9
|
+
*
|
|
10
|
+
* Success requests feed only the reducer's aggregates; the sink stays bounded
|
|
11
|
+
* (per-iteration step-name maps are dropped at iteration end). Failure-trace
|
|
12
|
+
* sampling and producer-release events land in later milestones.
|
|
13
|
+
*/
|
|
14
|
+
import type { LoadEndReason, LoadErrorKind, LoadEvent, LoadReducer, LoadResolvedConfig } from "@glubean/sdk/load";
|
|
15
|
+
/** Per-iteration attribution the sink stamps onto translated events. */
|
|
16
|
+
export interface LoadIterationEnvelope {
|
|
17
|
+
scenarioId: string;
|
|
18
|
+
scenarioRefId?: string;
|
|
19
|
+
producerSlotId: string;
|
|
20
|
+
iterationId: string;
|
|
21
|
+
}
|
|
22
|
+
/** Distributive Omit — applied per union member so each LoadEvent variant keeps
|
|
23
|
+
* its own discriminant-specific fields (a plain Omit over the union would keep
|
|
24
|
+
* only the common envelope keys). */
|
|
25
|
+
type DistributiveOmit<T, K extends PropertyKey> = T extends unknown ? Omit<T, K> : never;
|
|
26
|
+
type LoadEventBody = DistributiveOmit<LoadEvent, "ts" | "seq" | "runId" | "runnerId">;
|
|
27
|
+
export declare class LoadSink {
|
|
28
|
+
private readonly reducer;
|
|
29
|
+
private readonly runId;
|
|
30
|
+
private readonly runnerId;
|
|
31
|
+
private readonly now;
|
|
32
|
+
private seq;
|
|
33
|
+
private sealed;
|
|
34
|
+
private readonly envelopes;
|
|
35
|
+
private readonly stepNames;
|
|
36
|
+
private readonly phases;
|
|
37
|
+
private readonly iterSpan;
|
|
38
|
+
private sawUnreleasedTailPoll;
|
|
39
|
+
constructor(reducer: LoadReducer, runId: string, runnerId: string, now?: () => number);
|
|
40
|
+
/** Stamp envelope basics (ts / seq / runId / runnerId) and apply to the reducer.
|
|
41
|
+
* A no-op once sealed (post-finalize), so abandoned continuations can't mutate
|
|
42
|
+
* the already-built artifact. */
|
|
43
|
+
emit(body: LoadEventBody): void;
|
|
44
|
+
/** Stop forwarding events to the reducer (called once the run is finalized). */
|
|
45
|
+
seal(): void;
|
|
46
|
+
/** Whether any iteration ran a post-primary TAIL `.poll()` without requesting producer
|
|
47
|
+
* release (a request before it, none after, and no release asked). Gates the
|
|
48
|
+
* long-poll advisory — the closed-scheduling case it nudges toward release. */
|
|
49
|
+
get unreleasedTailPollRan(): boolean;
|
|
50
|
+
/** Flag the advisory if `span` shows a poll that HELD the slot: a request preceded it
|
|
51
|
+
* (minReq < maxUnreleasedPoll) and no primary-phase request followed it
|
|
52
|
+
* (maxPrimaryReq <= maxUnreleasedPoll — excludes a pre-primary readiness wait while
|
|
53
|
+
* ignoring post-boundary continuation requests). The sentinels make a missing held poll
|
|
54
|
+
* / request fail the first test. Idempotent — safe to call at release time AND at
|
|
55
|
+
* endIteration (the spans are frozen once the primary boundary / release is reached). */
|
|
56
|
+
private markUnreleasedTailPoll;
|
|
57
|
+
/** Register an iteration's attribution before its engine run starts. */
|
|
58
|
+
beginIteration(env: LoadIterationEnvelope): void;
|
|
59
|
+
/** Drop an iteration's per-iteration buffers once it has finished. */
|
|
60
|
+
endIteration(iterationId: string): void;
|
|
61
|
+
/** The shared per-iteration attribution every translated event carries. Phase
|
|
62
|
+
* starts "primary" and flips to "continuation" at the iteration's first
|
|
63
|
+
* `primaryComplete` boundary (see `emitPrimaryCompleted`). */
|
|
64
|
+
private baseOf;
|
|
65
|
+
/** Emit `iteration:start` (the executor calls this right after beginIteration). */
|
|
66
|
+
emitIterationStart(env: LoadIterationEnvelope, opts?: {
|
|
67
|
+
inputKey?: string;
|
|
68
|
+
feederKeys?: Record<string, string>;
|
|
69
|
+
}): void;
|
|
70
|
+
/** Emit `iteration:end` (the executor calls this once the engine run resolves). */
|
|
71
|
+
emitIterationEnd(env: LoadIterationEnvelope, result: {
|
|
72
|
+
ok: boolean;
|
|
73
|
+
durationMs: number;
|
|
74
|
+
errorKind?: LoadErrorKind;
|
|
75
|
+
}): void;
|
|
76
|
+
/** A per-scenario-stable, leaf-unique step id. The engine's leaf `index` is
|
|
77
|
+
* assigned in deterministic registry order (taken or skipped), so the same
|
|
78
|
+
* logical step always gets the same index — folding it in disambiguates two
|
|
79
|
+
* leaves that share a display name (the reducer keys aggregates by stepId). */
|
|
80
|
+
private stepIdOf;
|
|
81
|
+
/** Emit `report:checkpoint` (backs `ctx.report.checkpoint`). */
|
|
82
|
+
emitCheckpoint(env: LoadIterationEnvelope, checkpointId: string, data?: Record<string, unknown>): void;
|
|
83
|
+
/** Emit `producer:primaryCompleted` (backs the first `ctx.report.primaryComplete`)
|
|
84
|
+
* and FLIP this iteration into its continuation phase immediately, so every
|
|
85
|
+
* request / checkpoint the sink translates afterwards carries
|
|
86
|
+
* `phase: "continuation"` (the API's contract). The boundary event itself is
|
|
87
|
+
* stamped with the pre-flip ("primary") phase. A step that spans the boundary
|
|
88
|
+
* still keeps a single phase because step:end uses its captured START phase
|
|
89
|
+
* (see the `step_end` case). M5 records the measurement boundary only —
|
|
90
|
+
* `releaseRequested` is forwarded for M6 scheduling, it does not release a slot. */
|
|
91
|
+
emitPrimaryCompleted(env: LoadIterationEnvelope, info: {
|
|
92
|
+
primaryId: string;
|
|
93
|
+
primaryDurationMs: number;
|
|
94
|
+
releaseRequested: boolean;
|
|
95
|
+
}): void;
|
|
96
|
+
/** Emit `producer:released` (M6): the producer slot was freed at this iteration's
|
|
97
|
+
* primaryComplete boundary so a new primary can start; the rest of this iteration
|
|
98
|
+
* runs as a continuation. `backpressureMs` is the wait the release incurred when
|
|
99
|
+
* the continuation backlog was full. */
|
|
100
|
+
emitProducerReleased(env: LoadIterationEnvelope, info: {
|
|
101
|
+
releaseId: string;
|
|
102
|
+
primaryDurationMs: number;
|
|
103
|
+
continuationBacklog: number;
|
|
104
|
+
backpressureMs: number;
|
|
105
|
+
}): void;
|
|
106
|
+
/** Emit `producer:releaseRejected` (M6): a release was requested but not granted —
|
|
107
|
+
* backlog full under `fail-iteration`, a duplicate, a parked release whose drain
|
|
108
|
+
* bound expired (`drainTimeout`), or one cancelled by the run deadline. */
|
|
109
|
+
emitProducerReleaseRejected(env: LoadIterationEnvelope, info: {
|
|
110
|
+
releaseId: string;
|
|
111
|
+
reason: "continuationBacklogFull" | "duplicateRelease" | "drainTimeout" | "runDeadlineReached";
|
|
112
|
+
waitMs: number;
|
|
113
|
+
continuationBacklog: number;
|
|
114
|
+
}): void;
|
|
115
|
+
/** Emit `load:start` with the resolved config (orchestrator run boundary). */
|
|
116
|
+
emitLoadStart(config: LoadResolvedConfig): void;
|
|
117
|
+
/** Emit `load:end` with why the run stopped. */
|
|
118
|
+
emitLoadEnd(reason: LoadEndReason): void;
|
|
119
|
+
/** Emit `producerSlot:start` when a producer slot begins generating load. */
|
|
120
|
+
emitProducerSlotStart(producerSlotIndex: number): void;
|
|
121
|
+
/** Emit `producerSlot:end` with how many primary iterations the slot ran. */
|
|
122
|
+
emitProducerSlotEnd(producerSlotIndex: number, primaryIterations: number): void;
|
|
123
|
+
/** The engine-core sink callback: translate one wire event to LoadEvent(s). */
|
|
124
|
+
readonly handleWire: (wire: Record<string, unknown>) => void;
|
|
125
|
+
}
|
|
126
|
+
export {};
|
|
127
|
+
//# sourceMappingURL=sink.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sink.d.ts","sourceRoot":"","sources":["../../src/load/sink.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,351 @@
|
|
|
1
|
+
import { resolveRouteKey } from "./route-key.js";
|
|
2
|
+
export class LoadSink {
|
|
3
|
+
reducer;
|
|
4
|
+
runId;
|
|
5
|
+
runnerId;
|
|
6
|
+
now;
|
|
7
|
+
seq = 0;
|
|
8
|
+
// Once the run is finalized, events from continuations the drain timeout abandoned
|
|
9
|
+
// must not mutate reducer state (they'd land after the artifact was built).
|
|
10
|
+
sealed = false;
|
|
11
|
+
envelopes = new Map();
|
|
12
|
+
stepNames = new Map();
|
|
13
|
+
// Per-iteration phase: "primary" until that iteration's first primaryComplete
|
|
14
|
+
// boundary, "continuation" immediately after. Keyed by iterationId so concurrent
|
|
15
|
+
// iterations (one shared sink) flip independently. Every translated event carries
|
|
16
|
+
// this live phase, so post-boundary work (requests / assertions) is "continuation"
|
|
17
|
+
// — matching the public contract that `primaryComplete` switches the iteration
|
|
18
|
+
// into continuation. (Step aggregates stay coherent because the reducer keys steps
|
|
19
|
+
// by stepId, not by phase, so a step that spans the boundary is one row.)
|
|
20
|
+
phases = new Map();
|
|
21
|
+
// Per-iteration state for spotting a poll that held the producer slot without (timely)
|
|
22
|
+
// release — the long-poll advisory's target. All step indices are STEP-SCOPED; a poll's
|
|
23
|
+
// own attempt requests share its index, and unscoped setup/teardown requests (no
|
|
24
|
+
// stepIndex) don't enter the span. Two boundaries gate the spans separately:
|
|
25
|
+
// - `primaryCompleted` (a bare OR releasing `primaryComplete`): after it, requests are
|
|
26
|
+
// continuation-phase, so `maxPrimaryReq` (the latest PRIMARY-phase request) stops
|
|
27
|
+
// advancing — a post-boundary request must not disqualify a held poll;
|
|
28
|
+
// - `releaseRequested` (a releasing `primaryComplete`): after it the slot is FREED, so
|
|
29
|
+
// `maxUnreleasedPoll` (the latest poll that ran while the slot was held) stops.
|
|
30
|
+
// Plus `minReq`, the earliest request. The advisory fires iff a request preceded the held
|
|
31
|
+
// poll (minReq < maxUnreleasedPoll) AND no primary-phase request followed it
|
|
32
|
+
// (maxPrimaryReq <= maxUnreleasedPoll) — the latter excludes a pre-primary readiness wait
|
|
33
|
+
// whose load comes later, while a post-boundary continuation request doesn't disqualify.
|
|
34
|
+
iterSpan = new Map();
|
|
35
|
+
// Whether any iteration ran a TAIL `.poll()` WITHOUT requesting producer release — the
|
|
36
|
+
// closed-scheduling case the long-poll advisory targets. Per-iteration (not run-wide):
|
|
37
|
+
// a row that releases doesn't mute the advisory for a sibling row that doesn't.
|
|
38
|
+
sawUnreleasedTailPoll = false;
|
|
39
|
+
constructor(reducer, runId, runnerId, now = () => Date.now()) {
|
|
40
|
+
this.reducer = reducer;
|
|
41
|
+
this.runId = runId;
|
|
42
|
+
this.runnerId = runnerId;
|
|
43
|
+
this.now = now;
|
|
44
|
+
}
|
|
45
|
+
/** Stamp envelope basics (ts / seq / runId / runnerId) and apply to the reducer.
|
|
46
|
+
* A no-op once sealed (post-finalize), so abandoned continuations can't mutate
|
|
47
|
+
* the already-built artifact. */
|
|
48
|
+
emit(body) {
|
|
49
|
+
if (this.sealed)
|
|
50
|
+
return;
|
|
51
|
+
this.reducer.apply({
|
|
52
|
+
ts: this.now(),
|
|
53
|
+
seq: this.seq++,
|
|
54
|
+
runId: this.runId,
|
|
55
|
+
runnerId: this.runnerId,
|
|
56
|
+
...body,
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
/** Stop forwarding events to the reducer (called once the run is finalized). */
|
|
60
|
+
seal() {
|
|
61
|
+
this.sealed = true;
|
|
62
|
+
}
|
|
63
|
+
/** Whether any iteration ran a post-primary TAIL `.poll()` without requesting producer
|
|
64
|
+
* release (a request before it, none after, and no release asked). Gates the
|
|
65
|
+
* long-poll advisory — the closed-scheduling case it nudges toward release. */
|
|
66
|
+
get unreleasedTailPollRan() {
|
|
67
|
+
return this.sawUnreleasedTailPoll;
|
|
68
|
+
}
|
|
69
|
+
/** Flag the advisory if `span` shows a poll that HELD the slot: a request preceded it
|
|
70
|
+
* (minReq < maxUnreleasedPoll) and no primary-phase request followed it
|
|
71
|
+
* (maxPrimaryReq <= maxUnreleasedPoll — excludes a pre-primary readiness wait while
|
|
72
|
+
* ignoring post-boundary continuation requests). The sentinels make a missing held poll
|
|
73
|
+
* / request fail the first test. Idempotent — safe to call at release time AND at
|
|
74
|
+
* endIteration (the spans are frozen once the primary boundary / release is reached). */
|
|
75
|
+
markUnreleasedTailPoll(span) {
|
|
76
|
+
if (span.minReq < span.maxUnreleasedPoll && span.maxPrimaryReq <= span.maxUnreleasedPoll) {
|
|
77
|
+
this.sawUnreleasedTailPoll = true;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
/** Register an iteration's attribution before its engine run starts. */
|
|
81
|
+
beginIteration(env) {
|
|
82
|
+
this.envelopes.set(env.iterationId, env);
|
|
83
|
+
this.stepNames.set(env.iterationId, new Map());
|
|
84
|
+
this.phases.set(env.iterationId, "primary");
|
|
85
|
+
// Sentinels: no request (min +∞) and no primary request / held poll (max −∞) until seen.
|
|
86
|
+
this.iterSpan.set(env.iterationId, {
|
|
87
|
+
minReq: Infinity, maxPrimaryReq: -Infinity, maxUnreleasedPoll: -Infinity, primaryCompleted: false, releaseRequested: false,
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
/** Drop an iteration's per-iteration buffers once it has finished. */
|
|
91
|
+
endIteration(iterationId) {
|
|
92
|
+
// Catch the no-release case (the iteration ran to completion without ever asking for
|
|
93
|
+
// release, so its whole span is now final). Released iterations are evaluated earlier,
|
|
94
|
+
// at release time, so a later drain-abandoned continuation can't lose the advisory.
|
|
95
|
+
const span = this.iterSpan.get(iterationId);
|
|
96
|
+
if (span !== undefined)
|
|
97
|
+
this.markUnreleasedTailPoll(span);
|
|
98
|
+
this.envelopes.delete(iterationId);
|
|
99
|
+
this.stepNames.delete(iterationId);
|
|
100
|
+
this.phases.delete(iterationId);
|
|
101
|
+
this.iterSpan.delete(iterationId);
|
|
102
|
+
}
|
|
103
|
+
/** The shared per-iteration attribution every translated event carries. Phase
|
|
104
|
+
* starts "primary" and flips to "continuation" at the iteration's first
|
|
105
|
+
* `primaryComplete` boundary (see `emitPrimaryCompleted`). */
|
|
106
|
+
baseOf(env) {
|
|
107
|
+
return {
|
|
108
|
+
scenarioId: env.scenarioId,
|
|
109
|
+
...(env.scenarioRefId !== undefined ? { scenarioRefId: env.scenarioRefId } : {}),
|
|
110
|
+
producerSlotId: env.producerSlotId,
|
|
111
|
+
iterationId: env.iterationId,
|
|
112
|
+
phase: this.phases.get(env.iterationId) ?? "primary",
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
/** Emit `iteration:start` (the executor calls this right after beginIteration). */
|
|
116
|
+
emitIterationStart(env, opts = {}) {
|
|
117
|
+
this.emit({
|
|
118
|
+
type: "iteration:start",
|
|
119
|
+
...this.baseOf(env),
|
|
120
|
+
...(opts.inputKey !== undefined ? { inputKey: opts.inputKey } : {}),
|
|
121
|
+
...(opts.feederKeys !== undefined ? { feederKeys: opts.feederKeys } : {}),
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
/** Emit `iteration:end` (the executor calls this once the engine run resolves). */
|
|
125
|
+
emitIterationEnd(env, result) {
|
|
126
|
+
this.emit({
|
|
127
|
+
type: "iteration:end",
|
|
128
|
+
...this.baseOf(env),
|
|
129
|
+
ok: result.ok,
|
|
130
|
+
durationMs: result.durationMs,
|
|
131
|
+
...(result.errorKind !== undefined ? { errorKind: result.errorKind } : {}),
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
/** A per-scenario-stable, leaf-unique step id. The engine's leaf `index` is
|
|
135
|
+
* assigned in deterministic registry order (taken or skipped), so the same
|
|
136
|
+
* logical step always gets the same index — folding it in disambiguates two
|
|
137
|
+
* leaves that share a display name (the reducer keys aggregates by stepId). */
|
|
138
|
+
stepIdOf(index, name) {
|
|
139
|
+
return `${index}:${name}`;
|
|
140
|
+
}
|
|
141
|
+
/** Emit `report:checkpoint` (backs `ctx.report.checkpoint`). */
|
|
142
|
+
emitCheckpoint(env, checkpointId, data) {
|
|
143
|
+
this.emit({
|
|
144
|
+
type: "report:checkpoint",
|
|
145
|
+
...this.baseOf(env),
|
|
146
|
+
checkpointId,
|
|
147
|
+
...(data !== undefined ? { data } : {}),
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
/** Emit `producer:primaryCompleted` (backs the first `ctx.report.primaryComplete`)
|
|
151
|
+
* and FLIP this iteration into its continuation phase immediately, so every
|
|
152
|
+
* request / checkpoint the sink translates afterwards carries
|
|
153
|
+
* `phase: "continuation"` (the API's contract). The boundary event itself is
|
|
154
|
+
* stamped with the pre-flip ("primary") phase. A step that spans the boundary
|
|
155
|
+
* still keeps a single phase because step:end uses its captured START phase
|
|
156
|
+
* (see the `step_end` case). M5 records the measurement boundary only —
|
|
157
|
+
* `releaseRequested` is forwarded for M6 scheduling, it does not release a slot. */
|
|
158
|
+
emitPrimaryCompleted(env, info) {
|
|
159
|
+
this.emit({
|
|
160
|
+
type: "producer:primaryCompleted",
|
|
161
|
+
...this.baseOf(env),
|
|
162
|
+
primaryId: info.primaryId,
|
|
163
|
+
primaryDurationMs: info.primaryDurationMs,
|
|
164
|
+
releaseRequested: info.releaseRequested,
|
|
165
|
+
});
|
|
166
|
+
// This is the PRIMARY BOUNDARY (bare or releasing): from here on, requests are
|
|
167
|
+
// continuation-phase and stop advancing `maxPrimaryReq`. A RELEASING boundary also
|
|
168
|
+
// frees the slot, so later polls stop extending `maxUnreleasedPoll`; but any poll that
|
|
169
|
+
// ALREADY ran still held the slot — a late release can't free it in hindsight. Since
|
|
170
|
+
// the spans are now frozen, evaluate the advisory at release time — the continuation
|
|
171
|
+
// may be abandoned by the drain timeout before endIteration runs, which would otherwise
|
|
172
|
+
// lose this misordered case. (A requested-but-rejected release still counts as "asked".)
|
|
173
|
+
const span = this.iterSpan.get(env.iterationId);
|
|
174
|
+
if (span !== undefined) {
|
|
175
|
+
span.primaryCompleted = true;
|
|
176
|
+
if (info.releaseRequested) {
|
|
177
|
+
span.releaseRequested = true;
|
|
178
|
+
this.markUnreleasedTailPoll(span);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
this.phases.set(env.iterationId, "continuation");
|
|
182
|
+
}
|
|
183
|
+
/** Emit `producer:released` (M6): the producer slot was freed at this iteration's
|
|
184
|
+
* primaryComplete boundary so a new primary can start; the rest of this iteration
|
|
185
|
+
* runs as a continuation. `backpressureMs` is the wait the release incurred when
|
|
186
|
+
* the continuation backlog was full. */
|
|
187
|
+
emitProducerReleased(env, info) {
|
|
188
|
+
this.emit({
|
|
189
|
+
type: "producer:released",
|
|
190
|
+
...this.baseOf(env),
|
|
191
|
+
releaseId: info.releaseId,
|
|
192
|
+
primaryDurationMs: info.primaryDurationMs,
|
|
193
|
+
continuationBacklog: info.continuationBacklog,
|
|
194
|
+
...(info.backpressureMs > 0 ? { continuationBackpressure: true } : {}),
|
|
195
|
+
backpressureMs: info.backpressureMs,
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
/** Emit `producer:releaseRejected` (M6): a release was requested but not granted —
|
|
199
|
+
* backlog full under `fail-iteration`, a duplicate, a parked release whose drain
|
|
200
|
+
* bound expired (`drainTimeout`), or one cancelled by the run deadline. */
|
|
201
|
+
emitProducerReleaseRejected(env, info) {
|
|
202
|
+
this.emit({
|
|
203
|
+
type: "producer:releaseRejected",
|
|
204
|
+
...this.baseOf(env),
|
|
205
|
+
releaseId: info.releaseId,
|
|
206
|
+
reason: info.reason,
|
|
207
|
+
waitMs: info.waitMs,
|
|
208
|
+
continuationBacklog: info.continuationBacklog,
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
/** Emit `load:start` with the resolved config (orchestrator run boundary). */
|
|
212
|
+
emitLoadStart(config) {
|
|
213
|
+
this.emit({ type: "load:start", config });
|
|
214
|
+
}
|
|
215
|
+
/** Emit `load:end` with why the run stopped. */
|
|
216
|
+
emitLoadEnd(reason) {
|
|
217
|
+
this.emit({ type: "load:end", reason });
|
|
218
|
+
}
|
|
219
|
+
/** Emit `producerSlot:start` when a producer slot begins generating load. */
|
|
220
|
+
emitProducerSlotStart(producerSlotIndex) {
|
|
221
|
+
this.emit({ type: "producerSlot:start", producerSlotIndex });
|
|
222
|
+
}
|
|
223
|
+
/** Emit `producerSlot:end` with how many primary iterations the slot ran. */
|
|
224
|
+
emitProducerSlotEnd(producerSlotIndex, primaryIterations) {
|
|
225
|
+
this.emit({ type: "producerSlot:end", producerSlotIndex, primaryIterations });
|
|
226
|
+
}
|
|
227
|
+
/** The engine-core sink callback: translate one wire event to LoadEvent(s). */
|
|
228
|
+
handleWire = (wire) => {
|
|
229
|
+
const iterationId = wire.testId;
|
|
230
|
+
if (!iterationId)
|
|
231
|
+
return;
|
|
232
|
+
const env = this.envelopes.get(iterationId);
|
|
233
|
+
if (!env)
|
|
234
|
+
return; // not a tracked load iteration
|
|
235
|
+
const base = this.baseOf(env);
|
|
236
|
+
switch (wire.type) {
|
|
237
|
+
case "step_start": {
|
|
238
|
+
const index = wire.index;
|
|
239
|
+
const name = wire.name;
|
|
240
|
+
const group = wire.group;
|
|
241
|
+
this.stepNames.get(iterationId)?.set(index, name);
|
|
242
|
+
this.emit({
|
|
243
|
+
type: "step:start",
|
|
244
|
+
...base,
|
|
245
|
+
stepId: this.stepIdOf(index, name),
|
|
246
|
+
stepName: name,
|
|
247
|
+
...(group !== undefined ? { groupId: group } : {}),
|
|
248
|
+
});
|
|
249
|
+
break;
|
|
250
|
+
}
|
|
251
|
+
case "step_end": {
|
|
252
|
+
const index = wire.index;
|
|
253
|
+
const name = wire.name;
|
|
254
|
+
const status = wire.status;
|
|
255
|
+
const group = wire.group;
|
|
256
|
+
this.emit({
|
|
257
|
+
type: "step:end",
|
|
258
|
+
...base,
|
|
259
|
+
stepId: this.stepIdOf(index, name),
|
|
260
|
+
stepName: name,
|
|
261
|
+
ok: status === "passed",
|
|
262
|
+
durationMs: wire.durationMs ?? 0,
|
|
263
|
+
...(status === "skipped" ? { skipped: true } : {}),
|
|
264
|
+
assertionFailures: wire.failedAssertions ?? 0,
|
|
265
|
+
...(wire.error !== undefined ? { errorKind: "stepError" } : {}),
|
|
266
|
+
// Carries group for SKIPPED leaves (no step:start emitted for them).
|
|
267
|
+
...(group !== undefined ? { groupId: group } : {}),
|
|
268
|
+
});
|
|
269
|
+
break;
|
|
270
|
+
}
|
|
271
|
+
case "trace": {
|
|
272
|
+
const t = (wire.data ?? {});
|
|
273
|
+
const stepIndex = wire.stepIndex;
|
|
274
|
+
// Widen this iteration's request step-index span — ONLY for step-scoped requests.
|
|
275
|
+
// An unscoped setup/teardown HTTP call (no stepIndex) must not count as a request
|
|
276
|
+
// before a step, or a pre-primary readiness poll would look like a tail.
|
|
277
|
+
if (stepIndex !== undefined) {
|
|
278
|
+
const span = this.iterSpan.get(iterationId);
|
|
279
|
+
if (span !== undefined) {
|
|
280
|
+
if (stepIndex < span.minReq)
|
|
281
|
+
span.minReq = stepIndex;
|
|
282
|
+
// Only PRIMARY-PHASE requests (before the boundary) bound the tail: a post-
|
|
283
|
+
// boundary continuation request mustn't make an earlier held poll look pre-primary.
|
|
284
|
+
if (!span.primaryCompleted && stepIndex > span.maxPrimaryReq)
|
|
285
|
+
span.maxPrimaryReq = stepIndex;
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
const stepName = stepIndex !== undefined ? this.stepNames.get(iterationId)?.get(stepIndex) : undefined;
|
|
289
|
+
// Resolve the routeKey. An EXACT route template from the trace (M8 — a
|
|
290
|
+
// `contract.http()` client / user `X-Glubean-Route` header, e.g. "GET /runs/:runId")
|
|
291
|
+
// wins and is exact (`contract-metadata`, not heuristic). Otherwise fall back to
|
|
292
|
+
// method + heuristic URL normalization (id-like segments → ":id", M3-e): the method
|
|
293
|
+
// is recovered from the trace `target` when explicit `method` is absent, so a
|
|
294
|
+
// target-only POST/PUT isn't mislabelled GET.
|
|
295
|
+
const exact = t.routeKey !== undefined && t.routeKey !== "";
|
|
296
|
+
const { method, routeKey } = resolveRouteKey(t.method, t.url, t.target, t.protocol, t.routeKey);
|
|
297
|
+
this.emit({
|
|
298
|
+
type: "request:observed",
|
|
299
|
+
...base,
|
|
300
|
+
...(stepName !== undefined ? { stepId: this.stepIdOf(stepIndex, stepName) } : {}),
|
|
301
|
+
method,
|
|
302
|
+
url: t.url ?? "",
|
|
303
|
+
routeKey,
|
|
304
|
+
routeKeySource: exact ? "contract-metadata" : "normalized-url",
|
|
305
|
+
routeKeyHeuristic: !exact,
|
|
306
|
+
...(t.status !== undefined ? { status: t.status } : {}),
|
|
307
|
+
ok: t.ok ?? false,
|
|
308
|
+
durationMs: t.durationMs ?? 0,
|
|
309
|
+
});
|
|
310
|
+
break;
|
|
311
|
+
}
|
|
312
|
+
case "assertion": {
|
|
313
|
+
const stepIndex = wire.stepIndex;
|
|
314
|
+
const stepName = stepIndex !== undefined ? this.stepNames.get(iterationId)?.get(stepIndex) : undefined;
|
|
315
|
+
this.emit({
|
|
316
|
+
type: "assertion:observed",
|
|
317
|
+
...base,
|
|
318
|
+
...(stepName !== undefined ? { stepId: this.stepIdOf(stepIndex, stepName) } : {}),
|
|
319
|
+
passed: wire.passed,
|
|
320
|
+
...(wire.message !== undefined ? { message: wire.message } : {}),
|
|
321
|
+
// Diagnostic operands so a failure sample can show what value failed (the reducer
|
|
322
|
+
// previews/bounds them — only retained for FAILED assertions). Presence checks, not
|
|
323
|
+
// `!== undefined`, so a deliberately-`undefined` operand is preserved (codex).
|
|
324
|
+
...("actual" in wire ? { actual: wire.actual } : {}),
|
|
325
|
+
...("expected" in wire ? { expected: wire.expected } : {}),
|
|
326
|
+
});
|
|
327
|
+
break;
|
|
328
|
+
}
|
|
329
|
+
case "poll": {
|
|
330
|
+
// A poll step ran (the event fires after its attempt loop). Record its step
|
|
331
|
+
// index; whether it's a post-primary TAIL is decided in endIteration once the
|
|
332
|
+
// full request span is known (a later load request would disqualify it). No
|
|
333
|
+
// reducer mutation, so seal is irrelevant.
|
|
334
|
+
const pollIndex = wire.index;
|
|
335
|
+
const span = this.iterSpan.get(iterationId);
|
|
336
|
+
// Only a poll that ran while the slot was still HELD (no release yet) counts — a
|
|
337
|
+
// poll after release ran on a freed slot. Track the highest such index, so a later
|
|
338
|
+
// released poll can't erase an earlier held one.
|
|
339
|
+
if (span !== undefined && !span.releaseRequested && pollIndex > span.maxUnreleasedPoll) {
|
|
340
|
+
span.maxUnreleasedPoll = pollIndex;
|
|
341
|
+
}
|
|
342
|
+
break;
|
|
343
|
+
}
|
|
344
|
+
// log / metric / action / event / warning / schema / branch / start / status /
|
|
345
|
+
// timeout: not part of the M3 closed-model aggregates.
|
|
346
|
+
default:
|
|
347
|
+
break;
|
|
348
|
+
}
|
|
349
|
+
};
|
|
350
|
+
}
|
|
351
|
+
//# sourceMappingURL=sink.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sink.js","sourceRoot":"","sources":["../../src/load/sink.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import type { LoadArtifact, LoadPlan } from "@glubean/sdk/load";
|
|
2
|
+
/**
|
|
3
|
+
* Marker prefixed to every harness protocol line on stdout. The user's load file
|
|
4
|
+
* + plugins share stdout, whose `console.log` may itself print JSON; gating on
|
|
5
|
+
* this token stops a stray `{"type":"error",...}` log from spoofing an outcome or
|
|
6
|
+
* a failure. It leads with the ASCII Unit Separator (0x1F) — a control byte that
|
|
7
|
+
* ordinary text logs never emit — so collision is negligible. Lines without it
|
|
8
|
+
* are forwarded to the parent's stdout as ordinary user output.
|
|
9
|
+
*
|
|
10
|
+
* (stdout, not a dedicated fd: tsx re-spawns an inner node process and forwards
|
|
11
|
+
* only fd 0/1/2, so an extra protocol fd wouldn't reach the harness.)
|
|
12
|
+
*/
|
|
13
|
+
export declare const WIRE_PREFIX = "\u001Fglubean-load-wire\u001F";
|
|
14
|
+
/**
|
|
15
|
+
* One NDJSON line (after `WIRE_PREFIX`) emitted by `load-harness`. `artifact`
|
|
16
|
+
* carries a completed plan's finalized `LoadArtifact`; `error` carries a per-file
|
|
17
|
+
* import failure or a per-plan run failure; `done` is the terminal sentinel
|
|
18
|
+
* proving the harness finished its own logic cleanly (its absence at child exit
|
|
19
|
+
* means the child crashed before completing).
|
|
20
|
+
*/
|
|
21
|
+
export type LoadHarnessMessage = {
|
|
22
|
+
type: "artifact";
|
|
23
|
+
runnerId: string;
|
|
24
|
+
artifact: LoadArtifact;
|
|
25
|
+
} | {
|
|
26
|
+
type: "error";
|
|
27
|
+
message: string;
|
|
28
|
+
} | {
|
|
29
|
+
type: "done";
|
|
30
|
+
};
|
|
31
|
+
/**
|
|
32
|
+
* Collect every LoadPlan exported by a module namespace (flattening `.each()`
|
|
33
|
+
* arrays of plans).
|
|
34
|
+
*/
|
|
35
|
+
export declare function collectLoadPlans(ns: Record<string, unknown>): LoadPlan[];
|
|
36
|
+
/**
|
|
37
|
+
* Wrap an env map so a missing key falls back to `process.env` — the same
|
|
38
|
+
* shell/CI env semantics the test harness gives `ctx.vars` / `ctx.secrets`, so
|
|
39
|
+
* `BASE_URL=... glubean load ...` resolves even without a `.env` entry.
|
|
40
|
+
*
|
|
41
|
+
* Applied INSIDE the child (which inherits the parent's `process.env`): the
|
|
42
|
+
* parent ships the raw resolved `{ vars, secrets }` over stdin — a Proxy can't
|
|
43
|
+
* survive JSON serialization, so the fallback must be re-established where
|
|
44
|
+
* `process.env` is actually present. Spreading the proxy (for `ctx.vars.all()`)
|
|
45
|
+
* still yields only the explicit map's own keys, not the whole environment.
|
|
46
|
+
*/
|
|
47
|
+
export declare function withProcessEnvFallback(map: Record<string, string>): Record<string, string>;
|
|
48
|
+
/** One plan's completed run, parsed from the child's `artifact` message. */
|
|
49
|
+
export interface LoadSubprocessOutcome {
|
|
50
|
+
runnerId: string;
|
|
51
|
+
artifact: LoadArtifact;
|
|
52
|
+
}
|
|
53
|
+
/** A per-file or per-plan failure, parsed from the child's `error` message. */
|
|
54
|
+
export interface LoadSubprocessError {
|
|
55
|
+
message: string;
|
|
56
|
+
}
|
|
57
|
+
/** Result of running one `.load.ts` file in a child process. */
|
|
58
|
+
export interface RunLoadFileResult {
|
|
59
|
+
outcomes: LoadSubprocessOutcome[];
|
|
60
|
+
errors: LoadSubprocessError[];
|
|
61
|
+
}
|
|
62
|
+
/** Options for a single-file subprocess load run. */
|
|
63
|
+
export interface RunLoadFileOptions {
|
|
64
|
+
/** Resolved environment vars (raw — env fallback is applied in the child). */
|
|
65
|
+
vars: Record<string, string>;
|
|
66
|
+
/** Resolved secrets (raw — env fallback is applied in the child). */
|
|
67
|
+
secrets: Record<string, string>;
|
|
68
|
+
/** Working dir for the child (the project root) — drives runner resolution. */
|
|
69
|
+
cwd: string;
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Run one `.load.ts` file's plans in a child process and collect their
|
|
73
|
+
* artifacts. Spawns `load-harness.js` (project-local when the project ships a
|
|
74
|
+
* built runner with it, else the CLI's bundled copy) through tsx so the harness
|
|
75
|
+
* and the user file resolve the same `@glubean/sdk`. The raw `{ vars, secrets }`
|
|
76
|
+
* are written to the child's stdin; the child applies the process.env fallback.
|
|
77
|
+
*
|
|
78
|
+
* Mirrors the in-process contract: a file's import failure or a plan's run
|
|
79
|
+
* failure becomes an `errors[]` entry (never throws), so other files/plans still
|
|
80
|
+
* produce results.
|
|
81
|
+
*/
|
|
82
|
+
export declare function runLoadFileInSubprocess(file: string, opts: RunLoadFileOptions): Promise<RunLoadFileResult>;
|
|
83
|
+
//# sourceMappingURL=subprocess.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"subprocess.d.ts","sourceRoot":"","sources":["../../src/load/subprocess.ts"],"names":[],"mappings":"AAuBA,OAAO,KAAK,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAKhE;;;;;;;;;;GAUG;AACH,eAAO,MAAM,WAAW,kCAA8B,CAAC;AAEvD;;;;;;GAMG;AACH,MAAM,MAAM,kBAAkB,GAC1B;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,YAAY,CAAA;CAAE,GAC9D;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GAClC;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC;AAarB;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,EAAE,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,QAAQ,EAAE,CAUxE;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,sBAAsB,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAiB1F;AAID,4EAA4E;AAC5E,MAAM,WAAW,qBAAqB;IACpC,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,YAAY,CAAC;CACxB;AAED,+EAA+E;AAC/E,MAAM,WAAW,mBAAmB;IAClC,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,gEAAgE;AAChE,MAAM,WAAW,iBAAiB;IAChC,QAAQ,EAAE,qBAAqB,EAAE,CAAC;IAClC,MAAM,EAAE,mBAAmB,EAAE,CAAC;CAC/B;AAED,qDAAqD;AACrD,MAAM,WAAW,kBAAkB;IACjC,8EAA8E;IAC9E,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC7B,qEAAqE;IACrE,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,+EAA+E;IAC/E,GAAG,EAAE,MAAM,CAAC;CACb;AA8BD;;;;;;;;;;GAUG;AACH,wBAAsB,uBAAuB,CAC3C,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,kBAAkB,GACvB,OAAO,CAAC,iBAAiB,CAAC,CA+F5B"}
|