@loadstrike/loadstrike-sdk 1.0.30401 → 1.0.31001
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -0
- package/dist/cjs/iteration-observation-diagnostics.js +513 -0
- package/dist/cjs/iteration-observations.js +195 -22
- package/dist/cjs/local.js +55 -10
- package/dist/cjs/reporting.js +26 -7
- package/dist/cjs/runtime.js +159 -80
- package/dist/cjs/sink-retry-policy.js +52 -0
- package/dist/cjs/sinks.js +112 -9
- package/dist/cjs/transports.js +78 -25
- package/dist/esm/iteration-observation-diagnostics.js +508 -0
- package/dist/esm/iteration-observations.js +195 -22
- package/dist/esm/local.js +55 -10
- package/dist/esm/reporting.js +26 -7
- package/dist/esm/runtime.js +159 -80
- package/dist/esm/sink-retry-policy.js +44 -0
- package/dist/esm/sinks.js +112 -9
- package/dist/esm/transports.js +78 -25
- package/dist/types/iteration-observation-diagnostics.d.ts +21 -0
- package/dist/types/iteration-observations.d.ts +5 -0
- package/dist/types/runtime.d.ts +2 -0
- package/dist/types/sink-retry-policy.d.ts +9 -0
- package/dist/types/sinks.d.ts +6 -0
- package/dist/types/transports.d.ts +4 -0
- package/package.json +2 -2
package/dist/cjs/runtime.js
CHANGED
|
@@ -16,6 +16,8 @@ const reporting_js_1 = require("./reporting.js");
|
|
|
16
16
|
const sinks_js_1 = require("./sinks.js");
|
|
17
17
|
const load_engine_v2_js_1 = require("./load-engine-v2.js");
|
|
18
18
|
const iteration_observations_js_1 = require("./iteration-observations.js");
|
|
19
|
+
const iteration_observation_diagnostics_js_1 = require("./iteration-observation-diagnostics.js");
|
|
20
|
+
const sink_retry_policy_js_1 = require("./sink-retry-policy.js");
|
|
19
21
|
const LOAD_ENGINE_V2_SCHEDULER_DISTRIBUTIONS = Symbol("loadstrike.load-engine-v2.scheduler-distributions");
|
|
20
22
|
const PORTAL_RUN_TOKEN_PROVIDER = Symbol.for("loadstrike.internal.portal-run-token-provider");
|
|
21
23
|
exports.LoadStrikeNodeType = {
|
|
@@ -3455,8 +3457,8 @@ class LoadStrikeRunner {
|
|
|
3455
3457
|
}));
|
|
3456
3458
|
const sinkErrors = [];
|
|
3457
3459
|
const policyErrors = [];
|
|
3458
|
-
const sinkRetryCount =
|
|
3459
|
-
const sinkRetryBackoffMs =
|
|
3460
|
+
const sinkRetryCount = (0, sink_retry_policy_js_1.normalizeSinkRetryCount)(this.options.sinkRetryCount);
|
|
3461
|
+
const sinkRetryBackoffMs = (0, sink_retry_policy_js_1.normalizeSinkRetryBackoffMs)(this.options.sinkRetryBackoffMs);
|
|
3460
3462
|
const policies = this.options.runtimePolicies ?? [];
|
|
3461
3463
|
const runtimePolicyErrorMode = normalizedRuntimePolicyErrorMode(this.options.runtimePolicyErrorMode);
|
|
3462
3464
|
const plugins = this.options.reportingSinks === undefined && this.options.workerPlugins === undefined &&
|
|
@@ -3550,14 +3552,14 @@ class LoadStrikeRunner {
|
|
|
3550
3552
|
await init(baseContext, this.options.infraConfig ?? {});
|
|
3551
3553
|
}
|
|
3552
3554
|
}
|
|
3553
|
-
await this.initializeSinks(sinkStates, baseContext, this.options.infraConfig ?? {}, sinkRetryCount, sinkRetryBackoffMs, sinkErrors);
|
|
3555
|
+
await this.initializeSinks(sinkStates, baseContext, this.options.infraConfig ?? {}, sinkRetryCount, sinkRetryBackoffMs, sinkErrors, testInfo.sessionId, runLogger);
|
|
3554
3556
|
for (const plugin of plugins) {
|
|
3555
3557
|
const start = resolveWorkerPluginStart(plugin);
|
|
3556
3558
|
if (start) {
|
|
3557
3559
|
await start(sessionInfo);
|
|
3558
3560
|
}
|
|
3559
3561
|
}
|
|
3560
|
-
await this.startSinks(sinkStates, sessionInfo, sinkRetryCount, sinkRetryBackoffMs, sinkErrors);
|
|
3562
|
+
await this.startSinks(sinkStates, sessionInfo, sinkRetryCount, sinkRetryBackoffMs, sinkErrors, testInfo.sessionId, runLogger);
|
|
3561
3563
|
const iterationObservationRunId = String(this.internalOptions.iterationObservationRunId
|
|
3562
3564
|
?? sessionInfo.portalReportingRunId
|
|
3563
3565
|
?? sessionInfo.PortalReportingRunId
|
|
@@ -3588,7 +3590,10 @@ class LoadStrikeRunner {
|
|
|
3588
3590
|
expectedResultOwnerCount64: iterationObservationExpectedResultOwnerCount64,
|
|
3589
3591
|
processGroup: iterationObservationProcessGroup,
|
|
3590
3592
|
settings: resolveIterationObservationSettings(this.options),
|
|
3591
|
-
sinks: reporterIterationObservationSinks
|
|
3593
|
+
sinks: reporterIterationObservationSinks,
|
|
3594
|
+
sinkRetryCount,
|
|
3595
|
+
sinkRetryBackoffMs,
|
|
3596
|
+
logger: runLogger
|
|
3592
3597
|
});
|
|
3593
3598
|
const emitRealtimeSnapshot = async () => {
|
|
3594
3599
|
if (realtimeInFlight) {
|
|
@@ -3600,7 +3605,7 @@ class LoadStrikeRunner {
|
|
|
3600
3605
|
.map((value) => value.build(scenarioDurationsMs.get(value.scenarioName) ?? Math.max(Date.now() - started.getTime(), 0)))
|
|
3601
3606
|
.sort((left, right) => left.sortIndex - right.sortIndex);
|
|
3602
3607
|
const metricsSnapshot = collectMetricStats(allRegisteredMetrics, Date.now() - started.getTime());
|
|
3603
|
-
await this.emitRealtimeStats(sinkStates, snapshot, metricsSnapshot, sinkRetryCount, sinkRetryBackoffMs, sinkErrors);
|
|
3608
|
+
await this.emitRealtimeStats(sinkStates, snapshot, metricsSnapshot, sinkRetryCount, sinkRetryBackoffMs, sinkErrors, testInfo.sessionId, runLogger);
|
|
3604
3609
|
if (toBoolean(this.options.displayConsoleMetrics, true)) {
|
|
3605
3610
|
const requestCount = snapshot.reduce((sum, value) => sum + value.allRequestCount, 0);
|
|
3606
3611
|
const okCount = snapshot.reduce((sum, value) => sum + value.allOkCount, 0);
|
|
@@ -3791,8 +3796,8 @@ class LoadStrikeRunner {
|
|
|
3791
3796
|
finalizedResult.logFiles = mergeStringArrays(finalizedResult.logFiles, loggerSetup.logFiles);
|
|
3792
3797
|
finalizedResult.reportFiles = this.writeReports(finalizedResult);
|
|
3793
3798
|
finalizedResult.disabledSinks = sinkStates.filter((x) => x.disabled).map((x) => x.name);
|
|
3794
|
-
await this.emitRunResult(sinkStates, finalizedResult, sinkRetryCount, sinkRetryBackoffMs, sinkErrors);
|
|
3795
|
-
await this.stopSinks(sinkStates, sinkRetryCount, sinkRetryBackoffMs, sinkErrors);
|
|
3799
|
+
await this.emitRunResult(sinkStates, finalizedResult, sinkRetryCount, sinkRetryBackoffMs, sinkErrors, testInfo.sessionId, runLogger);
|
|
3800
|
+
await this.stopSinks(sinkStates, sinkRetryCount, sinkRetryBackoffMs, sinkErrors, testInfo.sessionId, runLogger);
|
|
3796
3801
|
sinksStopped = true;
|
|
3797
3802
|
finalizedResult.disabledSinks = sinkStates.filter((x) => x.disabled).map((x) => x.name);
|
|
3798
3803
|
finalizedResult.sinkErrors = sinkErrors
|
|
@@ -3805,7 +3810,7 @@ class LoadStrikeRunner {
|
|
|
3805
3810
|
await iterationObservationReporter.sealAndDrain().catch(() => { });
|
|
3806
3811
|
}
|
|
3807
3812
|
if (!sinksStopped) {
|
|
3808
|
-
await this.stopSinks(sinkStates, sinkRetryCount, sinkRetryBackoffMs, sinkErrors);
|
|
3813
|
+
await this.stopSinks(sinkStates, sinkRetryCount, sinkRetryBackoffMs, sinkErrors, testInfo.sessionId, runLogger);
|
|
3809
3814
|
}
|
|
3810
3815
|
if (!pluginsStopped) {
|
|
3811
3816
|
await this.stopPlugins(plugins, pluginLifecycleErrors, runLogger);
|
|
@@ -4113,9 +4118,9 @@ class LoadStrikeRunner {
|
|
|
4113
4118
|
}
|
|
4114
4119
|
return filtered;
|
|
4115
4120
|
}
|
|
4116
|
-
async initializeSinks(sinkStates, context, infraConfig, retryCount, retryBackoffMs, sinkErrors) {
|
|
4121
|
+
async initializeSinks(sinkStates, context, infraConfig, retryCount, retryBackoffMs, sinkErrors, runId, logger) {
|
|
4117
4122
|
for (const state of sinkStates) {
|
|
4118
|
-
await this.invokeSinkAction(state, "init", retryCount, retryBackoffMs, sinkErrors, false, true, async () => {
|
|
4123
|
+
await this.invokeSinkAction(state, "init", retryCount, retryBackoffMs, sinkErrors, runId, logger, false, true, async () => {
|
|
4119
4124
|
const init = resolveSinkInit(state.sink);
|
|
4120
4125
|
if (init) {
|
|
4121
4126
|
await init(context, infraConfig);
|
|
@@ -4123,9 +4128,9 @@ class LoadStrikeRunner {
|
|
|
4123
4128
|
});
|
|
4124
4129
|
}
|
|
4125
4130
|
}
|
|
4126
|
-
async startSinks(sinkStates, session, retryCount, retryBackoffMs, sinkErrors) {
|
|
4131
|
+
async startSinks(sinkStates, session, retryCount, retryBackoffMs, sinkErrors, runId, logger) {
|
|
4127
4132
|
for (const state of sinkStates) {
|
|
4128
|
-
await this.invokeSinkAction(state, "start", retryCount, retryBackoffMs, sinkErrors, false, true, async () => {
|
|
4133
|
+
await this.invokeSinkAction(state, "start", retryCount, retryBackoffMs, sinkErrors, runId, logger, false, true, async () => {
|
|
4129
4134
|
const start = resolveSinkStart(state.sink);
|
|
4130
4135
|
if (start) {
|
|
4131
4136
|
await start(session);
|
|
@@ -4133,9 +4138,9 @@ class LoadStrikeRunner {
|
|
|
4133
4138
|
});
|
|
4134
4139
|
}
|
|
4135
4140
|
}
|
|
4136
|
-
async emitRealtimeStats(sinkStates, scenarioStats, metrics, retryCount, retryBackoffMs, sinkErrors) {
|
|
4141
|
+
async emitRealtimeStats(sinkStates, scenarioStats, metrics, retryCount, retryBackoffMs, sinkErrors, runId, logger) {
|
|
4137
4142
|
for (const state of sinkStates) {
|
|
4138
|
-
await this.invokeSinkAction(state, "realtime", retryCount, retryBackoffMs, sinkErrors, false, true, async () => {
|
|
4143
|
+
await this.invokeSinkAction(state, "realtime", retryCount, retryBackoffMs, sinkErrors, runId, logger, false, true, async () => {
|
|
4139
4144
|
const saveRealtimeStats = resolveSinkSaveRealtimeStats(state.sink);
|
|
4140
4145
|
if (saveRealtimeStats) {
|
|
4141
4146
|
await saveRealtimeStats(scenarioStats);
|
|
@@ -4147,10 +4152,9 @@ class LoadStrikeRunner {
|
|
|
4147
4152
|
});
|
|
4148
4153
|
}
|
|
4149
4154
|
}
|
|
4150
|
-
async stopSinks(sinkStates, retryCount, retryBackoffMs, sinkErrors) {
|
|
4151
|
-
const shutdownRetryCount = 0;
|
|
4155
|
+
async stopSinks(sinkStates, retryCount, retryBackoffMs, sinkErrors, runId, logger) {
|
|
4152
4156
|
for (const state of sinkStates) {
|
|
4153
|
-
await this.invokeSinkAction(state, "stop",
|
|
4157
|
+
await this.invokeSinkAction(state, "stop", retryCount, retryBackoffMs, sinkErrors, runId, logger, true, true, async () => {
|
|
4154
4158
|
const stop = resolveSinkStop(state.sink);
|
|
4155
4159
|
if (stop) {
|
|
4156
4160
|
await stop();
|
|
@@ -4158,15 +4162,15 @@ class LoadStrikeRunner {
|
|
|
4158
4162
|
});
|
|
4159
4163
|
const dispose = resolveSinkDispose(state.sink);
|
|
4160
4164
|
if (dispose) {
|
|
4161
|
-
await this.invokeSinkAction(state, "dispose",
|
|
4165
|
+
await this.invokeSinkAction(state, "dispose", retryCount, retryBackoffMs, sinkErrors, runId, logger, true, true, async () => {
|
|
4162
4166
|
await dispose();
|
|
4163
4167
|
});
|
|
4164
4168
|
}
|
|
4165
4169
|
}
|
|
4166
4170
|
}
|
|
4167
|
-
async emitRunResult(sinkStates, result, retryCount, retryBackoffMs, sinkErrors) {
|
|
4171
|
+
async emitRunResult(sinkStates, result, retryCount, retryBackoffMs, sinkErrors, runId, logger) {
|
|
4168
4172
|
for (const state of sinkStates) {
|
|
4169
|
-
await this.invokeSinkAction(state, "run-result", retryCount, retryBackoffMs, sinkErrors, false, false, async () => {
|
|
4173
|
+
await this.invokeSinkAction(state, "run-result", retryCount, retryBackoffMs, sinkErrors, runId, logger, false, false, async () => {
|
|
4170
4174
|
const saveRunResult = resolveSinkSaveRunResult(state.sink);
|
|
4171
4175
|
if (saveRunResult) {
|
|
4172
4176
|
await saveRunResult(result);
|
|
@@ -4174,23 +4178,49 @@ class LoadStrikeRunner {
|
|
|
4174
4178
|
});
|
|
4175
4179
|
}
|
|
4176
4180
|
}
|
|
4177
|
-
async invokeSinkAction(state, phase, retryCount, retryBackoffMs, sinkErrors, ignoreDisabled, disableOnFailure, action) {
|
|
4181
|
+
async invokeSinkAction(state, phase, retryCount, retryBackoffMs, sinkErrors, runId, logger, ignoreDisabled, disableOnFailure, action) {
|
|
4178
4182
|
if (state.disabled && !ignoreDisabled) {
|
|
4179
4183
|
return;
|
|
4180
4184
|
}
|
|
4181
|
-
|
|
4182
|
-
|
|
4183
|
-
|
|
4185
|
+
const maximumAttempts = (0, sink_retry_policy_js_1.normalizeSinkRetryCount)(retryCount) + 1;
|
|
4186
|
+
const backoffMs = (0, sink_retry_policy_js_1.normalizeSinkRetryBackoffMs)(retryBackoffMs);
|
|
4187
|
+
for (let attempts = 1; attempts <= maximumAttempts; attempts += 1) {
|
|
4184
4188
|
try {
|
|
4185
4189
|
await action();
|
|
4190
|
+
if (attempts > 1) {
|
|
4191
|
+
(0, iteration_observation_diagnostics_js_1.logIterationObservationRecovery)(logger, {
|
|
4192
|
+
sinkName: state.name,
|
|
4193
|
+
operation: "reporting-sink-action",
|
|
4194
|
+
phase,
|
|
4195
|
+
runId,
|
|
4196
|
+
resultOwnerId: "",
|
|
4197
|
+
observationCount: 0,
|
|
4198
|
+
attempt: attempts,
|
|
4199
|
+
maximumAttempts,
|
|
4200
|
+
nextDelayMs: 0
|
|
4201
|
+
});
|
|
4202
|
+
}
|
|
4186
4203
|
return;
|
|
4187
4204
|
}
|
|
4188
4205
|
catch (error) {
|
|
4189
|
-
|
|
4206
|
+
const exhausted = attempts >= maximumAttempts;
|
|
4207
|
+
const nextDelayMs = exhausted ? 0 : (0, sink_retry_policy_js_1.sinkRetryDelayMs)(backoffMs, attempts);
|
|
4208
|
+
(0, iteration_observation_diagnostics_js_1.logIterationObservationFailure)(logger, exhausted ? "error" : "warn", {
|
|
4209
|
+
sinkName: state.name,
|
|
4210
|
+
operation: "reporting-sink-action",
|
|
4211
|
+
phase,
|
|
4212
|
+
runId,
|
|
4213
|
+
resultOwnerId: "",
|
|
4214
|
+
observationCount: 0,
|
|
4215
|
+
attempt: attempts,
|
|
4216
|
+
maximumAttempts,
|
|
4217
|
+
nextDelayMs
|
|
4218
|
+
}, error);
|
|
4219
|
+
if (exhausted) {
|
|
4190
4220
|
sinkErrors.push({
|
|
4191
4221
|
sinkName: state.name,
|
|
4192
4222
|
phase,
|
|
4193
|
-
message:
|
|
4223
|
+
message: "The reporting sink action failed after retries.",
|
|
4194
4224
|
attempts
|
|
4195
4225
|
});
|
|
4196
4226
|
if (disableOnFailure) {
|
|
@@ -4198,9 +4228,7 @@ class LoadStrikeRunner {
|
|
|
4198
4228
|
}
|
|
4199
4229
|
return;
|
|
4200
4230
|
}
|
|
4201
|
-
|
|
4202
|
-
await sleep(retryBackoffMs * attempts);
|
|
4203
|
-
}
|
|
4231
|
+
await (0, sink_retry_policy_js_1.waitForSinkRetryDelay)(nextDelayMs);
|
|
4204
4232
|
}
|
|
4205
4233
|
}
|
|
4206
4234
|
}
|
|
@@ -4610,7 +4638,18 @@ async function executeScenarioRuntime(args) {
|
|
|
4610
4638
|
attachScenarioContextAliases(context);
|
|
4611
4639
|
const startedUtcNs = (0, iteration_observations_js_1.utcNowNs)();
|
|
4612
4640
|
const startedAtNs = process.hrtime.bigint();
|
|
4613
|
-
|
|
4641
|
+
let policyFailure;
|
|
4642
|
+
let reply;
|
|
4643
|
+
try {
|
|
4644
|
+
reply = await executeScenarioInvocation(scenario, context, operation);
|
|
4645
|
+
}
|
|
4646
|
+
catch (error) {
|
|
4647
|
+
if (!(error instanceof RuntimePolicyCallbackError)) {
|
|
4648
|
+
throw error;
|
|
4649
|
+
}
|
|
4650
|
+
policyFailure = error;
|
|
4651
|
+
reply = LoadStrikeResponse.fail("runtime_policy_error", "", 0);
|
|
4652
|
+
}
|
|
4614
4653
|
const observedLatencyNs = maxBigInt(process.hrtime.bigint() - startedAtNs, 0n);
|
|
4615
4654
|
const completedUtcNs = startedUtcNs + observedLatencyNs;
|
|
4616
4655
|
const observedLatencyMs = Number(observedLatencyNs) / 1000000;
|
|
@@ -4625,7 +4664,8 @@ async function executeScenarioRuntime(args) {
|
|
|
4625
4664
|
observedLatencyUs: observedLatencyNs / 1000n,
|
|
4626
4665
|
reportedLatencyUs: normalizeRawObservationLatencyMicroseconds(resolveRecordedLatency(reply.customLatencyMs, observedLatencyMs)),
|
|
4627
4666
|
steps: attemptSteps,
|
|
4628
|
-
recordedSteps
|
|
4667
|
+
recordedSteps,
|
|
4668
|
+
...(policyFailure ? { policyFailure } : {})
|
|
4629
4669
|
};
|
|
4630
4670
|
};
|
|
4631
4671
|
const captureAttemptObservation = (operation, globalOrdinal, attemptIndex, isFinalAttempt, attempt, simulationIndex, simulationKind, iterationId, globalSecondaryOrdinal = 0n) => {
|
|
@@ -4674,22 +4714,18 @@ async function executeScenarioRuntime(args) {
|
|
|
4674
4714
|
const maxAttempts = 1 + (scenario.shouldRestartIterationOnFail() ? restartIterationMaxAttempts : 0);
|
|
4675
4715
|
while (attempts < maxAttempts && !shouldStopNow()) {
|
|
4676
4716
|
attempts += 1;
|
|
4677
|
-
|
|
4678
|
-
|
|
4679
|
-
attempt
|
|
4680
|
-
}
|
|
4681
|
-
catch (error) {
|
|
4682
|
-
if (error instanceof RuntimePolicyCallbackError) {
|
|
4683
|
-
stopScenario = true;
|
|
4684
|
-
scenarioAbortController.abort(error);
|
|
4685
|
-
}
|
|
4686
|
-
throw error;
|
|
4687
|
-
}
|
|
4688
|
-
const shouldRetry = !attempt.reply.isSuccess
|
|
4717
|
+
const attempt = await runSingleInvocation("Bombing", instanceData, instanceNumber, instanceId, false);
|
|
4718
|
+
const shouldRetry = !attempt.policyFailure
|
|
4719
|
+
&& !attempt.reply.isSuccess
|
|
4689
4720
|
&& scenario.shouldRestartIterationOnFail()
|
|
4690
4721
|
&& attempts < maxAttempts
|
|
4691
4722
|
&& !shouldStopNow();
|
|
4692
4723
|
captureAttemptObservation("Bombing", globalOrdinal, attempts - 1, !shouldRetry, attempt, simulationIndex, simulationKind, iterationId, explicitSecondaryOrdinal);
|
|
4724
|
+
if (attempt.policyFailure) {
|
|
4725
|
+
stopScenario = true;
|
|
4726
|
+
scenarioAbortController.abort(attempt.policyFailure);
|
|
4727
|
+
throw attempt.policyFailure;
|
|
4728
|
+
}
|
|
4693
4729
|
if (!shouldRetry) {
|
|
4694
4730
|
for (const step of attempt.recordedSteps) {
|
|
4695
4731
|
recordStepReply(step.stepName, step.reply, step.observedLatencyMs, step.sortIndex);
|
|
@@ -4716,6 +4752,11 @@ async function executeScenarioRuntime(args) {
|
|
|
4716
4752
|
const globalOrdinal = nextObservationOrdinal();
|
|
4717
4753
|
const attempt = await runSingleInvocation("WarmUp", instanceInfo.instanceData, instanceInfo.instanceNumber, instanceInfo.instanceId, false);
|
|
4718
4754
|
captureAttemptObservation("WarmUp", globalOrdinal, 0, true, attempt, -1, "SingleInvocation");
|
|
4755
|
+
if (attempt.policyFailure) {
|
|
4756
|
+
stopScenario = true;
|
|
4757
|
+
scenarioAbortController.abort(attempt.policyFailure);
|
|
4758
|
+
throw attempt.policyFailure;
|
|
4759
|
+
}
|
|
4719
4760
|
}
|
|
4720
4761
|
};
|
|
4721
4762
|
const executeV2TimedConstant = async (copies, durationNs, ramping, runSimulationInvocation, segment) => {
|
|
@@ -5386,10 +5427,17 @@ async function waitForScenarioTasks(tasks, scenarioName, timeoutSeconds, logger,
|
|
|
5386
5427
|
throwPolicyFailure(await settled);
|
|
5387
5428
|
return;
|
|
5388
5429
|
}
|
|
5389
|
-
const
|
|
5390
|
-
|
|
5391
|
-
|
|
5392
|
-
|
|
5430
|
+
const timeoutController = new AbortController();
|
|
5431
|
+
let completed;
|
|
5432
|
+
try {
|
|
5433
|
+
completed = await Promise.race([
|
|
5434
|
+
settled.then(() => true),
|
|
5435
|
+
delayWithAbort(Math.trunc(timeoutSeconds * 1000), combineAbortSignals(signal, timeoutController.signal)).then(() => false)
|
|
5436
|
+
]);
|
|
5437
|
+
}
|
|
5438
|
+
finally {
|
|
5439
|
+
timeoutController.abort();
|
|
5440
|
+
}
|
|
5393
5441
|
if (!completed) {
|
|
5394
5442
|
if (signal.reason instanceof RuntimePolicyCallbackError) {
|
|
5395
5443
|
throw signal.reason;
|
|
@@ -9451,11 +9499,23 @@ function readRuntimeTrackingId(payload, selector) {
|
|
|
9451
9499
|
return null;
|
|
9452
9500
|
}
|
|
9453
9501
|
let current = body;
|
|
9454
|
-
|
|
9502
|
+
const path = selector.slice("json:".length).trim().replace(/^\$\./, "");
|
|
9503
|
+
let segments;
|
|
9504
|
+
try {
|
|
9505
|
+
segments = runtimeSafeJsonPathSegments(path);
|
|
9506
|
+
}
|
|
9507
|
+
catch {
|
|
9508
|
+
return null;
|
|
9509
|
+
}
|
|
9510
|
+
for (const segment of segments) {
|
|
9455
9511
|
if (!current || typeof current !== "object" || Array.isArray(current)) {
|
|
9456
9512
|
return null;
|
|
9457
9513
|
}
|
|
9458
|
-
|
|
9514
|
+
const record = current;
|
|
9515
|
+
if (!Object.prototype.hasOwnProperty.call(record, segment)) {
|
|
9516
|
+
return null;
|
|
9517
|
+
}
|
|
9518
|
+
current = runtimeReadOwnJsonProperty(record, segment);
|
|
9459
9519
|
}
|
|
9460
9520
|
return current == null ? null : String(current);
|
|
9461
9521
|
}
|
|
@@ -9479,23 +9539,57 @@ function runtimeParseBodyAsObject(body) {
|
|
|
9479
9539
|
}
|
|
9480
9540
|
}
|
|
9481
9541
|
function setRuntimeJsonPathValue(body, path, value) {
|
|
9482
|
-
const target =
|
|
9483
|
-
|
|
9484
|
-
: {};
|
|
9485
|
-
const segments = path.split(".").filter(Boolean);
|
|
9542
|
+
const target = runtimeCloneJsonRecord(body);
|
|
9543
|
+
const segments = runtimeSafeJsonPathSegments(path);
|
|
9486
9544
|
if (!segments.length) {
|
|
9487
9545
|
return target;
|
|
9488
9546
|
}
|
|
9489
9547
|
let current = target;
|
|
9490
9548
|
for (let i = 0; i < segments.length - 1; i += 1) {
|
|
9491
9549
|
const segment = segments[i];
|
|
9492
|
-
const next = current
|
|
9550
|
+
const next = runtimeReadOwnJsonProperty(current, segment);
|
|
9551
|
+
let child;
|
|
9493
9552
|
if (!next || typeof next !== "object" || Array.isArray(next)) {
|
|
9494
|
-
|
|
9553
|
+
child = {};
|
|
9554
|
+
}
|
|
9555
|
+
else {
|
|
9556
|
+
child = runtimeCloneJsonRecord(next);
|
|
9495
9557
|
}
|
|
9496
|
-
current
|
|
9558
|
+
runtimeDefineJsonProperty(current, segment, child);
|
|
9559
|
+
current = child;
|
|
9560
|
+
}
|
|
9561
|
+
runtimeDefineJsonProperty(current, segments[segments.length - 1], value);
|
|
9562
|
+
return target;
|
|
9563
|
+
}
|
|
9564
|
+
const FORBIDDEN_RUNTIME_JSON_PATH_SEGMENTS = new Set(["__proto__", "prototype", "constructor"]);
|
|
9565
|
+
function runtimeSafeJsonPathSegments(path) {
|
|
9566
|
+
const segments = path.split(".").filter(Boolean);
|
|
9567
|
+
const forbidden = segments.find((segment) => FORBIDDEN_RUNTIME_JSON_PATH_SEGMENTS.has(segment));
|
|
9568
|
+
if (forbidden) {
|
|
9569
|
+
throw new Error(`Tracking selector contains forbidden JSON path segment '${forbidden}'.`);
|
|
9570
|
+
}
|
|
9571
|
+
return segments;
|
|
9572
|
+
}
|
|
9573
|
+
function runtimeDefineJsonProperty(target, key, value) {
|
|
9574
|
+
Object.defineProperty(target, key, {
|
|
9575
|
+
configurable: true,
|
|
9576
|
+
enumerable: true,
|
|
9577
|
+
value,
|
|
9578
|
+
writable: true
|
|
9579
|
+
});
|
|
9580
|
+
}
|
|
9581
|
+
function runtimeReadOwnJsonProperty(target, key) {
|
|
9582
|
+
const descriptor = Object.getOwnPropertyDescriptor(target, key);
|
|
9583
|
+
return descriptor && "value" in descriptor ? descriptor.value : undefined;
|
|
9584
|
+
}
|
|
9585
|
+
function runtimeCloneJsonRecord(value) {
|
|
9586
|
+
const target = {};
|
|
9587
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
9588
|
+
return target;
|
|
9589
|
+
}
|
|
9590
|
+
for (const [key, entry] of Object.entries(value)) {
|
|
9591
|
+
runtimeDefineJsonProperty(target, key, entry);
|
|
9497
9592
|
}
|
|
9498
|
-
current[segments[segments.length - 1]] = value;
|
|
9499
9593
|
return target;
|
|
9500
9594
|
}
|
|
9501
9595
|
function asTrackingRecord(value) {
|
|
@@ -9505,8 +9599,8 @@ function asTrackingRecord(value) {
|
|
|
9505
9599
|
}
|
|
9506
9600
|
function pickTrackingValue(source, ...keys) {
|
|
9507
9601
|
for (const key of keys) {
|
|
9508
|
-
if (key
|
|
9509
|
-
return source
|
|
9602
|
+
if (Object.prototype.hasOwnProperty.call(source, key)) {
|
|
9603
|
+
return runtimeReadOwnJsonProperty(source, key);
|
|
9510
9604
|
}
|
|
9511
9605
|
}
|
|
9512
9606
|
return undefined;
|
|
@@ -9760,26 +9854,10 @@ function createDefaultLogger(logFilePath) {
|
|
|
9760
9854
|
function wrapLoggerWithMinimumLevel(baseLogger, minimumLogLevel) {
|
|
9761
9855
|
const threshold = logLevelOrder(minimumLogLevel);
|
|
9762
9856
|
return {
|
|
9763
|
-
debug: (message) =>
|
|
9764
|
-
|
|
9765
|
-
|
|
9766
|
-
|
|
9767
|
-
},
|
|
9768
|
-
info: (message) => {
|
|
9769
|
-
if (threshold <= 1) {
|
|
9770
|
-
baseLogger.info(message);
|
|
9771
|
-
}
|
|
9772
|
-
},
|
|
9773
|
-
warn: (message) => {
|
|
9774
|
-
if (threshold <= 2) {
|
|
9775
|
-
baseLogger.warn(message);
|
|
9776
|
-
}
|
|
9777
|
-
},
|
|
9778
|
-
error: (message) => {
|
|
9779
|
-
if (threshold <= 3) {
|
|
9780
|
-
baseLogger.error(message);
|
|
9781
|
-
}
|
|
9782
|
-
}
|
|
9857
|
+
debug: (message) => threshold <= 0 ? baseLogger.debug(message) : undefined,
|
|
9858
|
+
info: (message) => threshold <= 1 ? baseLogger.info(message) : undefined,
|
|
9859
|
+
warn: (message) => threshold <= 2 ? baseLogger.warn(message) : undefined,
|
|
9860
|
+
error: (message) => threshold <= 3 ? baseLogger.error(message) : undefined
|
|
9783
9861
|
};
|
|
9784
9862
|
}
|
|
9785
9863
|
function formatDefaultLoggerLine(level, message) {
|
|
@@ -11293,6 +11371,7 @@ exports.__loadstrikeTestExports = {
|
|
|
11293
11371
|
parseStrictBooleanToken,
|
|
11294
11372
|
percentile,
|
|
11295
11373
|
pickOptionalTrackingSelectorString,
|
|
11374
|
+
pickTrackingValue,
|
|
11296
11375
|
pickTrackingNumber,
|
|
11297
11376
|
produceOrConsumeTrackingPayload,
|
|
11298
11377
|
readConfiguredSinkName,
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.MAXIMUM_TIMER_DELAY_MS = exports.MAXIMUM_SINK_RETRY_COUNT = exports.DEFAULT_SINK_RETRY_BACKOFF_MS = exports.DEFAULT_SINK_RETRY_COUNT = void 0;
|
|
4
|
+
exports.normalizeSinkRetryCount = normalizeSinkRetryCount;
|
|
5
|
+
exports.normalizeSinkRetryBackoffMs = normalizeSinkRetryBackoffMs;
|
|
6
|
+
exports.sinkRetryDelayMs = sinkRetryDelayMs;
|
|
7
|
+
exports.waitForSinkRetryDelay = waitForSinkRetryDelay;
|
|
8
|
+
exports.cooperativeSinkRetryYield = cooperativeSinkRetryYield;
|
|
9
|
+
exports.DEFAULT_SINK_RETRY_COUNT = 3;
|
|
10
|
+
exports.DEFAULT_SINK_RETRY_BACKOFF_MS = 250;
|
|
11
|
+
exports.MAXIMUM_SINK_RETRY_COUNT = 100;
|
|
12
|
+
exports.MAXIMUM_TIMER_DELAY_MS = 2147483647;
|
|
13
|
+
function normalizeSinkRetryCount(value) {
|
|
14
|
+
const resolved = value === undefined ? exports.DEFAULT_SINK_RETRY_COUNT : value;
|
|
15
|
+
if (!Number.isFinite(resolved) || resolved <= 0) {
|
|
16
|
+
return 0;
|
|
17
|
+
}
|
|
18
|
+
return Math.min(Math.trunc(resolved), exports.MAXIMUM_SINK_RETRY_COUNT);
|
|
19
|
+
}
|
|
20
|
+
function normalizeSinkRetryBackoffMs(value) {
|
|
21
|
+
const resolved = value === undefined ? exports.DEFAULT_SINK_RETRY_BACKOFF_MS : value;
|
|
22
|
+
if (!Number.isFinite(resolved) || resolved <= 0) {
|
|
23
|
+
return 0;
|
|
24
|
+
}
|
|
25
|
+
return Math.min(Math.trunc(resolved), exports.MAXIMUM_TIMER_DELAY_MS);
|
|
26
|
+
}
|
|
27
|
+
function sinkRetryDelayMs(baseDelayMs, retryNumber) {
|
|
28
|
+
if (baseDelayMs <= 0) {
|
|
29
|
+
return 0;
|
|
30
|
+
}
|
|
31
|
+
let delayMs = Math.min(Math.trunc(baseDelayMs), exports.MAXIMUM_TIMER_DELAY_MS);
|
|
32
|
+
const doublings = Math.max(Math.trunc(retryNumber) - 1, 0);
|
|
33
|
+
for (let index = 0; index < doublings; index += 1) {
|
|
34
|
+
if (delayMs >= Math.ceil(exports.MAXIMUM_TIMER_DELAY_MS / 2)) {
|
|
35
|
+
return exports.MAXIMUM_TIMER_DELAY_MS;
|
|
36
|
+
}
|
|
37
|
+
delayMs *= 2;
|
|
38
|
+
}
|
|
39
|
+
return delayMs;
|
|
40
|
+
}
|
|
41
|
+
async function waitForSinkRetryDelay(delayMs) {
|
|
42
|
+
if (delayMs <= 0) {
|
|
43
|
+
await cooperativeSinkRetryYield();
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
await new Promise((resolve) => {
|
|
47
|
+
setTimeout(resolve, Math.min(delayMs, exports.MAXIMUM_TIMER_DELAY_MS));
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
async function cooperativeSinkRetryYield() {
|
|
51
|
+
await new Promise((resolve) => setImmediate(resolve));
|
|
52
|
+
}
|