Spaces:
Paused
Paused
File size: 2,591 Bytes
529090e | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 | 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();
|