diff --git a/scripts/diagnose-shop-service.sh b/scripts/diagnose-shop-service.sh index c0ed2ad..4b69c62 100644 --- a/scripts/diagnose-shop-service.sh +++ b/scripts/diagnose-shop-service.sh @@ -28,16 +28,20 @@ else fi echo -echo "4. www-data доступ" +echo "4. Порт 3000" +ss -tlnp | grep ':3000' || echo " порт 3000 свободен" +echo + +echo "5. www-data доступ" sudo -u www-data test -r "$SHOP_ROOT/package.json" && echo " package.json: OK" || echo " package.json: FAIL" sudo -u www-data test -x "$SHOP_ROOT" && echo " каталог: OK" || echo " каталог: FAIL" echo -echo "5. Тест Node (5 сек)" +echo "6. Тест Node (5 сек)" set +e timeout 8 sudo -u www-data bash -c "cd '$SHOP_ROOT' && set -a && source .env 2>/dev/null && set +a && node src/server.js" 2>&1 | head -20 set -e echo -echo "6. journalctl shop" +echo "7. journalctl shop" journalctl -u shop -n 30 --no-pager 2>/dev/null || true diff --git a/scripts/free-port-3000.sh b/scripts/free-port-3000.sh new file mode 100644 index 0000000..719b56f --- /dev/null +++ b/scripts/free-port-3000.sh @@ -0,0 +1,31 @@ +#!/bin/bash +# Освободить порт 3000 (ручной npm start / старый процесс) +set -euo pipefail + +PORT="${1:-3000}" + +if ! command -v ss >/dev/null; then + echo "ss не найден" + exit 0 +fi + +if ! ss -tlnp | grep -q ":${PORT} "; then + echo "Порт ${PORT} свободен" + exit 0 +fi + +echo "Порт ${PORT} занят:" +ss -tlnp | grep ":${PORT} " || true + +if command -v fuser >/dev/null; then + echo "Останавливаем процессы на ${PORT}/tcp..." + fuser -k "${PORT}/tcp" 2>/dev/null || true + sleep 2 +fi + +if ss -tlnp | grep -q ":${PORT} "; then + echo "Порт ${PORT} всё ещё занят — остановите процесс вручную" + exit 1 +fi + +echo "Порт ${PORT} свободен" diff --git a/scripts/install-shop-service.sh b/scripts/install-shop-service.sh index ae4e3d0..0d949f5 100644 --- a/scripts/install-shop-service.sh +++ b/scripts/install-shop-service.sh @@ -78,6 +78,9 @@ fi systemctl daemon-reload systemctl enable shop +systemctl stop shop 2>/dev/null || true +bash "$SCRIPT_DIR/free-port-3000.sh" 3000 + echo "Запуск shop..." if ! systemctl restart shop; then echo "" @@ -89,13 +92,20 @@ if ! systemctl restart shop; then fi sleep 3 -if curl -sf http://127.0.0.1:3000/health; then - echo "" - echo "OK — служба shop запущена" - systemctl status shop --no-pager | head -15 - systemctl reload caddy 2>/dev/null || true -else - echo "shop не отвечает на :3000" + +if ! systemctl is-active --quiet shop; then + echo "shop.service не в состоянии active" + journalctl -u shop -n 40 --no-pager + exit 1 +fi + +if curl -sf http://127.0.0.1:3000/health; then + echo "" + echo "OK — служба shop запущена (systemd active)" + systemctl status shop --no-pager | head -15 + systemctl reload caddy 2>/dev/null || true +else + echo "health не отвечает" journalctl -u shop -n 40 --no-pager exit 1 fi diff --git a/scripts/server-update.sh b/scripts/server-update.sh index 3183515..1853c2d 100644 --- a/scripts/server-update.sh +++ b/scripts/server-update.sh @@ -35,6 +35,7 @@ fi if [ -f /etc/systemd/system/shop.service ]; then systemctl daemon-reload + bash "$SCRIPT_DIR/free-port-3000.sh" 3000 2>/dev/null || true systemctl restart shop sleep 2 if curl -sf http://127.0.0.1:3000/health; then diff --git a/src/server.js b/src/server.js index a27bdeb..35d5ab4 100644 --- a/src/server.js +++ b/src/server.js @@ -96,7 +96,13 @@ async function start() { }); server.on('error', (err) => { - console.error('Не удалось запустить сервер:', err.message); + if (err.code === 'EADDRINUSE') { + console.error( + `Порт ${PORT} уже занят (часто старый «npm start»). Выполните: bash scripts/free-port-3000.sh` + ); + } else { + console.error('Не удалось запустить сервер:', err.message); + } process.exit(1); }); } @@ -107,8 +113,12 @@ start().catch((err) => { console.error(' systemctl start postgresql'); console.error(' bash scripts/setup-postgres-ubuntu.sh'); console.error(' Проверьте DATABASE_URL в .env'); + } else if (err.code === 'MODULE_NOT_FOUND') { + console.error('Не найден модуль:', err.message); + console.error(' cd', path.join(__dirname, '..'), '&& npm install --omit=dev'); } else { console.error('Ошибка запуска:', err.message); + if (err.stack) console.error(err.stack); } process.exit(1); }); diff --git a/wiki/Troubleshooting.md b/wiki/Troubleshooting.md index 55afa8e..62a6633 100644 --- a/wiki/Troubleshooting.md +++ b/wiki/Troubleshooting.md @@ -52,6 +52,26 @@ cp /opt/shop/shop10.bak.*/.env /opt/shop/shop10/.env 2>/dev/null || cp /opt/shop bash /opt/shop/shop10/scripts/server-update.sh ``` +## shop.service: exit-code / activating (auto-restart) + +**Health ответил OK, но systemd падает** — часто порт 3000 занят старым `npm start`: + +```bash +cd /opt/shop/shop10 +git pull +sudo bash scripts/free-port-3000.sh +sudo systemctl restart shop +systemctl status shop +``` + +Лог: + +```bash +journalctl -u shop -n 30 --no-pager +# EADDRINUSE → free-port-3000.sh +# MODULE_NOT_FOUND → npm install --omit=dev +``` + ## Job for shop.service failed (control process exited) Чаще всего не запущен PostgreSQL или не прошёл `ExecStartPre`: