Sentry: errors from the duel server, and cron check-ins for the rollup and backup

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0141G6xqLeNRYEtviLWSB5Up
This commit is contained in:
Eric Wagoner
2026-09-22 22:09:33 -04:00
co-authored by Claude Fable 5.1
parent 9bd203ae60
commit b25abd4d69
7 changed files with 334 additions and 4 deletions
+11
View File
@@ -10,6 +10,7 @@
//
// Caddy serves the static site and proxies /api and /ws here.
import * as Sentry from '@sentry/node';
import { createServer, type IncomingMessage, type ServerResponse } from 'node:http';
import { WebSocketServer, WebSocket } from 'ws';
import { RateLimit } from './ratelimit';
@@ -21,6 +22,15 @@ const HOST = process.env.HOST ?? '127.0.0.1';
const DATA_DIR = process.env.WH_DATA_DIR ?? '../data/rooms';
const BODY_LIMIT = 16 * 1024;
// Errors go to Sentry when a DSN is set; the SDK drops them otherwise.
if (process.env.SENTRY_DSN) {
Sentry.init({ dsn: process.env.SENTRY_DSN, environment: 'production', tracesSampleRate: 0 });
}
process.on('unhandledRejection', (reason) => {
console.error(reason);
Sentry.captureException(reason);
});
const rooms = new Rooms(new Store(DATA_DIR));
/** Opening rooms and taking seats are open to anyone; a script gets a few dozen an hour, not thousands. */
const doors = new RateLimit(40, 60 * 60 * 1000);
@@ -112,6 +122,7 @@ const server = createServer((req, res) => {
handle(req, res).catch((err: unknown) => {
if (err instanceof RoomError) return send(res, err.status, { error: err.message });
console.error(err);
Sentry.captureException(err, { extra: { url: req.url, method: req.method } });
send(res, 500, { error: 'Something went wrong on the server.' });
});
});