61 lines
2.2 KiB
JavaScript
61 lines
2.2 KiB
JavaScript
#!/usr/bin/env node
|
|
import mysql from 'mysql2/promise';
|
|
import path from 'node:path';
|
|
|
|
import { assertPortalRuntimePath, hashArtifact } from '../release-gate/artifact.mjs';
|
|
import { createLocalGateStack } from '../release-gate/local-stack.mjs';
|
|
|
|
const ROOT = path.resolve(new URL('..', import.meta.url).pathname);
|
|
const runtimeRoot = assertPortalRuntimePath(path.join(ROOT, '.runtime', 'portal'), { repoRoot: ROOT });
|
|
const artifactBefore = await hashArtifact(runtimeRoot);
|
|
const runId = `cold-${new Date().toISOString().replace(/\D/g, '').slice(0, 14)}`;
|
|
const port = Number(process.env.MEMIND_RELEASE_GATE_COLD_PORT ?? 19084);
|
|
const stack = await createLocalGateStack({
|
|
root: ROOT,
|
|
runId,
|
|
port,
|
|
portalRoot: runtimeRoot,
|
|
nodeEnv: 'production',
|
|
runtimeProfile: 'production',
|
|
});
|
|
|
|
try {
|
|
const firstStatus = await fetch(`${stack.baseUrl}/auth/status`, {
|
|
signal: AbortSignal.timeout(5_000),
|
|
});
|
|
if (!firstStatus.ok) throw new Error(`first health check failed: ${firstStatus.status}`);
|
|
|
|
const connection = await mysql.createConnection(stack.mysqlUrl);
|
|
let initializedTables;
|
|
try {
|
|
const [rows] = await connection.query(
|
|
`SELECT COUNT(*) AS count
|
|
FROM information_schema.tables
|
|
WHERE table_schema = DATABASE()`,
|
|
);
|
|
initializedTables = Number(rows[0]?.count ?? 0);
|
|
} finally {
|
|
await connection.end();
|
|
}
|
|
if (initializedTables < 10) {
|
|
throw new Error(`database initialization is incomplete: ${initializedTables} tables`);
|
|
}
|
|
|
|
await stack.restartPortal();
|
|
const restartedStatus = await fetch(`${stack.baseUrl}/auth/status`, {
|
|
signal: AbortSignal.timeout(5_000),
|
|
});
|
|
if (!restartedStatus.ok) throw new Error(`restart health check failed: ${restartedStatus.status}`);
|
|
|
|
console.log('PASS REL-06 packaged runtime cold-starts with NODE_ENV=production');
|
|
console.log(`PASS REL-06 isolated database initialized ${initializedTables} tables and restart is idempotent`);
|
|
} finally {
|
|
await stack.cleanup();
|
|
const artifactAfter = await hashArtifact(runtimeRoot);
|
|
if (artifactAfter.sha256 !== artifactBefore.sha256) {
|
|
throw new Error(
|
|
`packaged runtime mutated its own artifact during cold start: ${artifactBefore.sha256} -> ${artifactAfter.sha256}`,
|
|
);
|
|
}
|
|
}
|