Files
mahmoodandCursor 15adbb7fe1 fix(api): survive existing-schema boots without DB shell
Nginx 502 Host-not-found meant the API never stayed listening. Stamp all
migrations when tracking is empty but a late table exists, apply DDL
statement-by-statement skipping already-exists, harden remaining CREATE
TYPE/TABLE files, and never let seed crash the process.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-27 17:35:25 +03:30

71 lines
2.2 KiB
TypeScript

import { execFile } from 'child_process';
import { existsSync } from 'fs';
import { join } from 'path';
import { promisify } from 'util';
import { Logger } from '@nestjs/common';
import { PrismaClient } from '@prisma/client';
import { logDataDiagnostics } from './diagnostics';
import { runMigrations, runOnce } from './migrate';
const execFileAsync = promisify(execFile);
function resolveSeedScript(): string | undefined {
const candidates = [
process.env.SEED_SCRIPT,
join(process.cwd(), 'seed.js'),
join(__dirname, '..', '..', 'seed.js'),
].filter((p): p is string => Boolean(p));
return candidates.find((file) => existsSync(file));
}
/**
* Runs pending SQL migrations before Nest boots, then seeds once.
*
* Seeding is gated on a marker row written only after the seed succeeds, so an
* interrupted seed is retried on the next boot (the seed itself upserts).
* Set RUN_MIGRATIONS=false or RUN_SEED=false to skip.
*/
export async function prepareDatabase(): Promise<void> {
if (process.env.RUN_MIGRATIONS === 'false') return;
const logger = new Logger('DatabaseBootstrap');
const prisma = new PrismaClient();
try {
const { applied } = await runMigrations(prisma);
if (applied.length > 0) {
logger.log(`Applied migrations: ${applied.join(', ')}`);
} else {
logger.log('No pending migrations');
}
// TEMPORARY — see diagnostics.ts. Never throws.
await logDataDiagnostics(prisma);
if (process.env.RUN_SEED === 'false') return;
const seedScript = resolveSeedScript();
if (!seedScript) {
logger.warn('No seed script found — skipping seed');
return;
}
try {
const seeded = await runOnce(prisma, 'seed:initial', async () => {
const { stdout } = await execFileAsync(process.execPath, [seedScript]);
if (stdout.trim()) logger.log(stdout.trim());
});
if (seeded) logger.log('Seed data inserted');
} catch (err) {
// Seed must never crash-loop the API (nginx Host not found / 502).
logger.warn(
`Seed skipped after error: ${err instanceof Error ? err.message : String(err)}`,
);
}
} finally {
await prisma.$disconnect();
}
}