Add backoff reconnecting
This commit is contained in:
parent
4ab2078afd
commit
b6d670deac
1 changed files with 126 additions and 109 deletions
47
src/cli.ts
47
src/cli.ts
|
|
@ -101,13 +101,13 @@ function tryParseHookEvent(
|
|||
|
||||
async function main() {
|
||||
const args = parseArgs();
|
||||
const { cols, rows } = getTerminalSize();
|
||||
|
||||
let pty: IPty | null = null;
|
||||
let ws: WebSocket | null = null;
|
||||
let isExiting = false;
|
||||
let isAuthenticated = false;
|
||||
let reconnectTimer: Timer | null = null;
|
||||
let reconnectDelay = 1000; // Start at 1s, back off exponentially
|
||||
const maxReconnectDelay = 30000; // Cap at 30s
|
||||
const disposables: Array<{ dispose: () => void }> = [];
|
||||
let lineBuffer = "";
|
||||
|
||||
|
|
@ -136,7 +136,10 @@ async function main() {
|
|||
process.on("SIGINT", cleanup);
|
||||
process.on("SIGTERM", cleanup);
|
||||
|
||||
// Spawn claude with PTY
|
||||
// Spawn PTY only after WebSocket connects
|
||||
const spawnClaude = () => {
|
||||
const { cols, rows } = getTerminalSize();
|
||||
|
||||
pty = spawn("claude", args.claudeArgs, {
|
||||
name: "xterm-256color",
|
||||
cols,
|
||||
|
|
@ -157,12 +160,12 @@ async function main() {
|
|||
}
|
||||
});
|
||||
|
||||
// Forward PTY output to stdout AND WebSocket (if authenticated)
|
||||
// Forward PTY output to stdout AND WebSocket
|
||||
disposables.push(
|
||||
pty.onData((data: string) => {
|
||||
process.stdout.write(data);
|
||||
|
||||
if (ws && ws.readyState === WebSocket.OPEN && isAuthenticated) {
|
||||
if (ws && ws.readyState === WebSocket.OPEN) {
|
||||
// Send output to server
|
||||
const outputMsg: ClientMessage = { type: "output", data };
|
||||
ws.send(JSON.stringify(outputMsg));
|
||||
|
|
@ -244,8 +247,9 @@ async function main() {
|
|||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// Connect to server
|
||||
// Connect to server first, then spawn claude
|
||||
const connect = () => {
|
||||
if (isExiting) return;
|
||||
|
||||
|
|
@ -254,6 +258,9 @@ async function main() {
|
|||
ws.onopen = () => {
|
||||
if (!ws) return;
|
||||
|
||||
// Reset backoff on successful connection
|
||||
reconnectDelay = 1000;
|
||||
|
||||
const command = `claude ${args.claudeArgs.join(" ")}`;
|
||||
const msg: ClientMessage = {
|
||||
type: "auth",
|
||||
|
|
@ -269,8 +276,11 @@ async function main() {
|
|||
const msg: ServerMessage = JSON.parse(event.data);
|
||||
|
||||
if (msg.type === "authenticated") {
|
||||
isAuthenticated = true;
|
||||
console.debug(`Authenticated with session ID: ${msg.session_id}`);
|
||||
console.debug(`Connected to ${args.server}`);
|
||||
// Only spawn claude after authenticated
|
||||
if (!pty) {
|
||||
spawnClaude();
|
||||
}
|
||||
} else if (msg.type === "input") {
|
||||
if (pty) {
|
||||
pty.write(msg.data);
|
||||
|
|
@ -287,24 +297,31 @@ async function main() {
|
|||
}
|
||||
};
|
||||
|
||||
ws.onerror = (event) => {
|
||||
console.error("WebSocket error:", event);
|
||||
ws.onerror = () => {
|
||||
// Error details come through onclose, suppress here
|
||||
};
|
||||
|
||||
ws.onclose = () => {
|
||||
if (isExiting) return;
|
||||
|
||||
// Reset auth flag on disconnect
|
||||
isAuthenticated = false;
|
||||
const hadPty = pty !== null;
|
||||
|
||||
// Try to reconnect after 2 seconds
|
||||
if (hadPty) {
|
||||
console.error(`Disconnected from server (retry in ${reconnectDelay / 1000}s)`);
|
||||
} else {
|
||||
console.error(`Waiting for server at ${args.server} (retry in ${reconnectDelay / 1000}s)`);
|
||||
}
|
||||
|
||||
// Exponential backoff for reconnection
|
||||
reconnectTimer = setTimeout(() => {
|
||||
console.debug("Reconnecting to server...");
|
||||
connect();
|
||||
}, 2000);
|
||||
}, reconnectDelay);
|
||||
|
||||
reconnectDelay = Math.min(reconnectDelay * 2, maxReconnectDelay);
|
||||
};
|
||||
};
|
||||
|
||||
console.error(`Connecting to ${args.server}...`);
|
||||
connect();
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue