From 736da0984631b8e1b65a668acd44ca920ad48b2f Mon Sep 17 00:00:00 2001 From: Horoli Date: Fri, 9 Oct 2026 17:56:37 +0900 Subject: [PATCH] Start server when loaded by the PM2 fork container --- README-서버실행.md | 6 ++++-- scripts/test-arrival-operations.mjs | 11 +++++++++++ server/index.mjs | 3 ++- 3 files changed, 17 insertions(+), 3 deletions(-) diff --git a/README-서버실행.md b/README-서버실행.md index c52988c..5edca08 100644 --- a/README-서버실행.md +++ b/README-서버실행.md @@ -74,6 +74,8 @@ NODE_ENV=production HOST=127.0.0.1 PORT=3600 npm start `deploy/arrival.env.example`은 예시입니다. 파일을 복사하는 것만으로 자동 로드되지는 않습니다. systemd의 EnvironmentFile 또는 Node의 명시적 `--env-file=/절대경로/arrival.env` 옵션을 사용하세요. 실제 설정 파일은 공개 폴더에 두지 마세요. +PM2에서는 `server/index.mjs`를 직접 실행합니다. PM2가 ESM 파일을 import하는 경우에도 서버가 시작되도록 실행 진입점을 처리했습니다. nginx가 다른 장비에 있으면 `HOST`를 nginx가 접근할 앱 서버의 IP로 지정하세요. 예를 들어 nginx가 `192.168.0.250:3600`으로 전달한다면 `HOST=192.168.0.250 PORT=3600`으로 실행합니다. 기존 PM2 프로세스의 환경변수 변경은 `--update-env`로 적용합니다. PM2의 `online` 표시만으로 HTTP 서버 시작을 판단하지 말고, nginx 장비에서 `/api/arrivals/count`에 연결되는지 확인하세요. + ## 3. nginx / HTTPS 기존 HTTPS 도메인의 요청을 같은 Fastify 프로세스로 전달합니다. 정적 화면과 `/api`가 같은 origin이어야 합니다. 기존 server 블록 안의 location 예시: @@ -120,8 +122,8 @@ DB_PATH="$HOME/behind-glass-data/analytics.sqlite" npm run --silent metrics -- - ### 현재 Windows 로컬 검증 (2026-10-09) - Node 24.19.0 / npm 11.17.0에서 일반 `npm ci`, SQLite 로딩, 정적 빌드 및 서버용 빌드를 확인했습니다. 최종 `dist`는 서버용 빌드입니다. -- `npm run test:arrival`은 서버 33개 + 클라이언트 73개, 총 106개 통과했습니다. -- 기존 전체 테스트는 470개 중 467개 통과했습니다. 다음 3개 테스트는 원래 배포본에 포함되지 않은 QA 자료 때문에 실패하며, 해당 원본 자료 복원이 필요합니다. 통과로 처리하거나 임의 자료로 대체하지 않았습니다. +- `npm run test:arrival`은 서버 34개 + 클라이언트 73개, 총 107개 통과했습니다. PM2 방식의 ESM import 시작 검증을 포함합니다. +- 기존 전체 테스트는 471개 중 468개 통과했습니다. 다음 3개 테스트는 원래 배포본에 포함되지 않은 QA 자료 때문에 실패하며, 해당 원본 자료 복원이 필요합니다. 통과로 처리하거나 임의 자료로 대체하지 않았습니다. - `scripts/test-cutout-worker.mjs`: `docs/qa-countryside-cutout-2026-10-07/runtime/sample-320.rgba` 누락 - `scripts/test-original-photo-only.mjs`: `docs/reference-assets/countryside/open-house.png` 누락 - `scripts/test-surface-reflection.mjs`: `docs/qa-surface-reflection/baseline-mosaic.frag` 누락 diff --git a/scripts/test-arrival-operations.mjs b/scripts/test-arrival-operations.mjs index 5e47ff5..c81b0ba 100644 --- a/scripts/test-arrival-operations.mjs +++ b/scripts/test-arrival-operations.mjs @@ -38,6 +38,17 @@ test('operational CLI entrypoints exist without starting an HTTP listener', () = for (const script of ['metrics', 'backup']) assert.ok(existsSync(resolve(`server/${script}.mjs`)), `missing ${script} CLI`); }); +test('PM2 fork imports execute the server entrypoint instead of silently skipping startup', () => { + const output = spawnSync(process.execPath, ['--input-type=module', '-e', + "import { pathToFileURL } from 'node:url'; process.argv[1] = 'ProcessContainerFork.js'; await import(pathToFileURL(process.env.pm_exec_path).href);", + ], { + env: { ...process.env, DB_PATH: '', NODE_ENV: 'production', pm_exec_path: resolve('server/index.mjs') }, + encoding: 'utf8', + }); + assert.equal(output.status, 1, 'the entrypoint must attempt startup and reject the missing database configuration'); + assert.match(output.stderr, /Server startup failed/); +}); + test('metrics prints aggregate-only JSON from an existing read-only database', async t => { const { store, dbPath } = await setup(t); const output = cli('metrics', ['--month', '2026-10'], dbPath); diff --git a/server/index.mjs b/server/index.mjs index 292bf95..c650f55 100644 --- a/server/index.mjs +++ b/server/index.mjs @@ -28,6 +28,7 @@ export async function startServer(env = process.env) { return app; } -if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) { +const entryPath = process.env.pm_exec_path || process.argv[1]; +if (entryPath && import.meta.url === pathToFileURL(entryPath).href) { startServer().catch(() => { process.stderr.write('Server startup failed; check configuration, private storage and build\n'); process.exitCode = 1; }); }