fix(tailscale): cap enable-flow health wait at 20s
Enable waited out the full 180s HEALTH_CHECK.timeoutMs when funnel URL DNS was unreachable, making the toggle hang ~3 minutes before returning success. waitForHealth now takes an optional timeoutMs; enable uses HEALTH_CHECK.enableTimeoutMs (20s) while watchdog/cloudflare keep 180s. Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
@@ -2,6 +2,7 @@
|
|||||||
export const HEALTH_CHECK = {
|
export const HEALTH_CHECK = {
|
||||||
intervalMs: 2000,
|
intervalMs: 2000,
|
||||||
timeoutMs: 180000,
|
timeoutMs: 180000,
|
||||||
|
enableTimeoutMs: 20000, // Enable flow waits short; watchdog re-verifies afterwards
|
||||||
fetchTimeoutMs: 8000,
|
fetchTimeoutMs: 8000,
|
||||||
dnsTimeoutMs: 3000,
|
dnsTimeoutMs: 3000,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -18,12 +18,12 @@ export async function probeUrlAlive(url) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function waitForHealth(url, cancelToken = { cancelled: false }) {
|
export async function waitForHealth(url, cancelToken = { cancelled: false }, { timeoutMs = HEALTH_CHECK.timeoutMs } = {}) {
|
||||||
const start = Date.now();
|
const start = Date.now();
|
||||||
while (Date.now() - start < HEALTH_CHECK.timeoutMs) {
|
while (Date.now() - start < timeoutMs) {
|
||||||
if (cancelToken.cancelled) throw new Error("cancelled");
|
if (cancelToken.cancelled) throw new Error("cancelled");
|
||||||
if (await probeUrlAlive(url)) return true;
|
if (await probeUrlAlive(url)) return true;
|
||||||
await new Promise((r) => setTimeout(r, HEALTH_CHECK.intervalMs));
|
await new Promise((r) => setTimeout(r, HEALTH_CHECK.intervalMs));
|
||||||
}
|
}
|
||||||
throw new Error(`Health check timeout after ${HEALTH_CHECK.timeoutMs}ms`);
|
throw new Error(`Health check timeout after ${timeoutMs}ms`);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { loadState, generateShortId } from "../shared/state.js";
|
import { loadState, generateShortId } from "../shared/state.js";
|
||||||
import { startFunnel, stopFunnel, isTailscaleRunning, isTailscaleRunningStrict, isTailscaleLoggedIn, isTailscaleLoggedInStrict, startLogin, startDaemonWithPassword, provisionCert } from "./tailscale.js";
|
import { startFunnel, stopFunnel, isTailscaleRunning, isTailscaleRunningStrict, isTailscaleLoggedIn, isTailscaleLoggedInStrict, startLogin, startDaemonWithPassword, provisionCert } from "./tailscale.js";
|
||||||
import { waitForHealth } from "./healthCheck.js";
|
import { waitForHealth } from "./healthCheck.js";
|
||||||
|
import { HEALTH_CHECK } from "./config.js";
|
||||||
import { getSettings, updateSettings } from "@/lib/localDb";
|
import { getSettings, updateSettings } from "@/lib/localDb";
|
||||||
import { getCachedPassword, loadEncryptedPassword, initDbHooks } from "@/mitm/manager";
|
import { getCachedPassword, loadEncryptedPassword, initDbHooks } from "@/mitm/manager";
|
||||||
|
|
||||||
@@ -88,7 +89,7 @@ export async function enableTailscale(localPort = 20128) {
|
|||||||
// Verify funnel serves /api/health — timeout is non-fatal (DNS may still be propagating)
|
// Verify funnel serves /api/health — timeout is non-fatal (DNS may still be propagating)
|
||||||
let reachableNow = false;
|
let reachableNow = false;
|
||||||
try {
|
try {
|
||||||
await waitForHealth(result.tunnelUrl, token);
|
await waitForHealth(result.tunnelUrl, token, { timeoutMs: HEALTH_CHECK.enableTimeoutMs });
|
||||||
reachableNow = true;
|
reachableNow = true;
|
||||||
} catch (he) {
|
} catch (he) {
|
||||||
if (!he.message.startsWith("Health check timeout")) throw he;
|
if (!he.message.startsWith("Health check timeout")) throw he;
|
||||||
|
|||||||
Reference in New Issue
Block a user