Fix tunnel health check

This commit is contained in:
decolua
2026-05-21 14:30:59 +07:00
parent f9e68631d1
commit 134a70c62f
9 changed files with 113 additions and 23 deletions
+1 -1
View File
@@ -289,7 +289,7 @@ export async function spawnQuickTunnel(localPort, onUrlUpdate) {
const requestedProtocol = String(process.env.TUNNEL_TRANSPORT_PROTOCOL || process.env.CLOUDFLARED_PROTOCOL || DEFAULT_QUICK_TUNNEL_PROTOCOL).trim().toLowerCase();
const tunnelProtocol = QUICK_TUNNEL_PROTOCOLS.has(requestedProtocol) ? requestedProtocol : DEFAULT_QUICK_TUNNEL_PROTOCOL;
const child = spawn(binaryPath, ["tunnel", "--url", `http://127.0.0.1:${localPort}`, "--config", configPath, "--no-autoupdate"], {
const child = spawn(binaryPath, ["tunnel", "--url", `http://127.0.0.1:${localPort}`, "--config", configPath, "--no-autoupdate", "--retries", "99"], {
detached: false,
windowsHide: true,
cwd: os.tmpdir(),
+1 -1
View File
@@ -12,7 +12,7 @@ export const INTERNET_CHECK = {
timeoutMs: 3000,
};
export const RESTART_COOLDOWN_MS = 180000;
export const RESTART_COOLDOWN_MS = 120000;
export const NETWORK_SETTLE_MS = 2500;
export const WATCHDOG_INTERVAL_MS = 60000;
export const NETWORK_CHECK_INTERVAL_MS = 5000;
+21 -3
View File
@@ -31,6 +31,10 @@ export function isTunnelManuallyDisabled() { return tunnelSvc.cancelToken.cancel
export function isTunnelReconnecting() { return tunnelSvc.spawnInProgress; }
export function isTailscaleReconnecting() { return tailscaleSvc.spawnInProgress; }
// Callback invoked when cloudflared exits unexpectedly (set by initializeApp)
let onTunnelUnexpectedExit = null;
export function setTunnelUnexpectedExitCallback(cb) { onTunnelUnexpectedExit = cb; }
// ─── Cloudflare Tunnel ───────────────────────────────────────────────────────
async function registerTunnelUrl(shortId, tunnelUrl) {
@@ -55,10 +59,18 @@ export async function enableTunnel(localPort = 20128) {
try {
if (isCloudflaredRunning()) {
const existing = loadState();
if (existing?.tunnelUrl && await probeUrlAlive(existing.tunnelUrl)) {
if (existing?.tunnelUrl && existing?.shortId) {
const publicUrl = `https://r${existing.shortId}.abc-tunnel.us`;
console.log(`[Tunnel] already running, reuse: ${existing.tunnelUrl}`);
return { success: true, tunnelUrl: existing.tunnelUrl, shortId: existing.shortId, publicUrl, alreadyRunning: true };
// Reuse only if BOTH direct + public URL alive (avoid stale socket after network change)
const [directOk, publicOk] = await Promise.all([
probeUrlAlive(existing.tunnelUrl),
probeUrlAlive(publicUrl),
]);
if (directOk && publicOk) {
console.log(`[Tunnel] already running, reuse: ${existing.tunnelUrl}`);
return { success: true, tunnelUrl: existing.tunnelUrl, shortId: existing.shortId, publicUrl, alreadyRunning: true };
}
console.log(`[Tunnel] stale (direct=${directOk} public=${publicOk}), respawn`);
}
}
@@ -77,6 +89,12 @@ export async function enableTunnel(localPort = 20128) {
await updateSettings({ tunnelEnabled: true, tunnelUrl: url });
};
// Register exit handler BEFORE spawn so it fires even on early exit
setUnexpectedExitHandler(() => {
console.warn("[Tunnel] cloudflared exited unexpectedly, scheduling respawn");
if (onTunnelUnexpectedExit) onTunnelUnexpectedExit();
});
const { tunnelUrl } = await spawnQuickTunnel(localPort, onUrlUpdate);
console.log(`[Tunnel] spawned: ${tunnelUrl}`);
throwIfCancelled(token, "tunnel");