ES /docs

Process exited with code 6

RCA: Process exited with code 6

Overview#

What Happened#

2026-06-24 KST 오후, cupixworks-sitetrack-instance (sitetrack master agent) 가 fork 한 child process 가 종료 시점에 exit code 6 으로 죽었다. 16분간 4회 발생했으며, 부모 프로세스의 Sitetrack::terminateService 가 grace timer 를 시작한 직후 child 의 비정상 종료를 감지해 error 로그를 남겼다. BIM mesh validation 작업의 메인 처리는 완료된 뒤 cleanup/shutdown 단계에서 발생한 것으로 보인다.

Quick Facts#

Field Value
exception.class Error (synthesized by ChildProcessManager)
exception.message Process exited with code 6
top_frame packages/base/src/manager/child-process.manager.ts:115
runtime Node.js child process running native C++ binding @cupix-compute/site-track
env production, us-west-2

Affected Teams#

Team / Domain Error Count Impact
dprconstruction (sitetrack-master-agent) 4 sitetrack job 들이 종료 시점에 비정상 exit — 사용자 가시적 실패 여부는 job state 확인 필요

job 별 영향(retry/실패 처리)은 JobManager.updateCompleteActionJob 호출 여부에 따라 달라지며, 본 RCA 시점에서는 확정할 수 없다 (uncertain — needs verification).

Timeline#

  1. 2026-06-24 16:06 KST — 첫 발생 (first_seen)
  2. 2026-06-24 16:18 KST — native BIM 처리 단계에서 다수 warn (Unsupported firmware version detected! - Camera: Insta360 X5, version: v1.6.18_build1, Invalid Geometry / Failed to decode geometry buffer)
  3. 2026-06-24 16:21–16:22 KSTcupix::bim_algorithm::SiteInsights::* 단계의 info 로그가 정상적으로 종료 (elapsed: ...)
  4. 2026-06-24 16:22:27 KSTSitetrack::terminateService | force shutdown after 10 seconds (info) 직후 동일 초에 child process 가 code: 6 으로 종료, ChildProcessManager::setupEventHandlers | Child process closedChild process exited 가 error 로그로 기록됨 (last_seen)
  5. 2026-06-24 (RCA 시점) — RCA 작성

Error Log#

Datadog Logs

text
Process exited with code 6

대표 발생 시점 (2026-06-24 16:22:27 KST) 의 인접 로그:

text
2026-06-24 16:22:27  info   Sitetrack::terminateService | force shutdown after 10 seconds
2026-06-24 16:22:27  error  Process exited with code 6
2026-06-24 16:22:27  error  Process exited with code 6
2026-06-24 16:22:27  error  ChildProcessManager::setupEventHandlers | Child process exited
2026-06-24 16:22:27  error  ChildProcessManager::setupEventHandlers | Child process closed
2026-06-24 16:22:26  info   [104365.31] | cupix::filterInterestedBimMeshes_() end. elapsed: 0

Impact#

  • Service: cupixworks-sitetrack-instance
  • Team: dprconstruction
  • 발생 횟수: 4
  • 최초 발생: 2026-06-24 16:06 KST
  • 최근 발생: 2026-06-24 16:22 KST

Root Cause Summary#

Child process 가 IPC shutdown 메시지로 graceful cleanup 을 마치고 종료하는 정상 경로에서는 process.exit(0) 또는 process.exit(1) 만 호출된다 (packages/base/src/process/base.process.ts:94,97). 그러나 실제 child 의 exit code 는 6 으로, 이는 TS 레이어 어디에서도 만들어지지 않는 값이다. 따라서 종료 원인은 child 가 임베드한 native C++ 바인딩 @cupix-compute/site-track (SiteTrack.process()packages/cupix-sitetrack-master-agent/src/process/sitetrack.process.ts:42) 내부에서 process-level abort 또는 명시적 exit(6) 호출이 발생한 것이다. 작업 본체 (BIM mesh filtering, SiteInsights) 가 완료된 뒤 bimProcessManager.stop() 시점에 발생한 점, 그리고 부모가 같은 초에 terminateService grace timer 를 시작한 점으로 미루어 종료/cleanup 경로에서 native 라이브러리의 정리 (소멸자, 리소스 해제) 가 비정상 종료한 것으로 보인다. Node.js 내장 exit code 6 ("Non-function Internal Exception Handler") 가능성도 있으나 BaseProcessuncaughtException 핸들러를 비함수로 설정하지 않으므로 그 경로일 가능성은 낮다 (uncertain — needs verification).

Technical Analysis#

Code Path#

  • Entry point: packages/cupixworks-sitetrack-master-agent/src/sitetrack-service.ts:201 (executeBimValidator)
  • IPC fork: packages/base/src/manager/child-process.manager.ts:74 (fork(actualScriptPath, ...))
  • Child main: packages/cupix-sitetrack-master-agent/src/process/sitetrack.process.ts:42validator.process() (native call)
  • Parent shutdown trigger: packages/cupix-sitetrack-master-agent/src/sitetrack-service.ts:224await this.bimProcessManager.stop()
  • Failure point: child process 종료 시점 — ChildProcessManager::setupEventHandlers | Child process closed 에서 code=6, signal=null 을 받아 부모 측에서 Error('Process exited with code 6') 을 합성 (packages/base/src/manager/child-process.manager.ts:107-117)

부모 측 child close 처리:

packages/base/src/manager/child-process.manager.ts:107-120typescript
this.process.on('close', (code: number | null, signal: string | null) => {
    logger.error('ChildProcessManager::setupEventHandlers | Child process closed', {
        code,
        signal
    });

    const errorMsg = signal
        ? `Process killed by signal ${signal} (code: ${code})`
        : `Process exited with code ${code}`;

    this.rejectAllPending(new Error(errorMsg));
    this.process = undefined;
    this.emit('close', code, signal);
});

Child 측 graceful shutdown 경로 (여기서는 6 을 만들지 않는다):

packages/base/src/process/base.process.ts:88-99typescript
if (message.type === 'shutdown') {
    console.log('BaseProcess::handleMessage | Received shutdown message, cleaning up...');
    this.sendSuccess(message.id, { shutting_down: true });

    try {
        await this.cleanup();
        process.exit(0);
    } catch (error) {
        console.error('BaseProcess::handleMessage | Error during shutdown cleanup:', error);
        process.exit(1);
    }
    return;
}

Child 의 작업 본체 — native SiteTrack 호출:

packages/cupix-sitetrack-master-agent/src/process/sitetrack.process.ts:35-57typescript
return new Promise((resolve, reject) => {
    try {
        const validator = new SiteTrack();
        validator.set_options_filepath(params.options_filepath!);
        validator.set_request_filepath(params.request_file_path!);
        validator.set_output_dirpath(params.result_dir_path!);

        validator.process();

        this.log('SitetrackProcess::execute | Sitetrack processing completed successfully');
        resolve({ success: true });
    } catch (error) {
        const errorMessage = error instanceof Error ? error.message : String(error);
        const errorStack = error instanceof Error ? error.stack : undefined;
        // ...
        reject(error);
    }
});

부모 측 정상 흐름:

packages/cupix-sitetrack-master-agent/src/sitetrack-service.ts:222-227typescript
cpSitetrack.setStat({ sitetrack_started_at: new Date(), sitetrack_version: this.bimProcessManager.getVersion() });
await this.bimProcessManager.execute(params);
await this.bimProcessManager.stop();        // 여기서 IPC shutdown 메시지 전송, child 가 cleanup 후 exit(0)/exit(1) 해야 함
cpSitetrack.setStat({ sitetrack_finished_at: new Date() });

기대 동작: bimProcessManager.stop() 이후 child 는 process.exit(0) 으로 종료되어야 하며, ChildProcessManagerclose 핸들러는 정상 종료 (code=0) 로 받아야 한다.

실제 동작: child 가 code 6 으로 종료하여 부모는 이를 error 로 간주하고 rejectAllPending(new Error('Process exited with code 6')) 호출.

Log Evidence#

사용된 Datadog 쿼리 (클러스터 파일의 URL 그대로):

text
service:cupixworks-sitetrack-instance status:error @environment:production "Process exited with code 6"

부가 컨텍스트 수집을 위한 쿼리:

text
service:cupixworks-sitetrack-instance status:(warn OR error)

핵심 로그 시퀀스 (원문):

text
2026-06-24 16:22:27  info   Sitetrack::terminateService | force shutdown after 10 seconds
2026-06-24 16:22:27  error  Process exited with code 6
2026-06-24 16:22:27  error  ChildProcessManager::setupEventHandlers | Child process exited
2026-06-24 16:22:27  error  ChildProcessManager::setupEventHandlers | Child process closed
2026-06-24 16:22:26  info   [104365.31] | cupix::filterInterestedBimMeshes_() end. elapsed: 0
2026-06-24 16:22:26  info   [104365.31] | cupix::filterInterestedBimMeshes_() start.
2026-06-24 16:22:25  info   [104362.49] | cupix::bim_algorithm::SiteInsights::recoverFarMeshes() start.
2026-06-24 16:22:23  info   [104417.68] | cupix::bim_algorithm::filteringBimMeshesByDistance() start.

종료 직전 native 측에 명시적 fatal/abort 로그는 잡히지 않았다. 부수적으로 Invalid Geometry(0): Failed to decode geometry buffer, Invalid OTG header - Unexpected zero length CDN resource received warn 다수가 16:21:48-49 KST 에 관찰되었으나, 이는 Forge/Autodesk CDN 에서 일부 mesh 데이터를 정상 로드하지 못한 것으로 child 종료 시점과는 약 38-39 초 차이가 있다.

부모 측 close 시 signalnull (즉 SIGKILL/SIGTERM 등 외부 신호가 아닌 process 가 자체 exit(6) 호출). 이는 위 가설 — native lib 가 process-level exit 을 자체적으로 호출 — 과 일치한다.

Hypotheses Considered#

# Hypothesis Evidence for Evidence against Verdict
H1 Native @cupix-compute/site-track 라이브러리가 cleanup/소멸자 경로에서 exit(6) 또는 abort 호출 TS 레이어 어디서도 process.exit(6) 호출 없음 (Grep 결과 0건); BaseProcess shutdown 경로는 exit(0)/exit(1) 만 사용; child close signal=null 로 외부 시그널 아님; 발생 시점이 main 작업 종료 직후 (bimProcessManager.stop() 라인) native 로그에서 명시적 abort 메시지 부재 (debug/silly 레벨 확인 필요) Confirmed (most likely)
H2 Parent 가 timeout 으로 child 를 SIGKILL — ChildProcessManager::sendMessageexecuteTimeoutMs 초과 manager/child-process.manager.ts:213-225 에 timeout 시 SIGKILL 분기 존재 SitetrackProcessManager 생성 시 executeTimeoutMs 옵션을 넘기지 않음 (manager/sitetrack-process.manager.ts:11) — 타임아웃 미설정; child close signalnull 이라 SIGKILL 흔적 없음 Rejected
H3 Sitetrack::terminateService 의 grace timer (ForcedShutdownTimeout) 가 child 를 종료시킴 terminateService 가 같은 초에 로그됨 해당 timer 는 부모 자체에 대해 process.exit(1) 호출 (sitetrack-service.ts:54) 이며 child 에 SIGKILL 을 보내지 않음; child exit code 가 6 이지 1 이 아님; timer 는 10 초 후 발화이므로 같은 초에 발화 불가 Rejected
H4 Node.js 내장 exit code 6 ("Non-function Internal Exception Handler") TS 코드 어디에도 6 이 생성되지 않으므로 후보 BaseProcess.setupMessageHandlers 에서 process.on('uncaughtException', non-function) 같은 패턴 없음; uncaughtException 핸들러 자체를 등록하지 않음 Rejected (uncertain — needs verification)
H5 Forge OTG / mesh decode 실패로 인한 처리 중단 16:21:48-49 KST 의 Failed to decode geometry buffer, Invalid OTG header warn 다수 child 가 38-39 초간 정상적으로 추가 작업 (filterInterestedBimMeshes_, SpatialOccupancyGrid::construct) 을 진행했고 모두 정상 종료 (elapsed: 0); 종료 사유로 직접 연결되지 않음 Rejected (관련 noise, root cause 아님)

Fix Recommendation#

즉시 조치 (Critical)#

  • Native @cupix-compute/site-track 라이브러리의 종료/소멸자 경로 점검packages/cupix-sitetrack-master-agent/src/process/sitetrack.process.ts:37-45validator 객체가 promise resolve 후에도 child process 가 살아남는 동안 native 리소스를 들고 있으며, IPC shutdown 시점에 소멸자에서 abort 가 나는 것으로 추정. site-track 라이브러리 소유 팀이 native 측 cleanup 코드 (특히 GPU/메모리/파일 핸들 해제) 에서 assert/abort 발생 여부를 확인해야 한다.
  • 부모 측 close 분류 보정packages/base/src/manager/child-process.manager.ts:107-117. 현재는 child 가 main 작업 성공 후 종료 단계에서 code 6 으로 죽어도 동일하게 error 로그를 남긴다. promise 가 이미 resolve 된 뒤 발생한 close 는 pending 이 없어 rejectAllPending 이 무의미하지만, error 로그는 그대로 남아 false-positive 알람을 만든다. 이미 resolve 된 작업 후 종료 단계의 비정상 exit 은 warn 으로 분류하는 방향 검토.

단기 개선 (1주 이내)#

  • 종료 단계 진단 로그 강화 — child 측 BaseProcess.handleMessage('shutdown') (packages/base/src/process/base.process.ts:88-99) 가 cleanup() 호출 직전/직후에 console.log 만 사용 중. structured logger 로 변경하고 native 정리 호출 전후의 timestamp 와 메모리/RSS 를 함께 남기면, native abort 직전의 상태를 추적 가능.
  • Exit code 매핑ChildProcessManager 가 known native exit codes (6, 134(SIGABRT), 139(SIGSEGV)) 를 분류해서 별도 error code 로 jobManager 에 전달하면, retry/alert 정책을 분리할 수 있다 (SitetrackProcessManager::executeErrorCode.Agent.Default 가 현재 일괄 적용 — manager/sitetrack-process.manager.ts:33).

장기 개선 (재발 방지)#

  • Native lib 의 abort 안정성 회귀 테스트 — Forge 응답이 정상이고 작업이 완료되는 케이스에서도 종료 단계에 abort 가 나는 시나리오에 대한 통합 테스트 추가.
  • IPC 종료 프로토콜 단순화 — 작업 성공 후에는 부모가 SIGTERM 으로 빠르게 종료하고 child 의 abort 가 자식 종료 처리에 영향주지 않게 격리 (성공 분기에서는 close error 무시).

Monitoring#

추가 메트릭/알림:

종료 코드 6 발생 빈도:

text
sum:logs.hits{service:cupixworks-sitetrack-instance,@message:"Process exited with code 6"}.as_count()

전체 child 비정상 종료 (코드 0 외 모두):

text
sum:logs.hits{service:cupixworks-sitetrack-instance,@message:"Child process closed"}.as_count()

Forge mesh decode 실패와의 상관관계:

text
sum:logs.hits{service:cupixworks-sitetrack-instance,@message:"Failed to decode geometry buffer"}.as_count()

알람 임계값: 5분 윈도 내 동일 클러스터 fingerprint 3회 이상 발생 시 alert.

Risk Assessment#

  • Risk level: medium
  • 예상 복잡도: standard (native lib 점검이 필요한 경우 critical)

이유: 작업 본체 (BIM validation) 는 종료 전에 성공적으로 진행된 정황이 있어 사용자 데이터 손상 위험은 낮지만, child 비정상 종료가 jobManager.updateCompleteActionJob 호출 전 promise 체인을 깨는 경우 job 상태가 incomplete 으로 남을 수 있다. native 라이브러리 수정이 필요하면 site-track 팀과의 협업이 필요해 복잡도가 올라간다.