fix: exit cleanly on fatal startup errors instead of crash-looping#69
Open
AminDhouib wants to merge 2 commits into
Open
fix: exit cleanly on fatal startup errors instead of crash-looping#69AminDhouib wants to merge 2 commits into
AminDhouib wants to merge 2 commits into
Conversation
…okploy#4253) After "Migration complete", a fatal error in the server startup window (e.g. a rejected `app.prepare()`) did not terminate the process. Background handles — the ioredis reconnect loop, open sockets — kept the event loop alive, so instead of exiting the process spun at high CPU, never passed the healthcheck, and Docker Swarm crash-looped the container showing only "ELIFECYCLE Command failed." Reproduced with the real compiled bundle (node:24.4.0-slim + Postgres 16): - before: fatal startup error -> process never exits, spins until killed - after: fatal startup error -> logs the cause, exits 1 in ~3-5s Changes in apps/dokploy/server/server.ts: - Phase-gated process handlers: before the HTTP server is listening, an uncaught exception or unhandled rejection logs the cause and exit(1)s so the orchestrator restarts cleanly. After it is listening, a stray rejection is only logged, so a healthy serving instance is never killed (verified: real post-listen docker.sock ENOENT rejection is survived). - try/catch around the synchronous directory/Traefik init. - await the listen() bind so a bind failure (e.g. EADDRINUSE) exits instead of spinning; only mark the server ready once actually listening. - .catch() on app.prepare() with a labeled diagnostic. (cherry picked from commit 9e122de)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Ports Dokploy#4601 by @apotema (1 commit, cherry-picked with
-x, original authorship preserved).Addresses Dokploy#4253 (verified: linked via the upstream PR's closing references; the diff directly targets the crash-loop-on-startup behavior described there).
What / why
A fatal error during startup (rejected
app.prepare(), failed directory/Traefik init,EADDRINUSEon listen) previously left the process alive but unserviceable: background handles (Redis reconnect loop, sockets) kept the event loop spinning at ~100% CPU, the healthcheck never passed, and the container crash-looped with only an opaqueELIFECYCLE Command failed.Changes in
apps/dokploy/server/server.ts:isServerListeningflag distinguishes pre-listen fatal errors from post-listen runtime errors.uncaughtExceptionhandler: log, thenexit(1)(preserves Node default, adds cause logging).unhandledRejectionhandler:exit(1)only before the server is listening; log-only afterwards.exit(1)on failure.server.listenis now awaited via a promise that rejects on theerrorevent, so bind failures exit cleanly..catchonapp.prepare()chain: log +exit(1).1when failure happens before listening.Adaptations
One conflict in the deployment-worker block: the fork starts its worker via
startDeploymentWorker()from./queues/queueSetup(upstream usesdeploymentWorker.run()from./queues/deployments-queue). Resolved by keeping the fork's worker call inside upstream's new error-handling structure. No functional deviation otherwise.Test evidence
pnpm --filter=dokploy run typecheck: clean.Overlap notes
No file overlap with open fork PRs #36/#58 or with the other salvo-2 M2 ports (only this item touches
server.ts).