ES /docs

Process killed by signal SIGABRT (code: null)

RCA: Process killed by signal SIGABRT

Overview#

What Happened#

2026-07-15 06:09:09 KST, production us-west-2 리전의 cupixworks-capture-refinement-arm-instance 서비스에서 scenemapper.process 자식 프로세스가 SIGABRT 시그널로 비정상 종료되었다. 부모 Node.js 프로세스는 ChildProcessManagerclose 이벤트 핸들러에서 이 시그널을 관측하고 Error: Process killed by signal SIGABRT (code: null)error 레벨로 기록했으며, 이후 ScenemapperManager::execute가 실패하며 refinement job 1196597이 실패 처리되었다.

Quick Facts#

Field Value
exception.class Error (Node.js)
exception.message Process killed by signal SIGABRT (code: null)
top_frame /tmp/agent/dist/app.cjs:5248:33 (bundled child-process.manager.ts close handler)
runtime Node.js child_process fork, native addon scenemapper_api.node
deploy bundled at /tmp/agent/dist/app.cjs (offset shifted from :5307:5248 between 2026-07-11 and 2026-07-15, redeploy 존재)
env production, region us-west-2, tenant cupix, arm instance

Affected Teams#

Team / Domain Error Count Impact
lemoine / capture refinement 1 (이번 클러스터) + 최근 14일 20건 이상의 유사 SIGABRT Refinement job 실패로 해당 capture의 refined alignment 산출물 미생성, 후속 3D reconstruction 파이프라인 차단

Timeline#

  1. 2026-07-15 06:08:20 KSTRefinementService::init / authenticate / job 1196597 load
  2. 2026-07-15 06:08:24 KST — 대량의 [123475.07] | video filepath not found - 694025.insv warn 로그 (native scenemapper 라이브러리 출력)
  3. 2026-07-15 06:08:53 KST[122204.00] | Failed unstitch refinement - landmark visible count decreased. Revert to the stitched state. warn 로그
  4. 2026-07-15 06:09:09 KST — 자식 프로세스 SIGABRT 종료; ChildProcessManager::setupEventHandlers | Child process closed, Child process exited, Process killed by signal SIGABRT (code: null) error 로그
  5. 2026-07-15 06:09:09 KSTScenemapperManager::execute | error - ... warn 로그와 함께 RefinerExecute (AGT3012) 에러코드 세팅 및 job 실패 처리
  6. 2026-07-15 06:09:10 KSTRefinementService::terminateService | force shutdown after 10 seconds
  7. 2026-07-15 06:11:34 KST — 새 인스턴스가 다음 job 1196611 처리 개시 (서비스 자체는 회복)

Error Log#

Datadog Logs

text
Process killed by signal SIGABRT (code: null)

Impact#

  • Service: cupixworks-capture-refinement-arm-instance
  • Team: lemoine
  • 발생 횟수: 1 (본 클러스터 fingerprint 기준). 단, 동일 원인(SIGABRT in scenemapper child)의 warn 이벤트는 14일 창에서 20건 이상 관측됨 — 만성적 recurrence 이슈.
  • 최초 발생: 2026-07-15 06:09:09 KST
  • 최근 발생: 2026-07-15 06:09:09 KST

Root Cause Summary#

Refinement agent는 native C++ addon (scenemapper_api.node)을 forked child process(process/scenemapper.process.ts) 안에서 로드해 Refiner.process()를 호출한다. 네이티브 코드 내부에서 abort()가 트리거되어 (전형적으로 std::terminate, C++ assertion, uncaught native exception, 또는 메모리 이상) 자식 프로세스가 SIGABRT로 종료되었다. 부모의 ChildProcessManager.setupEventHandlers는 이를 close 이벤트에서 감지해 pending promise를 Error: Process killed by signal SIGABRT (code: null) 로 reject하고 error 로그를 남긴다. 즉 관측된 에러는 네이티브 라이브러리의 crash가 TypeScript 레이어까지 전파된 표면적 증상이며, 진짜 원인은 native scenemapper 라이브러리의 특정 입력(landmark visible count 감소 → unstitch revert 시나리오)에 대한 미처리 실패 경로에 있다.

Technical Analysis#

Code Path#

Entry point: refinement-service.ts:79 (RefinementService::run) → runRefinement (line 305) → ScenemapperManager::executeChildProcessManager::execute → forked child scenemapper.process.tsRefiner.process() (native).

  1. 부모: refinement 실행 호출Refiner.process()를 IPC로 자식에게 위임한다.
applications/agents/packages/cupix-capture-refinement-agent/src/manager/scenemapper.manager.ts:49-58typescript
execute = async (params: RefinerParams): Promise<void> => {
    await this.ensureInitialized();
    try {
        await this.childProcessManager.execute('execute', params);
    } catch (error) {
        logger.warn('ScenemapperManager::execute | error - %s', error);
        if (this.setJobErrorCode) this.setJobErrorCode(ErrorCode.ScenemapperUtils.RefinerExecute);
        throw error;
    }
};
  1. 자식: 네이티브 라이브러리 실행 지점 — 이 라인 내부(C++)에서 abort()가 발생하여 SIGABRT.
applications/agents/packages/cupix-capture-refinement-agent/src/process/scenemapper.process.ts:36-48typescript
private execute = (params: ExecuteMessage): void => {
    this.log(`ScenemapperProcess::execute | params: ${JSON.stringify(params)}`);
    if (!this.libPath || !params?.refinerParamsFilepath) {
        throw new Error('ScenemapperProcess::execute | Required parameters missing');
    }

    // eslint-disable-next-line @typescript-eslint/no-require-imports
    const ScenemapperApi = require(this.libPath);
    const Refiner = new ScenemapperApi.refiner();

    Refiner.load_params(params.refinerParamsFilepath);
    Refiner.process();  // ← 네이티브 크래시 지점 (SIGABRT)
};
  1. Failure point: 부모의 close 이벤트 핸들러 — 스택 트레이스가 가리키는 app.cjs:5248:33에 해당하는 소스는 아래 handler. signal이 truthy이므로 "Process killed by signal SIGABRT (code: null)" 문자열이 그대로 생성되어 pending promise reject 및 로그 출력.
applications/agents/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);
});
  1. 부모: run 루프의 catch 및 job 실패 처리
applications/agents/packages/cupix-capture-refinement-agent/src/refinement-service.ts:79-111typescript
private run = async (): Promise<void> => {
    logger.info('RefinementService::run | begin');
    try {
        const srvJob = await this.jobManager.loadJob(Environment.CPX_JOB_ID as number);
        // ...
        await this.runRefinement(cpCapture);
        // ...
        await this.jobManager.updateCompleteActionJob('refinement', TESLA.UpdateJobRequest.StateEnum.Stopped);
    } catch (error) {
        logger.error('RefinementService::run | end - %s', JSON.stringify(error));
        await this.jobManager.updateErrorActionJob('refinement');
    }
};

기대 동작: Refiner.process()가 성공/실패를 IPC 응답으로 반환하고, 실패 시에도 자식 프로세스가 정상 종료되어 부모가 도메인 에러로 처리한다. 실제 동작: native C++ 레이어에서 abort()가 발생하여 자식이 SIGABRT로 즉시 종료되고, ScenemapperApi가 로그에 남긴 "landmark visible count decreased" / "video filepath not found" 이후의 특정 분기에서 assertion/undefined behavior가 발생한 것으로 추정. 자식 프로세스에는 uncaughtException 훅이 있어도 native abort는 잡을 수 없다.

Log Evidence#

Datadog query 1 — 본 클러스터의 원본 에러:

text
service:cupixworks-capture-refinement-arm-instance status:error @environment:production "Process killed by signal SIGABRT (code: null)"

주변 로그 (from Datadog service:cupixworks-capture-refinement-arm-instance, 2026-07-14T21:08:30Z–21:15:00Z):

text
2026-07-15 06:08:20 info  RefinementService::init
2026-07-15 06:08:20 info  RefinementService::authenticate | begin
2026-07-15 06:08:20 info  CupixAuth::setSession | session_id: 31e2e0c9afbc49c302b74163c3d7d72791b9262a
2026-07-15 06:08:20 info  RefinementService::run | begin
2026-07-15 06:08:20 info  RefinementService::authenticate | end
2026-07-15 06:08:20 info  JobManager::loadJob | begin - job id: 1196597
2026-07-15 06:08:20 info  JobManager::loadJob | end - job id: 1196597
2026-07-15 06:08:24 warn  [123475.07] | video filepath not found - 694025.insv   (× 수십 회 반복)
2026-07-15 06:08:24 warn  [123474.95] | video filepath not found - 694025.insv   (× 수십 회 반복)
2026-07-15 06:08:53 warn  [122204.00] | Failed unstitch refinement - landmark visible count decreased. Revert to the stitched state.
2026-07-15 06:09:09 error ChildProcessManager::setupEventHandlers | Child process closed
2026-07-15 06:09:09 error ChildProcessManager::setupEventHandlers | Child process exited
2026-07-15 06:09:09 error Process killed by signal SIGABRT (code: null)
2026-07-15 06:09:09 warn  ScenemapperManager::execute | error - {name:'Error', message:'Process killed by signal SIGABRT (code: null)', stack:'... at ChildProcess.<anonymous> (/tmp/agent/dist/app.cjs:5248:33) ...'}
2026-07-15 06:09:10 info  RefinementService::terminateService | force shutdown after 10 seconds
2026-07-15 06:11:34 info  RefinementService::init                                  ← 새 인스턴스의 다음 job

video filepath not found - 694025.insv 로그와 Failed unstitch refinement - landmark visible count decreased 로그는 소스 코드에는 존재하지 않는 문자열로, native scenemapper_api.node 내부에서 출력하는 것으로 확인 (repo 전체 grep 결과 없음). 이는 abort 직전의 native 실행 상태를 나타낸다.

Datadog query 2 — 14일간 SIGABRT recurrence:

text
service:cupixworks-capture-refinement-arm-instance "SIGABRT"

결과: 2026-07-02 ~ 2026-07-15 사이 20건 이상. 스택 트레이스가 app.cjs:5307:33에서 app.cjs:5248:33으로 이동한 것으로 보아 그 사이 재배포가 있었으나 문제는 지속.

Hypotheses Considered#

# Hypothesis Evidence for Evidence against Verdict
H1 Native scenemapper_api.node 내부에서 abort() 발생 (C++ assertion / uncaught exception / OOM), 특정 입력(landmark 감소 unstitch revert 경로 + missing .insv 파일)에서 재현 scenemapper.process.ts:47 에서 Refiner.process() 호출; abort 직전 native 로그 "Failed unstitch refinement - landmark visible count decreased" 와 대량의 "video filepath not found - 694025.insv" warn; 스택이 항상 ChildProcess.<anonymous> (부모 close handler)로 끝남 → JS 예외가 아님; SIGABRT signal name (JS에서 자발적으로 보내지 않음) Confirmed
H2 부모 프로세스가 timeout으로 자식을 SIGKILL/SIGTERM 한 것 child-process.manager.ts:219-221 에 timeout 시 SIGKILL 로직 존재 관측된 signal은 SIGABRT 이지 SIGKILL/SIGTERM 아님; ScenemapperManagerexecute 에 timeout 옵션을 전달하지 않음 (ChildProcessOptions.executeTimeoutMs 미설정) Rejected
H3 Node.js uncaughtException/unhandledRejection 핸들러가 process.exit(1) 을 호출한 것 app.ts:42-52 에 두 핸들러 존재 이 경로는 exit code 1, signal null 로 관측되어야 함. 실제 로그는 signal=SIGABRT, code=null → 자식이 시그널로 죽음 Rejected
H4 컨테이너 OOM Killer (cgroup)에 의한 종료 ARM instance 환경, 대용량 입력 처리 OOM은 통상 SIGKILL. SIGABRT는 프로세스 자신이 raise(SIGABRT) (즉 abort())로 보내는 시그널 → 커널이 아닌 프로세스 내부 발신 Rejected
H5 입력 데이터 손상(video filepath not found)이 실패의 유일한 원인 크래시 직전 대량 warn video filepath not found - 694025.insv 동일 warn 이후에도 native 코드가 "Revert to the stitched state" 로 회복을 시도(=warn 레벨). 크래시는 그 다음 단계에서 별개로 발생 → 입력 손상은 트리거 조건일 수는 있으나 abort 자체의 원인은 native 코드의 미처리 실패 경로 Contributory (not sole cause)

Fix Recommendation#

즉시 조치 (Critical)#

  • 네이티브 팀에 native crash 조사 이관. 표면적으로 TypeScript agent 레이어에 fix 여지가 거의 없음 — 부모 프로세스는 이미 close/exit/error 이벤트를 모두 로깅하고 pending promise를 reject하며 job 실패 처리를 하고 있음. 진짜 fix는 scenemapper_api.node (native C++ scenemapper 라이브러리)에서 이루어져야 함. 관측된 native 로그 패턴 (landmark visible count decreased + video filepath not found - 694025.insv)을 티켓에 첨부하여 재현 케이스로 전달할 것.
  • 자식 프로세스에서 core dump 또는 native stack 수집 활성화 고려. 현재 자식 프로세스 stdio 는 inherit 기본값이고 (child-process.manager.ts:44-47), pipe 모드가 아니면 native 라이브러리의 stderr 출력을 별도로 캡처하지 못함. ChildProcessOptions.stdioMode: 'pipe' 로 refinement agent 도 전환하면 native abort message (예: terminate called after throwing an instance of ...)를 로거로 흘려보낼 수 있어 root cause 파악에 유리.
    • 관련: child-process.manager.ts:138-141 에 이미 stderr handler 존재하나 pipe 모드일 때만 동작.
    • 자동화된 code-fix 대상에서는 제외 권장 — 다른 agent (skat, thumbnail, mesh 등)와 동작이 달라지므로 lemoine 팀 리뷰 필요.

단기 개선 (1주 이내)#

  • 재시도 정책 도입 검토. 현재 RefinementService::run catch 블록(refinement-service.ts:107-110)은 즉시 job을 error로 마킹함. 동일 job을 새 인스턴스에서 1회 재시도하는 정책이 있는지 lemoine 팀과 확인. 없다면 native abort의 transient 케이스 (예: 특정 image frame corruption)에 대해 상위 job 재큐 로직 검토.
  • 입력 검증 강화. RefinementService::checkInputFiles (refinement-service.ts:144-154) 는 alignment_archive.bin 만 검증. 크래시 트리거로 지목된 .insv video files 존재 여부를 native 호출 전에 검증해 실패 경로를 결정적으로 만들 것.
  • 동일 fingerprint 재발 알림. SIGABRT recurrence 를 지표화하여 (하단 Monitoring 섹션 참조) 특정 threshold 초과 시 team notify.

장기 개선 (재발 방지)#

  • Native 라이브러리 crash 관찰가능성 향상: refinement agent 컨테이너에 core dump 저장 볼륨과 gdb/addr2line 을 갖춘 debug image 배포 옵션. Kubernetes/ECS taskdefinition 에서 ulimit -c unlimited 활성화.
  • Native ↔ Node 경계 계약 표준화: Refiner.process() 실패 시 native 측이 예외 대신 result code 를 반환하도록 인터페이스 재설계 → JS 레벨에서 결정적 실패 경로 확보.
  • Refinement 입력 pre-validation 파이프라인: 상류 (skat master / postprocessor) 산출물에 대해 .insv presence + landmark count 정합성을 사전 검사하는 gate 를 도입해 이상 데이터가 refinement 로 넘어오지 않게 함.

Monitoring#

  • SIGABRT 발생 카운트 timeseries — refinement agent 전반의 SIGABRT recurrence 추적:
text
service:cupixworks-capture-refinement-arm-instance status:error "SIGABRT"
  • Child process close (비정상 종료) 카운트 — SIGABRT 외 다른 시그널까지 포괄:
text
service:cupixworks-capture-refinement-arm-instance "Child process closed"
  • native precursor warn 로그 카운트 — abort 직전 native 상태 신호:
text
service:cupixworks-capture-refinement-arm-instance status:warn "Failed unstitch refinement"
  • RefinerExecute 에러 코드 발생 카운트 — job-level 실패 추적 (tesla 측 job 테이블 error_code = 'AGT3012' 대비):
text
service:cupixworks-capture-refinement-arm-instance "ScenemapperManager::execute | error"

임계치 제안: SIGABRT 카운트가 24h 롤링 윈도우에서 5건을 초과하면 lemoine 팀 채널로 알림.

Risk Assessment#

  • Risk level: medium — 서비스 자체는 job 단위 리사이클로 회복하며, 부모 프로세스의 예외 처리 경로는 이미 정상 동작. 다만 native crash 는 개별 refinement job 실패로 이어져 사용자 capture 산출물이 미생성되며 14일에 20+회 재발하는 만성 이슈.
  • 예상 복잡도: critical (native scenemapper C++ 라이브러리 수정 필요). TypeScript agent 레이어에서 완결 가능한 fix는 관찰가능성/입력 검증 개선 정도로 제한적.