fix: crash loop recovery, auto-migrations, CI test pipeline
- Wrap startup syncs in safeStartup() to prevent crash on external service failure - Add migrate-entrypoint.sh for auto-generating migrations from schema diff - Update Dockerfile migration stage to use entrypoint script - Add test job to build-and-publish workflow (runs before build) - Add tests.yaml workflow to run tests on every push - Fix test setup to use real RSA key pair instead of plain strings - Add test script to package.json
This commit is contained in:
+29
-10
@@ -45,36 +45,55 @@ if (!existingAdmin) {
|
||||
events.emit("role:created", new RoleController(created));
|
||||
}
|
||||
|
||||
// Helper to run a startup sync safely — failures are logged but never crash the process.
|
||||
const safeStartup = async (label: string, fn: () => Promise<void>) => {
|
||||
try {
|
||||
await fn();
|
||||
} catch (err) {
|
||||
console.error(`[startup] ${label} failed — will retry on next interval`, err);
|
||||
}
|
||||
};
|
||||
|
||||
// Refresh the internal list of companies every minute
|
||||
await refreshCompanies();
|
||||
await safeStartup("refreshCompanies", refreshCompanies);
|
||||
setInterval(() => {
|
||||
return refreshCompanies();
|
||||
return refreshCompanies().catch((err) =>
|
||||
console.error("[interval] refreshCompanies failed", err),
|
||||
);
|
||||
}, 60 * 1000);
|
||||
|
||||
// Refresh the internal catalog every minute
|
||||
await refreshCatalog();
|
||||
await safeStartup("refreshCatalog", refreshCatalog);
|
||||
setInterval(() => {
|
||||
return refreshCatalog();
|
||||
return refreshCatalog().catch((err) =>
|
||||
console.error("[interval] refreshCatalog failed", err),
|
||||
);
|
||||
}, 60 * 1000);
|
||||
|
||||
// Refresh inventory on hand every 2 minutes
|
||||
await refreshInventory();
|
||||
await safeStartup("refreshInventory", refreshInventory);
|
||||
setInterval(
|
||||
() => {
|
||||
return refreshInventory();
|
||||
return refreshInventory().catch((err) =>
|
||||
console.error("[interval] refreshInventory failed", err),
|
||||
);
|
||||
},
|
||||
2 * 60 * 1000,
|
||||
);
|
||||
|
||||
// Refresh opportunities every minute
|
||||
await refreshOpportunities();
|
||||
await safeStartup("refreshOpportunities", refreshOpportunities);
|
||||
setInterval(() => {
|
||||
return refreshOpportunities();
|
||||
return refreshOpportunities().catch((err) =>
|
||||
console.error("[interval] refreshOpportunities failed", err),
|
||||
);
|
||||
}, 60 * 1000);
|
||||
|
||||
await unifiSites.syncSites();
|
||||
await safeStartup("syncSites", () => unifiSites.syncSites());
|
||||
setInterval(() => {
|
||||
return unifiSites.syncSites();
|
||||
return unifiSites.syncSites().catch((err) =>
|
||||
console.error("[interval] syncSites failed", err),
|
||||
);
|
||||
}, 60 * 1000);
|
||||
|
||||
Bun.serve({
|
||||
|
||||
Reference in New Issue
Block a user