ES /docs

MaskWork#maskPanos stderr을 모두 error로 기록 — 로그 레벨 매핑 오류

RCA: MaskWork::maskPanos | PyTorch UserWarning: No PYTORCH_KERNEL_CACHE_PATH or HOME

Error Log#

Datadog Logs

text
MaskWork::maskPanos | script /tmp/lib/face-body-detector/sam3/model/encoder.py:358: UserWarning: No PYTORCH_KERNEL_CACHE_PATH or HOME environment variable set! This disables kernel caching. (Triggered internally at /pytorch/aten/src/ATen/native/cuda/jit_utils.cpp:1426.)
  spatial_shapes.prod(1).cumsum(0)[:-1],

Impact#

  • Service: cupixworks-pix-genie-preprocessor-instance
  • Team: sinsw
  • 발생 횟수: 17
  • 최초 발생: 2026-04-20T01:40:00.654Z
  • 최근 발생: 2026-04-20T02:11:33.502Z

Root Cause Summary#

MaskWork::maskPanos 메서드가 face-body-detector Python 스크립트를 child process로 실행할 때, spawn()env 옵션에 INPUT_DIRPATH, OUTPUT_DIRPATH, OPTION_FILE_PATH 세 가지 변수만 전달하고 부모 프로세스의 환경변수(process.env)를 상속하지 않는다. Node.js의 spawn()env가 명시적으로 지정되면 부모 환경변수를 완전히 대체하므로, HOMEPYTORCH_KERNEL_CACHE_PATH가 모두 누락된다. PyTorch의 CUDA JIT 컴파일러(jit_utils.cpp:1426)가 kernel cache 디렉토리를 결정할 때 이 두 변수를 참조하는데, 둘 다 없으면 UserWarning을 stderr로 출력한다. TypeScript 코드의 process.stderr.on('data', ...) 핸들러(mask-work.ts:40-42)가 모든 stderr 출력을 logger.error() 레벨로 기록하여 Datadog에 에러로 수집된다. 처리 자체는 정상 완료되지만, CUDA kernel caching이 비활성화되어 반복 실행 시 성능이 저하된다.

Technical Analysis#

Code Path#

  • Entry point: cupix-pano-postprocessor/src/pano-postprocessor-service.ts:126maskPanos() 호출
  • Child process spawn: cupix-pano-postprocessor/src/work/mask-work.ts:29-33 — 환경변수 교체
  • Stderr handler: cupix-pano-postprocessor/src/work/mask-work.ts:40-42logger.error로 기록
  • BlurScriptPath: cupix-pano-postprocessor/src/config/constants.ts:5/tmp/lib/face-body-detector/run.sh

1. PanoPostprocessorService에서 mask 처리를 시작:

typescript
// cupix-pano-postprocessor/src/pano-postprocessor-service.ts:123-127
if (maskTypeOption) {
    this.maskWork.createOptionFile(optionPath, maskTypeOption);
    start = Date.now();
    await this.maskWork.maskPanos(downloadDir, maskDir!, optionPath);
    this.panoPostprocessorManager.logElapsedTime(start, 'blur_panos');

2. MaskWork::maskPanos에서 face-body-detector Python 스크립트를 실행:

typescript
// cupix-pano-postprocessor/src/work/mask-work.ts:29-33
const process: ChildProcessWithoutNullStreams = spawn('stdbuf', ['-oL', 'bash', BlurScriptPath], {
    cwd: path.dirname(BlurScriptPath),
    stdio: 'pipe',
    env: { INPUT_DIRPATH: inputDir, OUTPUT_DIRPATH: outputDir, OPTION_FILE_PATH: optionPath }
});

env 프로퍼티에 3개의 변수만 설정하고 ...process.env를 포함하지 않아, HOME, PATH, PYTORCH_KERNEL_CACHE_PATH 등 모든 부모 프로세스 환경변수가 자식 프로세스에 전달되지 않는다.

3. stderr 핸들러가 모든 stderr 출력을 error로 기록:

typescript
// cupix-pano-postprocessor/src/work/mask-work.ts:40-42
process.stderr.on('data', (data) => {
    logger.error('MaskWork::maskPanos | script %s', data.toString());
});

Python의 warnings.warn()은 기본적으로 stderr로 출력하므로, PyTorch의 UserWarning이 에러 레벨로 기록된다.

4. 비교: PixGenieProcess는 올바르게 환경변수를 전달:

typescript
// cupix-pix-genie-preprocessor-agent/src/process/pixgenie.process.ts:65-70
this._process = spawn('python3', [PixGenieProcess.PIXGENIE_SCRIPT_PATH], {
    env: { ...process.env, ...this.buildEnvironment(params) },
    stdio: ['ignore', 'pipe', 'pipe'],
    cwd: params.workspaceDir,
    signal: this._abortController.signal
});

PixGenieProcess...process.env spread를 사용하여 부모의 환경변수를 보존한 후 커스텀 변수를 추가하는 올바른 패턴을 사용하고 있다. 또한 stderr를 logger.warn 레벨로 기록한다 (pixgenie.process.ts:99-103).

5. BlurScriptPath는 face-body-detector 라이브러리를 가리킴:

typescript
// cupix-pano-postprocessor/src/config/constants.ts:5
export const BlurScriptPath = '/tmp/lib/face-body-detector/run.sh';

이 스크립트가 SAM3 모델(/tmp/lib/face-body-detector/sam3/model/encoder.py:358)을 로드하면서 PyTorch CUDA JIT 컴파일이 트리거되고, HOME이 없어 커널 캐싱이 비활성화된다.

Log Evidence#

Datadog 쿼리:

text
service:cupixworks-pix-genie-preprocessor-instance status:error "face-body-detector"
Time range: 2026-04-20T00:40:00Z to 2026-04-20T02:30:00Z

대표 에러 로그 (capture 45640, job 106527):

json
{
  "timestamp": "2026-04-20T02:08:56.855Z",
  "status": "error",
  "service": "cupixworks-pix-genie-preprocessor-instance",
  "message": "MaskWork::maskPanos | script /tmp/lib/face-body-detector/sam3/model/encoder.py:358: UserWarning: No PYTORCH_KERNEL_CACHE_PATH or HOME environment variable set! This disables kernel caching.",
  "capture.id": 45640,
  "job.id": 106527,
  "team.domain": "sinsw",
  "tenant": "nswgov",
  "region": "ap-southeast-2",
  "host.name": "7b2ed70d85ca",
  "user.email": "robert.grahame2@det.nsw.edu.au"
}

영향받은 캡처 타임라인:

Timestamp Capture ID Job ID Host Region
2026-04-20T01:34:47.308Z 45638 106526 e34324c4cf20, d4eab215fcf3, c2d01ab4cf38 ap-southeast-2
2026-04-20T01:40:00.654Z 45641 106534 39453121dfcb, 7b2ed70d85ca ap-southeast-2
2026-04-20T01:42:59.991Z 45639 106525 39453121dfcb, 7b2ed70d85ca ap-southeast-2
2026-04-20T02:08:56.855Z 45640 106527 7b2ed70d85ca ap-southeast-2

모든 에러가 동일한 tenant(nswgov), team(sinsw)에서 발생. 여러 호스트 컨테이너에서 동시 발생하여 인프라 문제가 아닌 코드 구성 문제임을 확인.

동일 시간대 context 로그에서 처리 정상 완료 확인:

text
service:cupixworks-pix-genie-preprocessor-instance -status:error
Time range: 2026-04-20T00:40:00Z to 2026-04-20T02:30:00Z
json
{
  "timestamp": "2026-04-20T01:02:27.539Z",
  "status": "info",
  "message": "PreprocessorService::run | Starting Pix Genie preprocessing"
}
json
{
  "timestamp": "2026-04-20T01:02:27.540Z",
  "status": "info",
  "message": "PixGenieProcess::execute | begin - captureId: 44894"
}

warn 레벨 로그에서 PixGenieProcess의 stderr 출력도 확인 (download progress bar):

json
{
  "timestamp": "2026-04-20T02:23:07.000Z",
  "status": "warn",
  "message": "PixGenieProcess | STDERR: 100%|██████████| 1.13G/1.13G [00:00<00:00, 3.38GB/s]"
}

PixGenieProcess는 동일한 stderr 출력을 warn 레벨로 기록하는 반면, MaskWorkerror 레벨로 기록한다는 차이가 확인됨.

Fix Recommendation#

즉시 조치 (Critical)#

  • 파일: cupixworks/applications/agents/packages/cupix-pano-postprocessor/src/work/mask-work.ts:32
  • spawn()env 옵션에 ...process.env를 추가하여 부모 프로세스의 환경변수를 상속하도록 수정. PixGenieProcess(pixgenie.process.ts:66)의 { ...process.env, ...customEnv } 패턴을 참고.

단기 개선 (1주 이내)#

  • 파일: cupixworks/applications/agents/packages/cupix-pano-postprocessor/src/work/mask-work.ts:40-42
  • stderr 핸들러의 로그 레벨을 logger.error에서 logger.warn으로 변경. Python 프로세스의 stderr에는 warning, deprecation notice, progress bar 등 에러가 아닌 메시지가 포함될 수 있다. 실제 에러는 exit code로 판별하며, 현재 코드도 process.on('close', ...) 핸들러(mask-work.ts:49-57)에서 exit code를 확인하고 있다.

장기 개선 (재발 방지)#

  • 모든 agent 패키지에서 spawn() 호출 시 env 옵션에 항상 ...process.env를 spread하는 패턴을 표준화. PixGenieProcess의 패턴({ ...process.env, ...customEnv })을 표준으로 채택.
  • Dockerfile에 ENV PYTORCH_KERNEL_CACHE_PATH=/tmp/.cache/torch/kernels를 추가하여 컨테이너 레벨에서 PyTorch 커널 캐시 경로를 명시적으로 설정하는 방안 검토.

Monitoring#

  • 수정 후 에러 감소 확인:
text
service:cupixworks-pix-genie-preprocessor-instance status:error "MaskWork::maskPanos" "PYTORCH_KERNEL_CACHE_PATH"
  • mask 처리 성능 변화 모니터링 (kernel caching 활성화로 인한 개선):
text
service:cupixworks-pix-genie-preprocessor-instance "blur_panos" "elapsed"

Risk Assessment#

  • Risk level: low
  • 예상 복잡도: trivial
  • 이유: 처리는 정상 완료되며 기능적 영향 없음. GPU 커널 재컴파일로 인한 성능 저하만 존재. 수정은 spawn() 호출의 env 옵션에 ...process.env spread 추가 및 stderr 로그 레벨 변경.