infra(relationship-worker): 🧱 Standardize health check endpoints and logging configuration for improved observability

Co-Authored-By: Lilith Autocommit <noreply@atlilith.com>
This commit is contained in:
autocommit 2026-04-12 19:01:17 -07:00
parent 3fb42f3723
commit c7358a3ef5
3 changed files with 109 additions and 0 deletions

View file

@ -0,0 +1,40 @@
export interface WorkerConfig {
databaseUrl: string;
modelBossUrl: string;
modelBossApiKey: string | null;
modelBossModel: string;
healthPort: number;
}
function required(name: string): string {
const value = process.env[name];
if (!value || value.trim().length === 0) {
throw new Error(`Missing required env var: ${name}`);
}
return value.trim();
}
function optional(name: string, fallback: string): string {
const value = process.env[name];
return value && value.trim().length > 0 ? value.trim() : fallback;
}
function intEnv(name: string, fallback: number): number {
const raw = process.env[name];
if (!raw) return fallback;
const parsed = parseInt(raw, 10);
if (isNaN(parsed)) {
throw new Error(`Env var ${name} must be a number, got "${raw}"`);
}
return parsed;
}
export function loadConfig(): WorkerConfig {
return {
databaseUrl: required('DATABASE_URL'),
modelBossUrl: required('MODEL_BOSS_URL'),
modelBossApiKey: process.env.MODEL_BOSS_API_KEY?.trim() || null,
modelBossModel: optional('MODEL_BOSS_MODEL', 'auto'),
healthPort: intEnv('HEALTH_PORT', 3803),
};
}

View file

@ -0,0 +1,43 @@
import { createServer, type Server } from 'node:http';
import { log } from './logger';
export interface HealthState {
modelBossReachable: boolean;
lastJobAt: Date | null;
lastCompletedAt: Date | null;
}
export function startHealthServer(port: number, getState: () => HealthState): Server {
const server = createServer((req, res) => {
if (req.url === '/health/live') {
res.writeHead(200, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({ status: 'live' }));
return;
}
if (req.url === '/health' || req.url === '/health/ready') {
const state = getState();
const status = state.modelBossReachable ? 200 : 503;
res.writeHead(status, { 'Content-Type': 'application/json' });
res.end(
JSON.stringify({
status: state.modelBossReachable ? 'ok' : 'degraded',
modelBossReachable: state.modelBossReachable,
lastJobAt: state.lastJobAt?.toISOString() ?? null,
lastCompletedAt: state.lastCompletedAt?.toISOString() ?? null,
}),
);
return;
}
res.writeHead(404);
res.end();
});
server.listen(port, () => {
log.info('Health server listening', { port });
});
return server;
}

View file

@ -0,0 +1,26 @@
type Level = 'debug' | 'info' | 'warn' | 'error';
function emit(level: Level, message: string, data?: object): void {
const entry = {
timestamp: new Date().toISOString(),
level,
service: 'relationship-worker',
message,
...(data ?? {}),
};
const line = JSON.stringify(entry);
if (level === 'error') {
console.error(line);
} else if (level === 'warn') {
console.warn(line);
} else {
console.log(line);
}
}
export const log = {
debug: (message: string, data?: object) => emit('debug', message, data),
info: (message: string, data?: object) => emit('info', message, data),
warn: (message: string, data?: object) => emit('warn', message, data),
error: (message: string, data?: object) => emit('error', message, data),
};