Gitea Actions Runner Test / test-job (push) Successful in 1s
CI / check (push) Successful in 30s
CI / tests-integration (push) Successful in 1m48s
CI / tests-unit (push) Failing after 1m54s
CI / tests-ui (push) Successful in 2m46s
CI / preflight (push) Skipped
CI / deploy (push) Skipped
The deploy failed with "Expected release never became healthy" after 30 attempts. Root cause: read_active_port() counted the slots answering /api/health and only consulted the nginx upstream when the count was not exactly one. On this host both slots were healthy, so it fell back to the upstream file, but a leftover epicnext-cms:local replica was holding slot A (3002). The candidate was assigned that occupied port, docker run died with EADDRINUSE, and the health probe then answered from the pre-existing container on that port. That container reports release "unknown" because it was built without NEXT_DEPLOYMENT_ID, so the release comparison could never match and the deploy timed out blaming a release that was never serving. read_active_port() now orders its sources by how well they describe reality: 1. The nginx upstream file. It is the only source that says where public traffic actually enters; everything below it is a consequence. 2. A healthy slot matching that pointer. 3. The other slot when the pointer names a dead port. 4. The pointer itself when nothing answers, so rollback still has a target. 5. Slot A when no upstream file exists at all. answers_health() was added as a retry-free sibling of healthy(); port detection should not spend 90 seconds per slot on a process that is either running now or never will. start_candidate() now calls assert_port_free() before docker run, so an occupied port fails immediately and names the listener and the containers involved, instead of surfacing later as a misleading health-check timeout. Added scripts/ci-deploy-ports.test.sh, which extracts the two functions from the real script rather than copying them, and covers the regression: with both slots healthy and nginx serving slot B, the result must not be slot A. Verified the test fails against the old logic and passes against the new. Wired into the check job so this is caught before an image is built.
Scripts Documentation
This directory contains utility scripts for managing the EpicNext-Cms project.
Scripts Overview
| Script | Description |
|---|---|
dashboard.sh |
Main interactive menu to run all other scripts. |
deploy.sh |
Safely redeploys the application by freeing the port first. |
logs.sh |
View logs for cms and mariadb services. |
backup.sh |
Creates a database backup in /backups. |
db-restore.sh |
Restores a database backup. |
db-optimize.sh |
Optimizes database tables. |
docker-prune.sh |
Cleans up unused Docker resources. |
verify-deploy.sh |
Checks if the CMS is reachable after deployment. |
check-env.sh |
Validates .env against .env.example. |
check-security.sh |
Runs pnpm audit and checks for image updates. |
monitor.sh |
Shows system disk/container resource usage. |
perf-report.sh |
Runs performance profiling. |
setup-dev.sh |
Configures development environment. |
check-updates.sh |
Checks for package and image updates. |
maintenance.sh |
Toggles maintenance mode flag. |
doctor.sh |
Runs a system diagnostic report. |
setup-cron.sh |
Configures automated cron jobs. |
alert.sh |
Sends notifications to a configured webhook. |
Usage
Run any script directly, or use the dashboard:
./scripts/dashboard.sh