ES /docs

PixGenie process failed with exit code 11. STDERR: clusters: 100%|██████████| 1/1 [00:00<?, ?it/s]

RCA: PixGenie process failed with exit code 11 (SIGSEGV during native library teardown)

Overview#

What Happened#

cupix-pix-genie-preprocessor-agentcapture_47326 (tenant nswgov, region ap-southeast-2)의 PixGenie 전처리를 실행하던 중, Python 프로세스가 모든 처리를 끝낸 직후 native library teardown 단계에서 SIGSEGV(11)로 크래시했다. 프로세스가 non-zero로 종료되자 agent가 이를 PixGenie process failed with exit code 11 에러로 보고하고 capture 상태를 Error로 마킹했다. 처리 결과물은 이미 생성되었으나 업로드 단계에 도달하지 못했다.

Quick Facts#

Field Value
exception.class Error (Node.js generic Error)
exception.message PixGenie process failed with exit code 11. STDERR: ... Received fatal signal: SIGSEGV(11)
top_frame src/process/pixgenie.process.ts:111
crash frame (native) cupix::foundation::factory::detail::unregisterObjectCreator(std::type_info const&) in libfoundation.so
runtime Node.js agent + Python 3.12 child process (PixGenie native libs, g3log)
env production, ap-southeast-2, tenant nswgov

Affected Teams#

Team / Domain Error Count Impact
sinsw / nswgov 1 (capture 47326) PixGenie 전처리 결과 업로드 실패, capture pix_genie_state = Error

Timeline#

  1. 2026-08-07 11:35 KST — PixGenie Python 프로세스 시작, video decoding 및 feature 추출 진행.
  2. 2026-08-07 11:47 KSTExtracting Features: 100%|██████████| 226/226 완료 (모든 처리 종료).
  3. 2026-08-07 11:49:23 KSTPipeline result saved to: /tmp/workspace/capture_47326/output/pixgenie_result.json (파이프라인 결과 저장 성공).
  4. 2026-08-07 11:49:24 KST — native library teardown 중 SIGSEGV(11) 발생, 프로세스 non-zero 종료.
  5. 2026-08-07 11:49:24 KST — agent가 PixGenie process failed with exit code 11 에러 로깅, capture pix_genie_state = Error, workspace cleanup.

Error Log#

Datadog Logs

text
PixGenie process failed with exit code 11. STDERR: ... Extracting Features: 100%|██████████| 226/226 [08:31<00:00,  2.26s/it]*******	FATAL SIGNAL *******
file: , function: , Received fatal signal: SIGSEGV(11)	PID: 33

***** SIGNAL SIGSEGV(11)

*******	STACKDUMP *******
	stack dump [1]  /tmp/lib/pixgenie/pixgenie/lib/pixgenieutil-x64-ubuntu22.04-gcc-release/libg3log.so+0x15d5b [0x7fa4912dcd5b]
	stack dump [2]  /usr/lib/x86_64-linux-gnu/libc.so.6+0x45330 [0x7fa57b4fb330]

	stack dump [3]  /tmp/lib/pixgenie/pixgenie/lib/pixgenieutil-x64-ubuntu22.04-gcc-release/libfoundation.so : cupix::foundation::factory::detail::unregisterObjectCreator(std::type_info const&)+0xa1 [0x7fa45a6a5b51]

	stack dump [4]  /tmp/lib/pixgenie/pixgenie/lib/pixgenieutil-x64-ubuntu22.04-gcc-release/libscenemodel.so : cupix::scene_model::unload()+0x14 [0x7fa45aff8254]

	stack dump [5]  /tmp/lib/pixgenie/pixgenie/lib/pixgenieutil-x64-ubuntu22.04-gcc-release/libfoundation.so : cupix::foundation::bootstrap::unload()+0x4d [0x7fa45a6d107d]
	stack dump [6]  /lib64/ld-linux-x86-64.so.2+0x10f2 [0x7fa57b8030f2]
	stack dump [7]  /lib64/ld-linux-x86-64.so.2+0x5578 [0x7fa57b807578]
	stack dump [8]  /usr/lib/x86_64-linux-gnu/libc.so.6+0x47a76 [0x7fa57b4fda76]
	stack dump [9]  /usr/lib/x86_64-linux-gnu/libc.so.6+0x47bbe [0x7fa57b4fdbbe]
	stack dump [10]  /usr/lib/x86_64-linux-gnu/libc.so.6+0x2a1d1 [0x7fa57b4e01d1]
	stack dump [11]  /usr/lib/x86_64-linux-gnu/libc.so.6__libc_start_main+0x8b [0x7fa57b4e028b]
	stack dump [12]  /usr/bin/python3_start+0x25 [0x657bc5]

Impact#

  • Service: cupixworks-pix-genie-preprocessor-instance
  • Team: sinsw (tenant nswgov)
  • 발생 횟수: 1 (cluster 기준). 14일 창 내 SIGSEGV-during-unload 시그니처 동일 발생 2건, 유사 SIGSEGV 1건 추가.
  • 최초 발생: 2026-08-07 11:49 KST
  • 최근 발생: 2026-08-07 11:49 KST

동일 서비스에서 14일 창 upload completed 성공 로그가 50건 이상 (조회 limit 도달)이고 error-level PreprocessorService::run | end 실패가 9건이므로, 성공이 지배적인 가운데 발생하는 저빈도 간헐 실패다. capture 처리 자체는 완료되었으나 결과 업로드가 누락되어 재실행이 필요하다.

Root Cause Summary#

PixGenie Python 프로세스가 모든 처리 (feature 추출 226/226, pixgenie_result.json 저장)를 정상 완료한 뒤, native C++ 라이브러리 teardown (cupix::foundation::bootstrap::unloadcupix::scene_model::unloadcupix::foundation::factory::detail::unregisterObjectCreator) 중 SIGSEGV(11)로 크래시했다. 이 크래시는 g3log signal handler가 stack dump를 남기고 프로세스를 non-zero exit code로 종료시킨다. pixgenie.process.tssetupProcessHandlerscode !== 0이면 무조건 PixGenie process failed with exit code ${code} 에러로 reject하므로, 처리 산출물이 이미 존재하더라도 프로세스가 처리 완료 후 teardown 단계에서만 죽었는지 구분하지 못하고 전체 job을 실패로 처리한다. 근본 원인은 PixGenie native library의 shutdown-time segfault (C++ static/전역 객체 소멸 순서 문제로 추정)이며, agent 측 결함은 teardown 크래시와 진짜 처리 실패를 구분하지 못하는 exit-code 처리 방식이다.

Technical Analysis#

Code Path#

  • Entry point: src/preprocessor-service.ts:66 (PreprocessorService.run)
  • 처리 실행: src/manager/pix-genie-manager.ts:56 (executePixGenieProcessing)
  • Python 프로세스 실행: src/process/pixgenie.process.ts:52 (runPythonProcess)
  • Failure point: src/process/pixgenie.process.ts:105-113 (close 핸들러의 non-zero exit 처리)

run은 처리 성공 시에만 pix_genie_state = Done으로, catch 블록에서 Error로 마킹한다.

src/preprocessor-service.ts:91-102typescript
				logger.info('PreprocessorService::run | Starting Pix Genie preprocessing');
				const start = Date.now();
				await this.pixGenieManager.executePixGenieProcessing(cpCapture);
				logDuration(start, Date.now(), `executePixGenieProcessing - capture_id: ${cpCapture.id}`, 'PreprocessorService');
				logger.info('PreprocessorService::run | Pix Genie preprocessing completed');

				await this.pixGenieManager.updatePixGenieState(captureId, TESLA.PixGenieState.Done);
				logger.info('PreprocessorService::run | successfully completed');
			}
		} catch (error) {
			await this.pixGenieManager.updatePixGenieState(captureId!, TESLA.PixGenieState.Error);
			logger.error('PreprocessorService::run | end - %s', stringifyError(error));

executePixGenieProcessingexecute (내부에서 verifyOutput) 성공 뒤에 uploadPixGenieResult를 호출한다. 즉 execute가 reject하면 업로드는 실행되지 않는다.

src/manager/pix-genie-manager.ts:74-78typescript
			const processStart = Date.now();
			await this._pixGenieProcess.execute(processParams);
			logDuration(processStart, Date.now(), `pixgenie_python_process - capture_id: ${cpCapture.id}`, 'PixGenieManager');

			await this.uploadPixGenieResult(cpCapture.id, outputDir);

실제 실패는 runPythonProcessclose 핸들러에서 발생한다. exit code가 0이 아니면 STDERR 전체를 붙여 Error로 reject한다. teardown SIGSEGV로 인한 종료도 이 경로로 들어온다.

src/process/pixgenie.process.ts:105-113typescript
		this._process.on('close', (code) => {
			logger.debug('PixGenieProcess | process exited with code: %d', code);

			if (code === 0) {
				resolve();
			} else {
				reject(new Error(`PixGenie process failed with exit code ${code}${stderr ? `. STDERR: ${stderr}` : ''}`));
			}
		});

기대 동작: Python 프로세스가 처리를 완료하고 산출물 (pixgenie.sqlite)을 남기면 agent가 이를 업로드하고 capture를 Done으로 마킹. 실제 동작: 처리는 완료되었으나 native teardown 중 SIGSEGV로 프로세스가 non-zero 종료 → close 핸들러가 무조건 실패 reject → verifyOutput/uploadPixGenieResult 미실행 → capture Error 마킹.

native stack은 shutdown 전용 경로임을 보여준다. bootstrap::unload (frame 5) → scene_model::unload (frame 4) → unregisterObjectCreator (frame 3), 그리고 frame 6-7의 ld-linux 및 frame 8-9의 libc __run_exit_handlers 계열은 프로세스 종료 시 static destructor/atexit 실행 중임을 나타낸다. 즉 세그폴트는 처리 로직이 아니라 라이브러리 언로드 순서에서 발생했다.

Log Evidence#

사용한 Datadog 쿼리:

text
service:cupixworks-pix-genie-preprocessor-instance "PixGenie process failed with exit code"

14일 창 4건 조회. capture별 전체 흐름 확인 쿼리:

text
service:cupixworks-pix-genie-preprocessor-instance "capture_47326"

파이프라인이 크래시 직전 정상 완료되었음을 보여주는 로그:

text
2026-08-07 11:49:23 info  PixGenieProcess | [2026-08-07T02:49:23.067Z] Pipeline result saved to: /tmp/workspace/capture_47326/output/pixgenie_result.json

메모리/디스크가 충분해 OOM이 아님을 보여주는 processing monitor 로그:

text
cpuUsage(%): 93.62, freeMemory(MB): 23389.07, VmSize(MB): 15339.18, vmRSS(MB): 6318.13, VmPeak(MB): 15386.64, freeDisk: 482357.93, timestamp: 2026-08-07T02:36:15
avg.cpuUsage(%d): 55.66, min.freeMemory(MB): 23389.07, max.VmPeak(MB): 15386.64

capture_47326에는 uploadPixGenieResult 로그가 전혀 없어 업로드 단계에 도달하지 못했음을 확증한다. 대조로, 정상 처리된 capture들은 다음과 같이 업로드 성공 로그를 남긴다:

text
2026-08-06 11:59:26 info  PixGenieManager::uploadPixGenieResult | uploading result for capture: 749615
2026-08-06 11:59:26 info  PixGenieManager::uploadPixGenieResult | file verified - size: 218620 KB
2026-08-06 11:59:32 info  PixGenieManager::uploadPixGenieResult | upload completed

크래시 후 정리 흐름 로그:

text
2026-08-07 11:49:24 error PreprocessorService::run | end - {"stack":"Error: PixGenie process failed with exit code 11. STDERR: ...
2026-08-07 11:49:24 info  FileSystemManager::cleanupWorkspace | workspace cleaned: /tmp/workspace/capture_47326
2026-08-07 11:49:24 info  PreprocessorService::run | end
2026-08-07 11:49:24 info  PreprocessorService::terminateService | force shutdown after 600 seconds

동일 시그니처의 크래시가 이전에도 발생했음 (SIGSEGV + unregisterObjectCreator unload frame + feature 100% 완료). 14일 창 발생: 2026-07-30 05:31, 2026-07-30 18:07, 2026-08-07 11:49 (2건, 동일 이벤트가 pixgenie.process.ts:37preprocessor-service.ts:102에서 각각 로깅됨).

Hypotheses Considered#

# Hypothesis Evidence for Evidence against Verdict
H1 PixGenie native library가 처리 완료 후 teardown (bootstrap::unloadscene_model::unloadunregisterObjectCreator)에서 SIGSEGV로 크래시, agent가 non-zero exit을 무조건 실패로 처리 native stack dump frame 3-5가 unload 경로, frame 8-9가 libc exit handler; Pipeline result saved to ... pixgenie_result.json가 크래시 직전 (02:49:23) 기록; Extracting Features: 100% 완료; pixgenie.process.ts:105-113code !== 0이면 무조건 reject Confirmed
H2 메모리 부족 (OOM)으로 인한 크래시 대용량 ML 모델 (dinov3 1.13G) 로딩 processing monitor 로그상 freeMemory 23 GB 이상, freeDisk 482 GB, VmPeak 15 GB로 여유 충분; SIGSEGV는 OOM-killer의 SIGKILL(9)과 다름 Rejected
H3 실제 처리 실패 (feature 추출 또는 pipeline 로직 오류) exit code non-zero feature 추출 226/226 완료, pipeline result 저장 성공 로그 존재; 크래시 위치가 처리 로직이 아닌 unload 경로 Rejected
H4 agent의 2시간 timeout (TIMEOUT_MS)으로 인한 abort runPythonProcess에 timeout 로직 존재 (pixgenie.process.ts:56-61) 처리 전체 소요가 약 14분 (11:35~11:49)으로 2시간 미만; process timeout, aborting warn 로그 없음; 종료 원인은 SIGSEGV Rejected
H5 exit code 11이 signal 11(SIGSEGV)을 그대로 반영한 값이며, g3log handler가 아니라 kernel이 프로세스를 죽였다 STDERR에 SIGSEGV(11) 명시 STDERR에 g3log FATAL SIGNAL + STACKDUMP 블록이 존재 = g3log signal handler가 신호를 잡아 dump 후 종료. Node closecode가 11로 채워진 것은 handler가 코드 11로 exit했음을 시사 (kernel-kill이면 code=null, signal='SIGSEGV') Inconclusive

Fix Recommendation#

즉시 조치 (Critical)#

  • 재실행으로 capture 47326을 복구한다. 처리 로직 자체는 정상이므로 재시도 시 teardown 크래시가 재현되지 않으면 성공 가능성이 높다.
  • native teardown 크래시는 데이터 손상이 아니라 shutdown-only 이슈다. 즉시 코드 변경 없이 재처리로 대응 가능.

단기 개선 (1주 이내)#

  • src/process/pixgenie.process.tsclose 핸들러 (105-113)와 execute (32-40)에서, non-zero exit이더라도 산출물 검증을 우선하도록 로직 방향을 조정한다. 구체적으로 verifyOutput (pixgenie.process.ts:121-127)이 pixgenie.sqlite 존재 및 유효성을 확인하면, STDERR에 Received fatal signal 같은 teardown-only 크래시 시그니처가 있고 산출물이 완전한 경우 성공으로 처리하는 방향을 검토한다. 단, 산출물 무결성 (sqlite 완전 flush 여부)을 반드시 검증해야 하며, 검증 실패 시에는 기존대로 실패 처리한다.
  • pixgenie_result.json 저장 로그 이후 pixgenie.sqlite가 완전히 기록되는 시점을 로그로 남겨, 크래시 시 산출물이 완전한지 판정할 근거를 확보한다.

장기 개선 (재발 방지)#

  • PixGenie native library (libfoundation.so, libscenemodel.so)의 shutdown-time segfault를 근본 수정한다. unregisterObjectCreator에서의 크래시는 C++ static/전역 factory 객체의 소멸 순서 (static destruction order fiasco) 또는 이미 언로드된 모듈의 심볼 참조가 원인일 가능성이 높으므로, PixGenie 라이브러리 소유 팀에서 factory teardown 순서를 점검한다.
  • 처리 완료 후 exit을 명시적으로 성공 코드로 종료하도록 docker_entrypoint.py 레벨에서 파이프라인 완료 직후 즉시 성공 종료 (예: os._exit(0))를 검토해, 정상 완료된 작업이 teardown 크래시로 실패 처리되지 않도록 한다. 단 이는 리소스 정리 우회이므로 native 팀과 협의가 필요하다.

Monitoring#

teardown SIGSEGV 재발 추적 (배포 후 감소 확인용):

text
service:cupixworks-pix-genie-preprocessor-instance status:error "PixGenie process failed with exit code 11"

전처리 실패 전반 추이:

text
service:cupixworks-pix-genie-preprocessor-instance status:error "PreprocessorService::run | end"

정상 업로드 완료 건수 (성공률 확인용, 위 실패 쿼리와 비교):

text
service:cupixworks-pix-genie-preprocessor-instance "PixGenieManager::uploadPixGenieResult | upload completed"

Risk Assessment#

  • Risk level: low
  • 예상 복잡도: standard

capture 처리 결과가 손상되지 않고 재실행으로 복구 가능하므로 즉시 위험도는 낮다. 다만 native teardown 크래시가 간헐적으로 정상 완료 작업을 실패로 처리하므로, agent의 exit-code 판정 로직 개선과 native library 근본 수정이 병행되어야 재발을 막을 수 있다. agent 측 단기 개선은 산출물 무결성 검증을 전제로 해야 하므로 standard 복잡도로 평가한다.