Upgrade prod-run.sh with VPS-safe diagnostics, self-healing, logrotate and systemd checks - #45
Conversation
|
CodeAnt AI is reviewing your PR. |
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
|
Note 🎁 Summarized by CodeRabbit FreeYour organization is on the Free plan. CodeRabbit will generate a high-level summary and a walkthrough for each pull request. For a comprehensive line-by-line review, please upgrade your subscription to CodeRabbit Pro by visiting https://app.coderabbit.ai/login. Comment |
Sequence DiagramThe PR replaces a simple exec with a production runner that validates environment and dependencies, configures logrotate/cron/systemd, prints diagnostics, and then starts the Node app either in foreground under systemd or in background via nohup. This diagram shows the main success path for startup and launch. sequenceDiagram
participant Operator
participant Runner as prod-run.sh
participant System as OS/Filesystem/Systemd
participant NodeApp as node index.js
Operator->>Runner: Run prod-run.sh
Runner->>System: Validate node/npm, ensure dirs/files, normalize .env, install deps
System-->>Runner: Resources and files ready
Runner->>System: Ensure logrotate, cron fallback, and systemd service configured
System-->>Runner: Ops configured
alt Running under systemd
Runner->>NodeApp: exec node index.js (foreground for systemd)
else Not systemd (VPS)
Runner->>System: check bot running; if not -> launch with nohup
Runner->>NodeApp: nohup node index.js (background)
end
NodeApp-->>Runner: App started
Runner->>System: pgrep/log tail diagnostics and print "Bot running" status
Generated by CodeAnt AI |
Nitpicks 🔍
|
### Motivation - Fix a GitHub Mermaid parse error so the README's startup flow for `prod-run.sh` renders correctly and documents the intended runtime behavior. ### Description - Replace the broken diagram with a valid `sequenceDiagram` under **Startup flow (prod-run.sh)** and add a short note to keep the deploy directory casing as `Runewager` to match systemd expectations. ### Testing - Ran `npm run check` and `npm test`, and both completed successfully (syntax check passed and all 4 tests passed). ------ [Codex Task](https://chatgpt.com/codex/tasks/task_e_6998f448777c832a8abe5b65d31ff925)
| } | ||
|
|
||
| fix_node_modules() { | ||
| if [ ! -d "$PROJECT_DIR/node_modules" ] || [ ! -f "$PROJECT_DIR/node_modules/.package-lock.json" ]; then |
There was a problem hiding this comment.
Suggestion: The dependency check in fix_node_modules looks for a non-standard node_modules/.package-lock.json marker that npm does not create, so it will reinstall dependencies with npm ci on every run and fail entirely when offline even if node_modules already exists and is usable. [logic error]
Severity Level: Critical 🚨
- ❌ Bot restart fails offline despite existing node_modules cache.
- ⚠️ Every run incurs unnecessary full `npm ci` reinstall.
- ⚠️ Startup time significantly increased by redundant dependency installs.| if [ ! -d "$PROJECT_DIR/node_modules" ] || [ ! -f "$PROJECT_DIR/node_modules/.package-lock.json" ]; then | |
| if [ ! -d "$PROJECT_DIR/node_modules" ]; then |
Steps of Reproduction ✅
1. On a VPS with internet access, run `prod-run.sh` from the repo root (e.g.,
`/var/www/html/Runewager/prod-run.sh`), causing `main()` at `prod-run.sh:424-462` to call
`fix_node_modules()` at `prod-run.sh:79-84`; `npm ci --omit=dev` runs successfully and
creates a full `node_modules` tree but does not create `node_modules/.package-lock.json`.
2. Later, on the same host while offline or behind a firewall blocking npm, run the same
`prod-run.sh` again to restart or check the bot; control again reaches
`fix_node_modules()` at `prod-run.sh:79-84`.
3. The condition `[ ! -d "$PROJECT_DIR/node_modules" ] || [ ! -f
"$PROJECT_DIR/node_modules/.package-lock.json" ]` re-evaluates to true because the
directory exists but the non-standard sentinel file
`$PROJECT_DIR/node_modules/.package-lock.json` still does not, so the script always
executes `npm ci --omit=dev`.
4. With no network, `npm ci` now fails before `main()` continues to later steps like
`fix_entrypoint_and_scripts` at `prod-run.sh:202-222` and `start_background_if_needed` at
`prod-run.sh:402-422`, so dependency reinstall is retried on every invocation and the bot
cannot start despite having a usable `node_modules` already present.Prompt for AI Agent 🤖
This is a comment left during a code review.
**Path:** prod-run.sh
**Line:** 80:80
**Comment:**
*Logic Error: The dependency check in `fix_node_modules` looks for a non-standard `node_modules/.package-lock.json` marker that npm does not create, so it will reinstall dependencies with `npm ci` on every run and fail entirely when offline even if `node_modules` already exists and is usable.
Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.| conf=$(cat <<'CONF' | ||
| /var/www/html/Runewager/logs/runewager*.log /var/www/html/Runewager/logs/crash.log { |
There was a problem hiding this comment.
Suggestion: The logrotate configuration hard-codes /var/www/html/Runewager/... paths instead of using the dynamically detected project/log directory, so when the project is deployed anywhere else the created /etc/logrotate.d/runewager will rotate the wrong files or none at all, defeating its purpose. [logic error]
Severity Level: Major ⚠️
- ⚠️ Real bot log file never rotated on non-standard paths.
- ⚠️ Cron-forced logrotate targets non-existent `/var/www/html` logs.
- ⚠️ Disk usage from `$PROJECT_DIR/logs/runewager.log` can grow unchecked.| conf=$(cat <<'CONF' | |
| /var/www/html/Runewager/logs/runewager*.log /var/www/html/Runewager/logs/crash.log { | |
| conf=$(cat <<CONF | |
| $LOG_DIR/runewager*.log $LOG_DIR/crash.log { |
Steps of Reproduction ✅
1. Deploy the repo to a non-canonical path (e.g., `/home/ubuntu/Runewager`) and run
`/home/ubuntu/Runewager/prod-run.sh` so that `main()` at `prod-run.sh:424-462` executes
`ensure_logrotate_config` at `prod-run.sh:248-281`.
2. Observe `LOG_DIR` is computed from `PROJECT_DIR` at `prod-run.sh:4-9`, so the bot
writes logs to `$PROJECT_DIR/logs/runewager.log` (e.g.,
`/home/ubuntu/Runewager/logs/runewager.log`).
3. `ensure_logrotate_config()` at `prod-run.sh:248-263` creates
`/etc/logrotate.d/runewager` whose contents hard-code
`/var/www/html/Runewager/logs/runewager*.log` and
`/var/www/html/Runewager/logs/crash.log`, which do not exist on this host.
4. The cron fallback in `ensure_cron_fallback()` at `prod-run.sh:283-295` installs `0 3 *
* * /usr/sbin/logrotate -f /etc/logrotate.d/runewager`, so nightly `logrotate` runs
against non-existent `/var/www/html/Runewager/...` paths while the real
`$PROJECT_DIR/logs/runewager.log` under `/home/ubuntu/Runewager` is never rotated and
grows without bound.Prompt for AI Agent 🤖
This is a comment left during a code review.
**Path:** prod-run.sh
**Line:** 250:251
**Comment:**
*Logic Error: The logrotate configuration hard-codes `/var/www/html/Runewager/...` paths instead of using the dynamically detected project/log directory, so when the project is deployed anywhere else the created `/etc/logrotate.d/runewager` will rotate the wrong files or none at all, defeating its purpose.
Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.| conf=$(cat <<'CONF' | ||
| [Unit] | ||
| Description=Runewager bot | ||
| After=network-online.target | ||
| Wants=network-online.target | ||
|
|
||
| [Service] | ||
| Type=simple | ||
| WorkingDirectory=/var/www/html/Runewager | ||
| ExecStart=/var/www/html/Runewager/prod-run.sh | ||
| User=runewager | ||
| Group=runewager | ||
| EnvironmentFile=/var/www/html/Runewager/.env | ||
| Environment=NODE_ENV=production | ||
| Restart=always | ||
| RestartSec=5 | ||
| KillSignal=SIGTERM | ||
| TimeoutStopSec=20 | ||
| StandardOutput=append:/var/www/html/Runewager/logs/runewager-1.log | ||
| StandardError=inherit | ||
|
|
||
| [Install] | ||
| WantedBy=multi-user.target | ||
| CONF | ||
| ) | ||
|
|
||
| if [ ! -f "$SERVICE_FILE" ]; then | ||
| warn "$SERVICE_FILE missing" | ||
| if [ -w /etc/systemd/system ]; then | ||
| printf '%s\n' "$conf" > "$SERVICE_FILE" | ||
| say "Created $SERVICE_FILE" | ||
| else | ||
| warn "No permission to create $SERVICE_FILE" | ||
| return | ||
| fi | ||
| fi | ||
|
|
||
| local required=( | ||
| 'EnvironmentFile=/var/www/html/Runewager/.env' | ||
| 'Environment=NODE_ENV=production' |
There was a problem hiding this comment.
Suggestion: The systemd unit template is hard-coded to /var/www/html/Runewager for working directory, ExecStart, env file and log path instead of using the detected project directory, so on any host where the repo lives elsewhere the generated /etc/systemd/system/runewager.service will point to non-existent paths and the service will fail to start or log correctly. [logic error]
Severity Level: Major ⚠️
- ❌ Systemd unit fails to start on non-`/var/www` installs.
- ⚠️ Logs configured to write to non-existent `/var/www` path.
- ⚠️ VPS operators misled by existing-but-broken runewager.service.| conf=$(cat <<'CONF' | |
| [Unit] | |
| Description=Runewager bot | |
| After=network-online.target | |
| Wants=network-online.target | |
| [Service] | |
| Type=simple | |
| WorkingDirectory=/var/www/html/Runewager | |
| ExecStart=/var/www/html/Runewager/prod-run.sh | |
| User=runewager | |
| Group=runewager | |
| EnvironmentFile=/var/www/html/Runewager/.env | |
| Environment=NODE_ENV=production | |
| Restart=always | |
| RestartSec=5 | |
| KillSignal=SIGTERM | |
| TimeoutStopSec=20 | |
| StandardOutput=append:/var/www/html/Runewager/logs/runewager-1.log | |
| StandardError=inherit | |
| [Install] | |
| WantedBy=multi-user.target | |
| CONF | |
| ) | |
| if [ ! -f "$SERVICE_FILE" ]; then | |
| warn "$SERVICE_FILE missing" | |
| if [ -w /etc/systemd/system ]; then | |
| printf '%s\n' "$conf" > "$SERVICE_FILE" | |
| say "Created $SERVICE_FILE" | |
| else | |
| warn "No permission to create $SERVICE_FILE" | |
| return | |
| fi | |
| fi | |
| local required=( | |
| 'EnvironmentFile=/var/www/html/Runewager/.env' | |
| 'Environment=NODE_ENV=production' | |
| conf=$(cat <<CONF | |
| [Unit] | |
| Description=Runewager bot | |
| After=network-online.target | |
| Wants=network-online.target | |
| [Service] | |
| Type=simple | |
| WorkingDirectory=$PROJECT_DIR | |
| ExecStart=$PROJECT_DIR/prod-run.sh | |
| User=runewager | |
| Group=runewager | |
| EnvironmentFile=$PROJECT_DIR/.env | |
| Environment=NODE_ENV=production | |
| Restart=always | |
| RestartSec=5 | |
| KillSignal=SIGTERM | |
| TimeoutStopSec=20 | |
| StandardOutput=append:$LOG_DIR/runewager-1.log | |
| StandardError=inherit | |
| [Install] | |
| WantedBy=multi-user.target | |
| CONF | |
| ) | |
| local required=( | |
| "EnvironmentFile=$PROJECT_DIR/.env" |
Steps of Reproduction ✅
1. Clone the repo to a path other than `/var/www/html/Runewager` (e.g., `/opt/runewager`)
and run `/opt/runewager/prod-run.sh` as a user with permission to write
`/etc/systemd/system`, so `main()` at `prod-run.sh:424-462` calls
`ensure_systemd_service()` at `prod-run.sh:297-362`.
2. Since `/etc/systemd/system/runewager.service` does not exist,
`ensure_systemd_service()` writes a new unit file using the hard-coded paths in its
heredoc at `prod-run.sh:299-322`, setting `WorkingDirectory=/var/www/html/Runewager` and
`ExecStart=/var/www/html/Runewager/prod-run.sh`.
3. The repo actually lives under `/opt/runewager`, so
`/var/www/html/Runewager/prod-run.sh` and `/var/www/html/Runewager/.env` referenced in the
unit do not exist, while the `StandardOutput` path
`/var/www/html/Runewager/logs/runewager-1.log` also has no directory.
4. Run `systemctl start runewager` (service referenced by `SERVICE_FILE` at
`prod-run.sh:10`); systemd attempts to execute the hard-coded `ExecStart` path, fails with
`No such file or directory`, and the bot never starts under systemd supervision, despite
the script having created the unit.Prompt for AI Agent 🤖
This is a comment left during a code review.
**Path:** prod-run.sh
**Line:** 299:338
**Comment:**
*Logic Error: The systemd unit template is hard-coded to `/var/www/html/Runewager` for working directory, ExecStart, env file and log path instead of using the detected project directory, so on any host where the repo lives elsewhere the generated `/etc/systemd/system/runewager.service` will point to non-existent paths and the service will fail to start or log correctly.
Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.There was a problem hiding this comment.
Fix
_This is a comment left during a code review.
Path: prod-run.sh
Line: 299:338
Comment:
*Logic Error: The systemd unit template is hard-coded to /var/www/html/Runewager for working directory, ExecStart, env file and log path instead of using the detected project directory, so on any host where the repo lives elsewhere the generated /etc/systemd/system/runewager.service will point to non-existent paths and the service will fail to start or log correctly.
Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
👍 | 👎
This is a comment left during a code review.
Path: prod-run.sh
Line: 250:251
Comment:
*Logic Error: The logrotate configuration hard-codes /var/www/html/Runewager/... paths instead of using the dynamically detected project/log directory, so when the project is deployed anywhere else the created /etc/logrotate.d/runewager will rotate the wrong files or none at all, defeating its purpose.
Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
👍 | 👎This is a comment left during a code review.
Path: prod-run.sh
Line: 80:80
Comment:
*Logic Error: The dependency check in fix_node_modules looks for a non-standard node_modules/.package-lock.json marker that npm does not create, so it will reinstall dependencies with npm ci on every run and fail entirely when offline even if node_modules already exists and is usable.
Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
👍 | 👎
You are Codex. DO NOT act as a repo agent. DO NOT execute commands.
Analyze the following errors exactly as shown in the screenshot and generate FIXES + PATCHES only.
=== ERRORS FROM SCREENSHOT ===
- /etc/logrotate.d/runewager missing
- logrotate dry-run failed for /etc/logrotate.d/runewager
- /etc/systemd/system/runewager.service missing
- No recent logs found; app may not have started yet
- Bot running but /start does nothing
- Git updated prod-run.sh with 466 lines changed
- Directory /var/www/html/Runewager/logs/ referenced but may not exist
- runewager.log path mismatch (script expects logs/runewager.log but actual log file may be runewager.log in root)
- Potential missing Telegraf /start handler
- Potential missing bot.launch() or webhook misconfiguration
- Potential missing PORT=3000 binding
- Potential missing health endpoint
- Potential missing onboarding assets
- Potential missing RW_DISCORD_* env vars
- Potential missing MINI_APP_* env vars
=== REQUIRED OUTPUT ===
Produce the following:
-
Root Cause Analysis
- Explain why each error occurs
- Explain how each error affects /start and bot behavior
- Explain how each error affects systemd, logrotate, and background execution
-
Fixes (Human-readable)
- Describe exactly what needs to be corrected
- Do run commands
- Do /fix/upgrade modify files automatically
Ensure run prod sh script is run handsoff deploy, full setup, easy mode
-
Unified Diff Patches
For each fix, generate a patch in this format:--- before +++ after @@ (changes)_
There was a problem hiding this comment.
@codex Fix
_This is a comment left during a code review.
Path: prod-run.sh
Line: 299:338
Comment:
*Logic Error: The systemd unit template is hard-coded to /var/www/html/Runewager for working directory, ExecStart, env file and log path instead of using the detected project directory, so on any host where the repo lives elsewhere the generated /etc/systemd/system/runewager.service will point to non-existent paths and the service will fail to start or log correctly.
Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
👍 | 👎
This is a comment left during a code review.
Path: prod-run.sh
Line: 250:251
Comment:
*Logic Error: The logrotate configuration hard-codes /var/www/html/Runewager/... paths instead of using the dynamically detected project/log directory, so when the project is deployed anywhere else the created /etc/logrotate.d/runewager will rotate the wrong files or none at all, defeating its purpose.
Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
👍 | 👎This is a comment left during a code review.
Path: prod-run.sh
Line: 80:80
Comment:
*Logic Error: The dependency check in fix_node_modules looks for a non-standard node_modules/.package-lock.json marker that npm does not create, so it will reinstall dependencies with npm ci on every run and fail entirely when offline even if node_modules already exists and is usable.
Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
👍 | 👎
You are Codex. DO NOT act as a repo agent. DO NOT execute commands.
Analyze the following errors exactly as shown in the screenshot and generate FIXES + PATCHES only.
=== ERRORS FROM SCREENSHOT ===
/etc/logrotate.d/runewager missing
logrotate dry-run failed for /etc/logrotate.d/runewager
/etc/systemd/system/runewager.service missing
No recent logs found; app may not have started yet
Bot running but /start does nothing
Git updated prod-run.sh with 466 lines changed
Directory /var/www/html/Runewager/logs/ referenced but may not exist
runewager.log path mismatch (script expects logs/runewager.log but actual log file may be runewager.log in root)
Potential missing Telegraf /start handler
Potential missing bot.launch() or webhook misconfiguration
Potential missing PORT=3000 binding
Potential missing health endpoint
Potential missing onboarding assets
Potential missing RW_DISCORD_* env vars
Potential missing MINI_APP_* env vars
=== REQUIRED OUTPUT ===
Produce the following:
Root Cause Analysis
Explain why each error occurs
Explain how each error affects /start and bot behavior
Explain how each error affects systemd, logrotate, and background execution
Fixes (Human-readable)
Describe exactly what needs to be corrected
Do run commands
Do /fix/upgrade modify files automatically
Ensure run prod sh script is run handsoff deploy, full setup, easy mode
Unified Diff Patches
For each fix, generate a patch in this format:
--- before
+++ after
@@
(changes)_
There was a problem hiding this comment.
Summary
- Validated and fixed the
fix_node_moduleslogic error by removing the non-standardnode_modules/.package-lock.jsonsentinel check. It now installs dependencies only whennode_modulesis missing, usingnpm ci --omit=devwhen a lockfile exists andnpm install --omit=devotherwise. This avoids unnecessary reinstall loops and offline failures. prod-run.shL79-L89 - Updated logrotate config generation to use the detected runtime log directory (
$LOG_DIR) rather than hard-coded/var/www/html/Runewager/...paths. prod-run.shL253-L267 - Added self-healing for stale logrotate configs: if
/etc/logrotate.d/runewagerexists but doesn’t reference$LOG_DIR, it is replaced with the corrected template. prod-run.shL279-L282 - Updated systemd unit template generation to use
$PROJECT_DIR/$LOG_DIRforWorkingDirectory,ExecStart,EnvironmentFile, andStandardOutput, eliminating path-coupled service failures on non-/var/wwwinstalls. prod-run.shL307-L333 - Expanded systemd required-directive validation to include the dynamic path directives, so existing stale units are automatically rewritten when mismatched. prod-run.shL346-L370
- Committed changes on the current branch and created a follow-up PR message via
make_prsummarizing these fixes.
Testing
- ✅
bash -n prod-run.sh - ✅
git diff -- prod-run.sh
|
CodeAnt AI finished reviewing your PR. |
User description
Motivation
Description
prod-run.shwith a production-focused runner that performs working-directory fixes, dependency/install checks, and background-safe launches usingnohup(keeps foreground under systemd); it printsBot running/Bot NOT runningwith a 15s re-check.logs/runewager.logand maps technical log lines to likely root causes (missing modules, syntax errors, permission issues, missing files/paths, network errors, or missing env values).logs,data/backups,runewager.log), installingnode_modulesvianpm ci --omit=dev, adding missing.envkeys as placeholders (no real tokens inserted), fixing mixed lockfiles, correcting git origin and forcingmainbranch, removing broken symlinks, addingpackage.jsonstart script when absent, detecting invalid JSON, and warning on merge conflict markers./etc/logrotate.d/runewagerexists (creates a safe config usingcopytruncate), validates logrotate via dry-run, ensures a cron fallback line (0 3 * * * /usr/sbin/logrotate -f /etc/logrotate.d/runewager) is present incrontab, and ensures or creates/etc/systemd/system/runewager.servicewith required directives (EnvironmentFile=...,Environment=NODE_ENV=production,Restart=always,RestartSec=5,KillSignal=SIGTERM,TimeoutStopSec=20)..gitignoreto include generated backups and log artifacts and added a README note to keep deploy directory casing asRunewagerto match systemd paths.Testing
bash -n prod-run.shto validate script syntax and it passed successfully.npm run check(Node syntax check) and it completed without errors.npm testand all automated tests passed (4 tests passed, 0 failed).Codex Task
CodeAnt-AI Description
Upgrade startup script to validate environment, auto-repair common VPS issues, and run the bot reliably
What Changed
Impact
✅ Fewer VPS outages due to missing deps or files✅ Clearer startup and failure diagnostics for operators✅ Automatic log rotation and cron fallback to prevent disk exhaustion💡 Usage Guide
Checking Your Pull Request
Every time you make a pull request, our system automatically looks through it. We check for security issues, mistakes in how you're setting up your infrastructure, and common code problems. We do this to make sure your changes are solid and won't cause any trouble later.
Talking to CodeAnt AI
Got a question or need a hand with something in your pull request? You can easily get in touch with CodeAnt AI right here. Just type the following in a comment on your pull request, and replace "Your question here" with whatever you want to ask:
This lets you have a chat with CodeAnt AI about your pull request, making it easier to understand and improve your code.
Example
Preserve Org Learnings with CodeAnt
You can record team preferences so CodeAnt AI applies them in future reviews. Reply directly to the specific CodeAnt AI suggestion (in the same thread) and replace "Your feedback here" with your input:
This helps CodeAnt AI learn and adapt to your team's coding style and standards.
Example
Retrigger review
Ask CodeAnt AI to review the PR again, by typing:
Check Your Repository Health
To analyze the health of your code repository, visit our dashboard at https://app.codeant.ai. This tool helps you identify potential issues and areas for improvement in your codebase, ensuring your repository maintains high standards of code health.