Skip to content

Commit 1f08ffe

Browse files
committed
Honor coordinator lease retry timing
1 parent 1215172 commit 1f08ffe

3 files changed

Lines changed: 21 additions & 2 deletions

File tree

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
const DEFAULT_RETRY_DELAY_MS = 1_000
2+
3+
export function leaseRetryDelayMs(retryAfterSeconds: number | undefined, remainingMs: number): number {
4+
const requestedMs = retryAfterSeconds !== undefined && Number.isFinite(retryAfterSeconds) && retryAfterSeconds > 0
5+
? retryAfterSeconds * 1_000
6+
: DEFAULT_RETRY_DELAY_MS
7+
return Math.max(0, Math.min(remainingMs, requestedMs))
8+
}

packages/runtime-cloudflare/src/worker.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { bootWordPressAndRequestHandler, type WordPressInstallMode } from "@wp-p
66
import { dependenciesTotalSize, init } from "../../../node_modules/@php-wasm/web-8-5/asyncify/php_8_5.js"
77
import phpWasmModule from "../../../node_modules/@php-wasm/web-8-5/asyncify/8_5_8/php_8_5.wasm"
88
import { CLOUDFLARE_RUNTIME_HEALTH_MARKER, CLOUDFLARE_RUNTIME_HEALTH_SCHEMA, cloudflareRuntimeHealthResponse } from "./health-envelope.js"
9+
import { leaseRetryDelayMs } from "./lease-retry.js"
910
import { routeWorkerRequest } from "./request-routing.js"
1011
import { toFetchResponse, toPHPRequest } from "./request-translation.js"
1112
import { deriveWordPressAuthConstants, type WordPressAuthConstant } from "./wordpress-auth.js"
@@ -228,13 +229,15 @@ async function coordinatorCall<T>(coordinator: DurableObjectStub, requestUrl: st
228229
async function acquireLease(coordinator: DurableObjectStub, requestUrl: string): Promise<Lease> {
229230
const deadline = Date.now() + LEASE_ACQUISITION_TIMEOUT_MS
230231
let lastError: CoordinatorRequestError | undefined
231-
while (Date.now() < deadline) {
232+
while (true) {
233+
const remainingMs = deadline - Date.now()
234+
if (remainingMs <= 0) break
232235
try {
233236
return await coordinatorCall<Lease>(coordinator, requestUrl, "begin", {})
234237
} catch (error) {
235238
if (!(error instanceof CoordinatorRequestError) || error.status !== 409) throw error
236239
lastError = error
237-
await new Promise((resolve) => setTimeout(resolve, Math.min(250, Math.max(25, (error.retryAfter ?? 1) * 100))))
240+
await new Promise((resolve) => setTimeout(resolve, leaseRetryDelayMs(error.retryAfter, deadline - Date.now())))
238241
}
239242
}
240243
throw new Error(`Timed out waiting for the canonical WordPress lease${lastError ? `: ${lastError.message}` : "."}`)

tests/cloudflare-runtime.test.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import test from "node:test"
77
import { decodeZip, encodeZip } from "@php-wasm/stream-compression"
88
import { RUNTIME_COMMAND_RESULT_SCHEMA } from "../packages/runtime-core/src/runtime-contracts.js"
99
import { CLOUDFLARE_RUNTIME_HEALTH_MARKER, CLOUDFLARE_RUNTIME_HEALTH_SCHEMA, cloudflareRuntimeHealthResponse } from "../packages/runtime-cloudflare/src/health-envelope.js"
10+
import { leaseRetryDelayMs } from "../packages/runtime-cloudflare/src/lease-retry.js"
1011
import { routeWorkerRequest } from "../packages/runtime-cloudflare/src/request-routing.js"
1112
import { toFetchResponse, toPHPRequest } from "../packages/runtime-cloudflare/src/request-translation.js"
1213
import { WordPressStateCoordinator } from "../packages/runtime-cloudflare/src/state-coordinator.js"
@@ -106,6 +107,13 @@ test("Cloudflare runtime declares the paid-plan WordPress boot CPU budget", asyn
106107
assert.equal(config.limits?.cpu_ms, 300_000)
107108
})
108109

110+
test("Cloudflare lease contention honors Retry-After without exceeding the acquisition deadline", () => {
111+
assert.equal(leaseRetryDelayMs(90, 100_000), 90_000)
112+
assert.equal(leaseRetryDelayMs(90, 12_345), 12_345)
113+
assert.equal(leaseRetryDelayMs(undefined, 100_000), 1_000)
114+
assert.equal(leaseRetryDelayMs(Number.NaN, 500), 500)
115+
})
116+
109117
test("Cloudflare runtime packages a provenanced canonical MDI seed", async () => {
110118
const config = JSON.parse((await readFile(new URL("../packages/runtime-cloudflare/wrangler.jsonc", import.meta.url), "utf8")).replace(/^\s*\/\/.*\n/, "")) as {
111119
rules?: Array<{ type?: string; globs?: string[] }>

0 commit comments

Comments
 (0)