baa-conductor

git clone 

commit
b9ce589
parent
8672d67
author
claude@macbookpro
date
2026-03-30 17:39:27 +0800 CST
Revert "feat: add jitter to renewal dispatcher to avoid rate limiting"

This reverts commit 8672d67c7bb6c2eb692df4cd1764b8b0018e12c8.
1 files changed,  +2, -53
M apps/conductor-daemon/src/renewal/dispatcher.ts
+2, -53
  1@@ -22,11 +22,8 @@ import {
  2 } from "./projector.js";
  3 
  4 const DEFAULT_EXECUTION_TIMEOUT_MS = 20_000;
  5-const DEFAULT_INTER_JOB_JITTER_MAX_MS = 3_000;
  6-const DEFAULT_INTER_JOB_JITTER_MIN_MS = 500;
  7 const DEFAULT_RECHECK_DELAY_MS = 10_000;
  8 const DEFAULT_RETRY_BASE_DELAY_MS = 30_000;
  9-const DEFAULT_RETRY_JITTER_FACTOR = 0.3;
 10 const DEFAULT_RETRY_MAX_DELAY_MS = 5 * 60_000;
 11 const PROXY_DELIVERY_TARGET_KIND = "browser.proxy_delivery";
 12 const RUNNER_NAME = "renewal.dispatcher";
 13@@ -82,13 +79,9 @@ interface RenewalDispatchOutcome {
 14 interface RenewalDispatcherRunnerOptions {
 15   browserBridge: BrowserBridgeController | null;
 16   executionTimeoutMs?: number;
 17-  interJobJitterMaxMs?: number;
 18-  interJobJitterMinMs?: number;
 19   now?: () => number;
 20-  random?: () => number;
 21   recheckDelayMs?: number;
 22   retryBaseDelayMs?: number;
 23-  retryJitterFactor?: number;
 24   retryMaxDelayMs?: number;
 25 }
 26 
 27@@ -161,20 +154,8 @@ export async function runRenewalDispatcher(
 28   let retriedJobs = 0;
 29   let skippedJobs = 0;
 30   let successfulJobs = 0;
 31-  const random = options.random ?? Math.random;
 32-  let dispatchedAtLeastOne = false;
 33 
 34   for (const job of dueJobs) {
 35-    if (dispatchedAtLeastOne) {
 36-      const jitterMs = sampleUniformJitterMs(random, {
 37-        maxMs: options.interJobJitterMaxMs,
 38-        minMs: options.interJobJitterMinMs
 39-      });
 40-      if (jitterMs > 0) {
 41-        await sleep(jitterMs);
 42-      }
 43-    }
 44-
 45     const dispatchContext = await resolveDispatchContext(artifactStore, job);
 46 
 47     if (dispatchContext.conversation == null) {
 48@@ -235,9 +216,7 @@ export async function runRenewalDispatcher(
 49         errorMessage: dispatchContext.link == null ? "missing_active_link" : "route_unavailable",
 50         logDir: context.logDir,
 51         now: nowMs,
 52-        random,
 53         retryBaseDelayMs: options.retryBaseDelayMs,
 54-        retryJitterFactor: options.retryJitterFactor,
 55         retryMaxDelayMs: options.retryMaxDelayMs,
 56         targetSnapshot: dispatchContext.targetSnapshot
 57       });
 58@@ -292,7 +271,6 @@ export async function runRenewalDispatcher(
 59       continue;
 60     }
 61 
 62-    dispatchedAtLeastOne = true;
 63     const runningJob = await artifactStore.updateRenewalJob({
 64       finishedAt: null,
 65       jobId: job.jobId,
 66@@ -363,9 +341,7 @@ export async function runRenewalDispatcher(
 67         errorMessage,
 68         logDir: context.logDir,
 69         now: now(),
 70-        random,
 71         retryBaseDelayMs: options.retryBaseDelayMs,
 72-        retryJitterFactor: options.retryJitterFactor,
 73         retryMaxDelayMs: options.retryMaxDelayMs,
 74         targetSnapshot: dispatchContext.targetSnapshot
 75       });
 76@@ -501,9 +477,7 @@ async function applyFailureOutcome(
 77     errorMessage: string;
 78     logDir: string | null;
 79     now: number;
 80-    random: () => number;
 81     retryBaseDelayMs?: number;
 82-    retryJitterFactor?: number;
 83     retryMaxDelayMs?: number;
 84     targetSnapshot: RenewalProjectorTargetSnapshot | null;
 85   }
 86@@ -535,9 +509,8 @@ async function applyFailureOutcome(
 87     };
 88   }
 89 
 90-  const nextAttemptAt = input.now + computeRetryDelayMs(input.attemptCount, input.random, {
 91+  const nextAttemptAt = input.now + computeRetryDelayMs(input.attemptCount, {
 92     retryBaseDelayMs: input.retryBaseDelayMs,
 93-    retryJitterFactor: input.retryJitterFactor,
 94     retryMaxDelayMs: input.retryMaxDelayMs
 95   });
 96   await artifactStore.updateRenewalJob({
 97@@ -607,21 +580,15 @@ function buildRenewalPlanId(messageId: string): string {
 98 
 99 function computeRetryDelayMs(
100   attemptCount: number,
101-  random: () => number,
102   options: {
103     retryBaseDelayMs?: number;
104-    retryJitterFactor?: number;
105     retryMaxDelayMs?: number;
106   }
107 ): number {
108   const baseDelayMs = resolvePositiveInteger(options.retryBaseDelayMs, DEFAULT_RETRY_BASE_DELAY_MS);
109   const maxDelayMs = resolvePositiveInteger(options.retryMaxDelayMs, DEFAULT_RETRY_MAX_DELAY_MS);
110-  const jitterFactor = options.retryJitterFactor ?? DEFAULT_RETRY_JITTER_FACTOR;
111   const exponent = Math.max(0, attemptCount - 1);
112-  const baseDelay = Math.min(maxDelayMs, baseDelayMs * (2 ** exponent));
113-  const jitterRange = baseDelay * Math.min(1, Math.max(0, jitterFactor));
114-  const jitter = Math.round((random() * 2 - 1) * jitterRange);
115-  return Math.max(1, baseDelay + jitter);
116+  return Math.min(maxDelayMs, baseDelayMs * (2 ** exponent));
117 }
118 
119 function normalizeDispatchPayload(
120@@ -825,24 +792,6 @@ function resolvePositiveInteger(value: number | undefined, fallback: number): nu
121   return Number.isInteger(value) && Number(value) > 0 ? Number(value) : fallback;
122 }
123 
124-function sleep(ms: number): Promise<void> {
125-  return new Promise((resolve) => {
126-    setTimeout(resolve, ms);
127-  });
128-}
129-
130-function sampleUniformJitterMs(
131-  random: () => number,
132-  options: {
133-    maxMs?: number;
134-    minMs?: number;
135-  }
136-): number {
137-  const minMs = Math.max(0, options.minMs ?? DEFAULT_INTER_JOB_JITTER_MIN_MS);
138-  const maxMs = Math.max(minMs, options.maxMs ?? DEFAULT_INTER_JOB_JITTER_MAX_MS);
139-  return Math.round(minMs + random() * (maxMs - minMs));
140-}
141-
142 function sanitizePathSegment(value: string): string {
143   const normalized = value.trim().toLowerCase().replace(/[^a-z0-9]+/gu, "-");
144   const collapsed = normalized.replace(/-+/gu, "-").replace(/^-|-$/gu, "");