Add comprehensive error handling to prevent process crashes

- Global uncaughtException/unhandledRejection handlers in index.ts
- FFmpeg stdout/stderr stream error handlers in player.ts
- HTTP server and WebSocket server error handlers in server.ts
- Safe WebSocket broadcast with try-catch in websocket.ts
- Catch async errors from textMessage handler in instance.ts
- Reset voiceFramesSent counter on reconnect in client.ts

https://claude.ai/code/session_01EjpEsC2GCsvwbu4n3XC8EE
This commit is contained in:
Claude committed 2026-03-31 16:58:14 +00:00
1 parent 168f9f0286
commit 1c88dd7a35
6 files changed
+31 -1

No files matched your search

+8
View File
@@ -128,6 +128,14 @@ export class AudioPlayer extends EventEmitter {
this.logger.info({ ffmpeg: ffmpegBin }, "Using ffmpeg binary");
this.ffmpeg = spawn(ffmpegBin, args, { stdio: ["ignore", "pipe", "pipe"] });
// Prevent stream errors from crashing the process
this.ffmpeg.stdout!.on("error", (err) => {
this.logger.warn({ err }, "FFmpeg stdout error");
});
this.ffmpeg.stderr!.on("error", (err) => {
this.logger.warn({ err }, "FFmpeg stderr error");
});
let gotFirstData = false;
this.ffmpeg.stdout!.on("data", (chunk: Buffer) => {
if (!gotFirstData) {
+3 -1
View File
@@ -99,7 +99,9 @@ export class BotInstance extends EventEmitter {
private setupTsEvents(): void {
this.tsClient.on("textMessage", (msg: TS3TextMessage) => {
this.handleTextMessage(msg);
this.handleTextMessage(msg).catch((err) => {
this.logger.error({ err }, "Unhandled error in text message handler");
});
});
this.tsClient.on("disconnected", () => {
+8
View File
@@ -25,6 +25,14 @@ async function main() {
saveConfig(CONFIG_PATH, config);
const logger = createLogger(LOG_DIR);
// Prevent unhandled errors from crashing the process
process.on("uncaughtException", (err) => {
logger.error({ err }, "Uncaught exception");
});
process.on("unhandledRejection", (reason) => {
logger.error({ reason }, "Unhandled promise rejection");
});
const db = createDatabase(DB_PATH);
const apiServer = createApiServerManager(
+1
View File
@@ -114,6 +114,7 @@ export class TS3Client extends EventEmitter {
await this.client.connect();
await this.client.waitConnected();
this.clientId = this.client.clientID();
this.voiceFramesSent = 0;
this.logger.info({ clientId: this.clientId }, "Logged in (visible client)");
// Join default channel if specified
+7
View File
@@ -67,7 +67,14 @@ export function createWebServer(options: WebServerOptions): WebServer {
});
}
server.on("error", (err) => {
logger.error({ err }, "HTTP server error");
});
const wss = new WebSocketServer({ server, path: "/ws" });
wss.on("error", (err) => {
logger.error({ err }, "WebSocket server error");
});
const cleanupWs = setupWebSocket(wss, options.botManager, logger);
return {
+4
View File
@@ -39,7 +39,11 @@ export function setupWebSocket(
const message = JSON.stringify(data);
for (const client of clients) {
if (client.readyState === WebSocket.OPEN) {
try {
client.send(message);
} catch {
clients.delete(client);
}
}
}
};