FileSystemManager::loadSkatMasterResults | end - not found file - /efs/440b1b3f3824bb81/skatmaster/r
RCA: FileSystemManager::loadSkatMasterResults | end - not found file
Error Log#
FileSystemManager::loadSkatMasterResults | end - not found file - /efs/440b1b3f3824bb81/skatmaster/results/processing_status.json
Impact#
- Service:
cupixworks-capture-postprocessor-agent - Team: walmart
- 발생 횟수: 1
- 최초 발생: 2026-04-14T19:24:22.942Z
- 최근 발생: 2026-04-14T19:24:22.942Z
Root Cause Summary#
cupixworks-capture-postprocessor-agent가 capture 681052 (job 1015022)의 후처리를 시작했을 때, 상위 단계인 cupix-skat-master-agent가 EFS 경로 /efs/440b1b3f3824bb81/skatmaster/results/에 processing_status.json 파일을 아직 생성하지 않은 상태였습니다. cupixworks-any-compute-agent가 19:22:47Z에 EFS 경로를 설정하고 컨테이너를 시작한 후 약 95초 만에 postprocessor-agent가 결과를 읽으려 시도했으나, skat-master 처리가 완료되지 않아 파일이 존재하지 않았습니다. 이 에러로 인해 Promise가 reject되었고, getApiErrorToDeleteMessage에서 undefined error로 판단되어 SQS 메시지가 삭제되면서 자동 재시도 기회가 소멸되었습니다.
Technical Analysis#
Code Path#
- Entry point:
base-service.ts:153—runByMessage가 SQS 메시지를 수신하여 job 1015022 처리 시작 postprocessor-service.ts:64—run()메서드가 job을 로드하고 CPCapture를 생성postprocessor-service.ts:87-91— EFS 경로 설정 후 순차적으로 파일 로드 시작
// postprocessor-service.ts:85-91
const fileSystemManager = new FileSystemManager(Environment.DEBUG_MODE);
fileSystemManager.setErrorCode = (errorCode: string) => this.jobManager.setErrorCode(errorCode);
fileSystemManager.setEfsPath(cpCapture);
fileSystemManager.makeEfsDirectory();
await fileSystemManager.loadCPCaptureModel(cpCapture);
await fileSystemManager.loadCPCaptureModelFromVideoDecodingResult(cpCapture);
await fileSystemManager.loadSkatMasterResults(cpCapture); // <-- 여기서 실패
- Failure point:
file-system.manager.ts:188-190—CPUtils.getFileSize()가 -1을 반환하여 파일 미존재 확인 후 reject
// file-system.manager.ts:178-191
loadSkatMasterResults = (cpCapture: CPCapture): Promise<void> => new Promise((resolve, reject) => {
logger.debug('FileSystemManager::loadSkatMasterResults | begin');
if (this.setErrorCode) this.setErrorCode(ErrorCode.Agent.FailedToLoadSkatMasterResults);
if (this.skatMasterDirPath == undefined) {
logger.error('FileSystemManager::loadSkatMasterResults | end - undefined directory path');
return reject();
}
const skatMasterResultsFilePath = path.join(this.skatMasterDirPath, Constants.DefaultResultsDirName, Constants.DefaultSkatMasterFileName);
if (CPUtils.getFileSize(skatMasterResultsFilePath) === -1) {
logger.error('FileSystemManager::loadSkatMasterResults | end - not found file - %s', skatMasterResultsFilePath);
return reject(); // reject()에 에러 객체 없이 호출됨
}
// ...
reject()가 인자 없이 호출되어 에러 값이undefined로 전파됨base-service.ts:109-110—runByMessage에서 throw된 에러가checkingQueue의 catch 블록으로 전달
// base-service.ts:106-111
try {
await this.runByMessages();
} catch (error) {
await this.handlingMessageErrors(error);
}
base-service.ts:240-244—getApiErrorToDeleteMessage에서undefined에러를 받아'undefined error'문자열 반환 (truthy)
// base-service.ts:240-244
private getApiErrorToDeleteMessage = (error: any): any => {
if (error == undefined) {
logger.warn('BaseService::getApiErrorToDeleteMessage | undefined error');
return 'undefined error'; // truthy 값 반환 → 메시지 삭제 결정
}
base-service.ts:300-304—apiErrorObject가 truthy이므로 SQS 메시지가 삭제됨
// base-service.ts:300-304
const apiErrorObject = this.getApiErrorToDeleteMessage(error);
if (apiErrorObject != undefined || this.checkReceiveCountToDeleteMessage()) {
// apiErrorObject가 'undefined error'(truthy)이므로 이 블록 실행
await this.deleteByMessage(this.messageInProcess);
if (this._modelInProcess != undefined && this._modelInProcess.id > 0) await this.updateErrorState(this._modelInProcess);
}
기대 동작: skat-master 처리가 완료된 후에만 postprocessor-agent가 실행되어야 하며, 파일 미존재 시 재시도가 가능해야 합니다.
실제 동작: skat-master 결과 파일이 아직 생성되지 않은 상태에서 postprocessor가 실행되었고, reject()에 에러 객체가 없어 undefined로 전파되어 getApiErrorToDeleteMessage가 메시지를 삭제 대상으로 판단했습니다.
Log Evidence#
Datadog에서 사용한 쿼리:
service:cupixworks-capture-postprocessor-agent status:error @environment:production "FileSystemManager"
service:cupixworks-capture-postprocessor-agent @environment:production @job.id:1015022
service:cupixworks-any-compute-agent @environment:production "440b1b3f3824bb81"
타임라인 (Job 1015022, Capture 681052):
| 시간 (UTC) | 서비스 | 레벨 | 메시지 |
|---|---|---|---|
| 19:22:47.649Z | cupixworks-any-compute-agent | info | QMJob::makeContainerOverride — EFS 경로 설정 (EFS_SKAT_MASTER_PATH=/efs/440b1b3f3824bb81/skatmaster) |
| 19:24:22.288Z | postprocessor-agent | info | BaseService::runByMessage | id: 1015022 |
| 19:24:22.333Z | postprocessor-agent | info | JobManager::loadJob | begin - job id: 1015022 |
| 19:24:22.376Z | postprocessor-agent | info | JobManager::loadJob | end - job id: 1015022 |
| 19:24:22.927Z | postprocessor-agent | info | CPCapture::fromMeta | key: Y8sm4NF3V, version: 1 |
| 19:24:22.942Z | postprocessor-agent | error | FileSystemManager::loadSkatMasterResults | end - not found file - /efs/.../processing_status.json |
| 19:24:22.944Z | postprocessor-agent | warn | BaseService::getApiErrorToDeleteMessage | undefined error |
| 19:24:22.945Z | postprocessor-agent | info | AwsQueueManager::deleteMessage | begin — SQS 메시지 삭제 시작 |
| 19:24:22.974Z | postprocessor-agent | info | AwsQueueManager::deleteMessage | end - message id: 95283124-... |
| 19:24:25.631Z | postprocessor-agent | error | BaseService::handlingMessageErrors | Error and message object - {"error":"undefined error","sqsMessage":{"MessageId":"95283124-...","Attributes":{"ApproximateReceiveCount":"1"}}} |
핵심 관찰 사항:
ApproximateReceiveCount가 1이므로 첫 번째 시도에서 바로 메시지가 삭제됨 (재시도 없음)- 동일 세션의 다른 capture(681051, job 1015014)는 다른 호스트에서 정상 처리됨 — 인프라 문제가 아닌 타이밍/순서 문제
getApiErrorToDeleteMessage의undefined errorwarn 로그가 에러 객체 없는 reject 확인
Fix Recommendation#
즉시 조치 (Critical)#
-
file-system.manager.ts:190—reject()호출 시 에러 객체를 포함하도록 수정. 현재 인자 없이 호출되어undefined가 전파되고, 이것이getApiErrorToDeleteMessage에서 메시지 삭제로 이어집니다.reject(new Error('...'))로 변경하면getApiErrorToDeleteMessage가 Node.js 에러로 인식하여 메시지를 삭제하지 않고 재시도 기회를 보존합니다. -
base-service.ts:240-244—undefined에러를 받았을 때 메시지를 삭제하는 현재 로직 검토.undefined에러는 일시적 파일 미존재 등의 원인일 수 있으므로, 재시도가 더 적절한 처리 방식입니다.
단기 개선 (1주 이내)#
-
파이프라인 순서 보장:
cupixworks-any-compute-agent가 postprocessor SQS 메시지를 보내기 전에 skat-master 처리가 완료되었는지 확인하는 메커니즘 검토. 현재 약 95초 만에 postprocessor가 실행을 시도하는데, skat-master 처리 시간이 이보다 길 수 있습니다. -
재시도 로직 추가:
loadSkatMasterResults에서 파일 미존재 시 일정 간격으로 재시도하는 로직 추가 검토 (예: 30초 간격으로 3회 재시도). 다른 load 메서드들(loadCPCaptureModelFromVideoDecodingResult등)은 파일 미존재를 resolve로 처리하는데,loadSkatMasterResults는 reject하여 일관성이 없습니다.
장기 개선 (재발 방지)#
-
이벤트 기반 트리거링: postprocessor-agent가 SQS 폴링이 아닌 skat-master 완료 이벤트를 기반으로 실행되도록 아키텍처 변경 검토. 이렇게 하면 처리 순서가 보장됩니다.
-
reject() 표준화: 모든 agent 패키지에서
reject()호출 시 항상 에러 객체를 포함하도록 코딩 표준 적용.getApiErrorToDeleteMessage가 에러 타입에 따라 재시도/삭제를 결정하므로, 에러 객체 누락은 잘못된 삭제 판단으로 이어집니다.
Monitoring#
- 다음 Datadog 쿼리로 동일 패턴 모니터링:
service:cupixworks-capture-postprocessor-agent status:error "loadSkatMasterResults" "not found file"
undefined error로 인한 SQS 메시지 삭제 추적:
service:cupixworks-capture-postprocessor-agent "getApiErrorToDeleteMessage" "undefined error"
ApproximateReceiveCount:1에서 삭제되는 메시지 비율 메트릭 추가 권장
Risk Assessment#
- Risk level: medium
- 예상 복잡도: standard