| 219 | * a real reboot. Throws if it never goes down within the deadline. |
| 220 | */ |
| 221 | export const waitForHttpDown = async ( |
| 222 | url: string, |
| 223 | options: { readonly timeoutMs?: number } = {}, |
| 224 | ): Promise<void> => { |
| 225 | const deadline = Date.now() + (options.timeoutMs ?? 120_000); |
| 226 | while (Date.now() < deadline) { |
| 227 | try { |
| 228 | await fetch(url, { redirect: "manual", signal: AbortSignal.timeout(2000) }); |
| 229 | } catch { |
| 230 | return; // the server (or its tunnel) is gone — the reboot took |
| 231 | } |
| 232 | await new Promise((resolve) => setTimeout(resolve, 500)); |
| 233 | } |
| 234 | throw new Error(`${url} never became unreachable — the reboot may not have taken`); |
| 235 | }; |