Kraft102's picture
Initial deployment - WidgeTDC Cortex Backend v2.1.0
529090e
import { prisma } from '../database/prisma.js';
import { neo4jAdapter } from '../adapters/Neo4jAdapter.js';
// BootstrapGate ensures critical infra is reachable before we start listening
export class BootstrapGate {
constructor(
private readonly options = {
timeoutMs: 10000, // Increased timeout for slow container startup
redisUrl: process.env.REDIS_URL || 'redis://localhost:6379',
}
) {}
async init(): Promise<void> {
const results = await Promise.all([this.checkPostgres(), this.checkNeo4j(), this.checkRedis()]);
const failing = results.filter(r => !r.ok);
if (failing.length > 0) {
failing.forEach(f => console.error(`❌ Bootstrap check failed: ${f.service} -> ${f.error}`));
throw new Error('BootstrapGate failed');
}
console.log('✅ BootstrapGate: all critical services are reachable');
}
private async checkPostgres(): Promise<{ service: string; ok: boolean; error?: string }> {
const op = async () => {
// prisma uses configured connection (expected on port 5433 via env)
await prisma.$queryRaw`SELECT 1`;
};
return this.runWithTimeout('postgres', op);
}
private async checkNeo4j(): Promise<{ service: string; ok: boolean; error?: string }> {
const op = async () => {
const health = await neo4jAdapter.healthCheck();
if (!health.connected) throw new Error('neo4j not connected');
};
return this.runWithTimeout('neo4j', op);
}
private async checkRedis(): Promise<{ service: string; ok: boolean; error?: string }> {
const op = async () => {
// Dynamic import to avoid hard failure if dependency missing during tests
const Redis = (await import('ioredis')).default;
const client = new Redis(this.options.redisUrl, { maxRetriesPerRequest: 2 });
try {
const res = await client.ping();
if (res !== 'PONG') throw new Error(`unexpected ping reply: ${res}`);
} finally {
client.disconnect();
}
};
return this.runWithTimeout('redis', op);
}
private async runWithTimeout(
service: string,
fn: () => Promise<void>
): Promise<{ service: string; ok: boolean; error?: string }> {
const timeout = new Promise<never>((_, reject) => {
setTimeout(() => reject(new Error('timeout')), this.options.timeoutMs);
});
try {
await Promise.race([fn(), timeout]);
return { service, ok: true };
} catch (error: any) {
return { service, ok: false, error: error?.message || 'unknown error' };
}
}
}
export const bootstrapGate = new BootstrapGate();