@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.
@@ -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 = Math.max(this.options.sinkRetryCount ?? 2, 0);
3459
- const sinkRetryBackoffMs = Math.max(this.options.sinkRetryBackoffMs ?? 25, 0);
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", shutdownRetryCount, retryBackoffMs, sinkErrors, true, true, async () => {
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", shutdownRetryCount, retryBackoffMs, sinkErrors, true, true, async () => {
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
- let attempts = 0;
4182
- while (attempts <= retryCount) {
4183
- attempts += 1;
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
- if (attempts > retryCount) {
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: String(error ?? "sink action failed"),
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
- if (retryBackoffMs > 0) {
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
- const reply = await executeScenarioInvocation(scenario, context, operation);
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
- let attempt;
4678
- try {
4679
- attempt = await runSingleInvocation("Bombing", instanceData, instanceNumber, instanceId, false);
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 completed = await Promise.race([
5390
- settled.then(() => true),
5391
- delayWithAbort(Math.trunc(timeoutSeconds * 1000), signal).then(() => false)
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
- for (const segment of selector.slice("json:".length).trim().replace(/^\$\./, "").split(".").filter(Boolean)) {
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
- current = current[segment];
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 = body && typeof body === "object" && !Array.isArray(body)
9483
- ? { ...body }
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[segment];
9550
+ const next = runtimeReadOwnJsonProperty(current, segment);
9551
+ let child;
9493
9552
  if (!next || typeof next !== "object" || Array.isArray(next)) {
9494
- current[segment] = {};
9553
+ child = {};
9554
+ }
9555
+ else {
9556
+ child = runtimeCloneJsonRecord(next);
9495
9557
  }
9496
- current = current[segment];
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 in source) {
9509
- return source[key];
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
- if (threshold <= 0) {
9765
- baseLogger.debug(message);
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
+ }