( lockDir: string, staleLeaseMs: number, timeoutMs = staleLeaseMs )
| 1211 | } |
| 1212 | |
| 1213 | async function acquireWorkflowMutationLock( |
| 1214 | lockDir: string, |
| 1215 | staleLeaseMs: number, |
| 1216 | timeoutMs = staleLeaseMs |
| 1217 | ): Promise<void> { |
| 1218 | const deadline = Date.now() + timeoutMs; |
| 1219 | while (Date.now() <= deadline) { |
| 1220 | if (await acquireLeaseMutationLock(lockDir, Date.now(), staleLeaseMs)) { |
| 1221 | return; |
| 1222 | } |
| 1223 | // Jittered backoff: a fixed sleep can phase-lock with the periodic lease renewal (whose |
| 1224 | // interval is also a small constant when staleLeaseMs is short, e.g. in tests), so every |
| 1225 | // retry lands while a renewal holds the lock and waiters starve for hundreds of ms. |
| 1226 | await new Promise((resolve) => setTimeout(resolve, 2 + Math.random() * 6)); |
| 1227 | } |
| 1228 | throw new Error(`Timed out acquiring workflow mutation lock: ${lockDir}`); |
| 1229 | } |
| 1230 | |
| 1231 | async function acquireLeaseMutationLock( |
| 1232 | lockDir: string, |
no test coverage detected