- 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
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, "");