BaseTaskContainer::checkTaskFail | Failed - Total: 500, Done: 285, Failed: 10
RCA: BaseTaskContainer::checkTaskFail | Failed - Total: 500, Done: 285, Failed: 10
Error Log#
BaseTaskContainer::checkTaskFail | Failed - Total: 500, Done: 285, Failed: 10
Impact#
- Service:
cupixworks-capture-postprocessor-agent - Team: tridentconstruction
- 발생 횟수: 206
- 최초 발생: 2026-04-13T21:29:55.767Z
- 최근 발생: 2026-04-13T21:30:16.591Z
Root Cause Summary#
tridentconstruction 팀의 postprocessor agent (capture 680042, job 1012296)가 pano 업로드 시 잘못된 capture_id(680039, metconus 팀 소유)를 사용하여 API를 호출했습니다. Tesla API의 권한 검사 (CaptureRepository#permission_joins)에서 tridentconstruction 사용자(Liam Hudock, user_id 32496)가 metconus 소유 capture 680039에 접근 권한이 없어 HTTP 403 (Cupix::Errors::NotFound, code ARG10002, "Capture not found")을 반환했습니다. HTTP 403은 agent SDK에서 HttpError로 throw되어 init() 단계에서 즉시 실패하고, pano가 생성되지 않아 upload_url이 설정되지 않았습니다. checkStatusCode()가 403을 비재시도 대상(400 < 403 < 500)으로 판단하여 failTask()를 즉시 호출, count: 0/5로 재시도 없이 실패했습니다.
잘못된 capture_id 사용 원인: agent는 workspace 디렉토리 /tmp/workspace/680039/videos/640181/의 파일을 처리했습니다. EFS의 preprocessor 메타데이터(cpcapture.json)에 srvVideo.capture.id = 680039가 임베딩되어 있었고, CPVideo.fromMeta() (cpvideo.ts:108-124)가 이를 검증 없이 역직렬화하여 잘못된 capture_id가 createPanoRequest에 전파되었습니다.
workspace가 cleanup되지 않은 원인: 이전 job 1012095 (capture 680039)은 20:03:37에 최초 실행되어 20:09:51에 workspace가 정상 cleanup되었습니다. 그러나 SQS visibility timeout 만료로 21:15:48에 동일 메시지가 재수신되어 copySourceDir() (file-system.manager.ts:413-445)가 EFS에서 /tmp/workspace/680039/로 파일을 다시 복사했습니다. 재처리 중 21:26:59에 RESC10000 ("Resource does not uploaded") 에러로 실패했고, handlingMessageErrors() (base-service.ts:290-313)는 SQS 메시지 삭제만 수행하고 workspace cleanup을 호출하지 않았습니다. cleanUpAnythingRelatedModel() (base-service.ts:204-222)은 runByMessage()의 성공 경로(line 171)에서만 호출되며, 에러 경로에서는 호출되지 않습니다. 결과적으로 /tmp/workspace/680039/가 디스크에 잔존한 상태에서, 직후 21:27:00에 job 1012296 (capture 680042)이 동일 agent에서 실행되어 stale workspace의 영향을 받았습니다.
285개의 성공한 pano는 올바른 capture 680042에 대해 생성된 것이며, 실패한 215개는 잘못된 capture 680039에 대해 시도된 것입니다.
Technical Analysis#
Code Path#
1. API 서버 측 — upload_url 생성 경로#
upload_url은 Tesla API에서 다음 체인을 통해 생성됩니다:
PanoSerializer(pano_serializer.rb:110-116)에서resource_state_name이[:created, :uploading, :missing]에 포함될 때만upload_url반환
# pano_serializer.rb:110-116
attribute :upload_url do |pano, params|
if %i[created uploading missing].include?(pano.resource_state_name)
pano.resource_upload_url
else
nil
end
end
Resourcable::Pano#resource_upload_url(resourcable/pano.rb:47-49) →Resourcable#upload_url(resourcable.rb:70-80) →Storagable::Resource#presigned_upload_url(storagable/resource.rb:111-131)
# storagable/resource.rb:111-131
def presigned_upload_url(revision, force: false)
revision ||= self.revision + 1
client = Cupix::StorageService.client(storage_option: storage_option)
signer = Aws::S3::Presigner.new(client: client)
signer.presigned_url(:put_object, bucket: bucket_name, key: object(revision).key, ...)
end
-
Aws::S3::Presigner는 로컬 암호화 서명 연산이며 네트워크 호출 없음 — S3 rate limiting이나 IAM throttling은 원인이 아님 -
upload_url이nil이 되는 조건:resource_state_name이[:created, :uploading, :missing]에 없을 때 (e.g.,:uploaded)resourceassociation이nil일 때 (resourcable.rb:71-73)- Pano 자체가 생성되지 않았을 때 (HTTP 403/에러 응답) — 이번 사건의 원인
2. API 서버 측 — 권한 검사 (403 발생 경로)#
PanosController#create(panos_controller.rb:43-47) →PanoFactory#create!(pano_factory.rb:7-16)에서CaptureRepository.new(current_user: self.current_user).show(params[:capture_id])호출BaseRepository#show(base_repository.rb:327-353)에서permission_joins()로 팀 권한 검사 수행- tridentconstruction 사용자가 metconus 소유 capture 680039에 권한 없음 →
model = nil→Cupix::Errors::NotFound(codeARG10002) raise ClientErrorController(client_error_controller.rb:27,55-57)에서NotFound를 HTTP 403으로 변환
# client_error_controller.rb:27
rescue_from Cupix::Errors::NotFound, with: :not_found_403_error
# client_error_controller.rb:55-57
def not_found_403_error(exception)
raise_error(403, exception)
end
3. Agent 측 — HTTP 403 처리 경로#
cupixApi.pano.create()→ Tesla SDK (panoApi.js:1026-1040)에서 status 200-299 범위 외의 응답은HttpError로 rejectcupixRetriableRequest()에서 403은 retriable 코드(408, 429, 500, 502, 503, 504)에 포함되지 않아 에러 전파UploadNewPanosTask.init()(upload-new-panos.task.ts:39)에서HttpErrorthrow →responsePano할당 안 됨 →setServerPanoData()미호출 →_uploadUrl미설정transferTask()catch →retryTask()→checkStatusCode(error)(transfer.manager.ts:168-171)
// transfer.manager.ts:168-171
private checkStatusCode = (error: any): boolean => {
if (error?.statusCode != undefined && error.statusCode > 400 && error.statusCode < 500) return false;
return true;
};
- 403은
400 < 403 < 500이므로false반환 → 재시도 불가 → 즉시failTask()→count: 0/5로 로그
4. 잘못된 capture_id 전파 경로 (근본 원인)#
- Agent 세션 생성:
capture.user.agent_team_session(capture.team)(processible_capture.rb:59-65,user.rb:116-126) — capture 680042의 owner(tridentconstruction) 세션으로 정상 생성 - SQS 메시지에
session.token포함 (cws/capture_postprocessor_agent.rb:19-39) - Agent가 job 로드 시
FileSystemManager.loadCPCaptureModel()(file-system.manager.ts:103-136)에서 EFS의 preprocessor 메타데이터(cpcapture.json) 읽기 CPCapture.fromMeta()(cpcapture.ts:622-639)에서CPVideo.fromMeta(videoMeta)호출CPVideo.fromMeta()(cpvideo.ts:108-124)에서meta.srvVideo에 임베딩된 이전 capture (680039) 데이터를 검증 없이this._serverModel에 설정CPCapture.fromMeta()(cpcapture.ts:601)에서 capture ID 불일치 검사 존재하나, 비디오 메타데이터의 임베딩된 capture ID는 재귀적으로 검증하지 않음
// cpcapture.ts:601
if (metaCaptureId == undefined || (captureId != undefined && captureId !== metaCaptureId)) {
logger.warn('CPCapture::fromMeta | capture ID is different...');
return false;
}
UploadNewPanosTask.init()의createPanoRequest에서capture_id: cpCapture.id를 사용하지만, 500개 task 중 215개가 잘못된 메타데이터 경로(/tmp/workspace/680039/)의 파일을 참조
5. Workspace Cleanup 실패 경로 (stale workspace 잔존 원인)#
Agent의 workspace cleanup은 BaseService.cleanUpAnythingRelatedModel() (base-service.ts:204-222)에서 수행됩니다:
// base-service.ts:204-222
private cleanUpAnythingRelatedModel = (): Promise<void> => new Promise(resolve => {
if (Environment.DEBUG_MODE && Environment.CPX_SKIP_CLEANUP_DATA) {
return resolve(); // skip in debug mode
}
if (this._modelDirPath) {
CPUtils.deleteFolderRecursive(this._modelDirPath);
this._modelDirPath = undefined;
resolve();
} else {
resolve(); // undefined modelDirPath — no cleanup
}
});
이 함수는 runByMessage() (base-service.ts:153-191)의 성공 경로에서만 호출됩니다:
// base-service.ts:164-185
try {
await TraceUtils.activateSpan(span, async () => {
await this.authenticateByMessage(msgObject);
await this.run(targetId, msgObject); // ← 여기서 에러 발생 시
await this.cleanUpAnythingRelatedModel(); // ← 이 줄에 도달하지 못함
await this.deleteByMessage(message);
});
} catch (error) {
throw error; // ← 에러가 상위로 전파
}
에러 발생 시 flow:
this.run()(line 170) →PostprocessorService::run()→FinalizationService→UploadNewPanosTask→check_uploadingAPI 호출 실패 → throwcatch (error)(line 182) →throw error→ 상위checkingQueue()(line 109)의catchhandlingMessageErrors()(base-service.ts:290-313) 호출:
// base-service.ts:290-313
private handlingMessageErrors = async (error: any): Promise<void> => {
if (this.messageInProcess) {
const apiErrorObject = this.getApiErrorToDeleteMessage(error);
if (apiErrorObject != undefined || this.checkReceiveCountToDeleteMessage()) {
await this.deleteByMessage(this.messageInProcess); // SQS 메시지만 삭제
if (this._modelInProcess) await this.updateErrorState(...); // 에러 상태 업데이트
}
// ❌ cleanUpAnythingRelatedModel() 호출 없음 — workspace 잔존
}
};
SQS 재수신에 의한 workspace 재생성: workspace /tmp/workspace/680039/는 20:09:51에 정상 cleanup되었지만, SQS visibility timeout 만료로 21:15:48에 job 1012095이 재수신됨. PostprocessorService::run() → fileSystemManager.copySourceDir(cpCapture) (postprocessor-service.ts:103)에서 EFS의 preprocessor 결과를 workspace에 다시 복사:
// file-system.manager.ts:413-427
copySourceDir = (cpCapture: CPCapture): Promise<boolean> => new Promise((resolve, reject) => {
const preProcessorResultDir = path.join(this.preProcessorDirPath, Constants.DefaultResultsDirName);
CPUtils.copyFolderRecursiveSync(preProcessorResultDir, cpCapture.workspaceDirPath, false);
// video frame files 복사 → /tmp/workspace/680039/videos/640181/original/ 재생성
});
재처리가 21:26:59에 실패한 후, 에러 경로에서 cleanup이 호출되지 않아 /tmp/workspace/680039/가 잔존. Job 1012296 (capture 680042)이 21:27:00에 동일 agent에서 실행되면서 stale workspace의 파일을 참조하게 됨.
기대 동작: capture 680042의 pano만 생성되어 모두 upload_url 포함 응답을 받아 정상 업로드.
실제 동작: 285개는 올바른 capture 680042로 성공, 215개는 잘못된 capture 680039으로 API 호출 → HTTP 403 → init() 실패 → url: undefined → 즉시 failTask() → 206건의 checkTaskFail 에러 로그 생성.
Log Evidence#
사용한 Datadog 쿼리:
service:cupixworks-capture-postprocessor-agent status:error @environment:production "BaseTaskContainer::checkTaskFail"
service:cupixworks-capture-postprocessor-agent status:error @environment:production "TransferManager::failTask"
service:cupixworks-api status:error @environment:production @http.status_code:403 "680039"
service:cupixworks-api status:info @environment:production "680042" "panos"
실패 타임라인:
Phase 1 — 정상 업로드 (21:25:53 ~ 21:26:56, capture 680042):
21:25:53.047Z UploadNewPanosTask::init | begin - cpPano target: /tmp/workspace/680039/videos/640181/original/640181_00696.jpg
21:25:53.061Z createPanoRequest - {"capture_id":680039,"video_id":640181,"name":"VID_...(696).jpg",...}
21:25:53.XXX TransferManager::uploadFile | begin path: .../640181_00696.jpg, url: https://s3.amazonaws.com/cupixworks-source-dc9dcff32488-usea1/resources/.../usea1/v1?...
285개의 pano가 이 패턴으로 정상 업로드.
Phase 2 — 첫 번째 실패 (유효한 URL, 재시도 소진):
21:26:56.307Z TransferManager::failTask | path: /tmp/workspace/680039/videos/640181/original/640181_00674.jpg, url: https://s3.amazonaws.com/cupixworks-source-dc9dcff32488-usea1/resources/jaxpgh/usea1/v1?..., count: 5/5
21:26:56.306Z BaseTaskContainer::checkTaskFail | Failed - Total: 500, Done: 271, Failed: 1
Phase 3 — 연쇄 실패 (url: undefined, HTTP 403, 21:29:54 ~ 21:30:16):
21:29:54.969Z BaseTaskContainer::checkTaskFail | Failed - Total: 500, Done: 285, Failed: 2
21:29:54.970Z TransferManager::failTask | path: /tmp/workspace/680039/videos/640181/original/640181_01006.jpg, url: undefined, count: 0/5
21:29:55.XXX TransferManager::failTask | path: .../640181_01007.jpg, url: undefined, count: 0/5
...
21:30:16.591Z BaseTaskContainer::checkTaskFail | Failed - Total: 500, Done: 285, Failed: 215
API 측 403 에러 (cupixworks-api, 같은 시간대):
21:29:55Z ~ 21:30:18Z POST /api/v1/panos (capture_id=680039) → HTTP 403
user: Liam Hudock (id: 32496, tridentconstruction)
exception: Cupix::Errors::NotFound (code: ARG10002, "Capture not found")
214 occurrences
API 측 정상 응답 (cupixworks-api, capture 680042):
21:30:17Z POST /api/v1/panos (capture_id=680042) → HTTP 200
22:30:47Z ~ 22:31:23Z POST /api/v1/panos (capture_id=680042) → HTTP 200 (241건)
user: Liam Hudock (id: 32496, tridentconstruction)
정상 응답 — upload_url 포함
Workspace Cleanup 로그 (stale workspace 잔존 증거):
service:cupixworks-capture-postprocessor-agent @environment:production "cleanUpAnythingRelatedModel" "680039"
service:cupixworks-capture-postprocessor-agent @environment:production "1012095"
| 시각 (UTC) | 이벤트 |
|---|---|
| 20:03:37.734 | BaseService::runByMessage | id: 1012095 — job 1012095 최초 수신 |
| 20:09:51.546 | cleanUpAnythingRelatedModel | path: /tmp/workspace/680039 — 정상 cleanup |
| 21:15:48.734 | BaseService::runByMessage | id: 1012095 — SQS 재수신 (visibility timeout 만료) |
| 21:26:56.309 | getApiErrorToDeleteMessage — RESC10000 "Resource does not uploaded", modelId: 1012095 |
| 21:26:59.647 | handlingMessageErrors — 에러 처리 (SQS 메시지만 삭제, workspace cleanup 없음) |
| 21:27:00.204 | BaseService::runByMessage | id: 1012296 — capture 680042 job 실행 (stale workspace 680039 존재) |
Job 1012095의 재처리(21:15:48)에서 copySourceDir()가 EFS에서 /tmp/workspace/680039/로 파일을 복사했고, 21:26:59에 RESC10000 에러로 실패. handlingMessageErrors()가 호출되었지만 workspace cleanup은 수행하지 않음 — 에러 경로에 cleanUpAnythingRelatedModel() 호출이 없기 때문. 잔존한 workspace가 직후 job 1012296에 영향.
핵심 관찰:
- 연쇄 실패 시 모든 task가
count: 0/5로 재시도 없이 즉시 실패 — HTTP 403의statusCode가checkStatusCode()에서 비재시도로 분류 - 정상 phase의
createPanoRequest에서capture_id: 680039를 사용 — workspace 경로에서 파생된 잘못된 ID - API 서버 로그에서
cupixworks-api의 error-level 로그 0건 — 403은 정상적인 권한 거부 응답 cupixworks-apiwarn 로그 53건의Pano#_update_document: NotFound— Elasticsearch 인덱싱 지연 (직접 원인 아님)
Fix Recommendation#
즉시 조치 (Critical)#
-
에러 경로에서 workspace cleanup 추가 —
base-service.ts:290-313handlingMessageErrors()에cleanUpAnythingRelatedModel()호출 추가. 현재 에러 경로에서는 SQS 메시지 삭제만 수행하고 workspace 디렉토리를 삭제하지 않아, 실패한 job의 workspace가 동일 agent의 후속 job에 영향this._modelDirPath가 설정된 경우 (setModelWorkspace()호출 후 에러 발생 시) cleanup이 수행되어야 함
-
메타데이터 capture_id 검증 추가 —
cpcapture.ts:622-639CPCapture.fromMeta()에서 비디오 메타데이터의 임베딩된srvVideo.capture.id가 현재 job의 capture_id와 일치하는지 검증- 불일치 시 경고 로그 + 현재 job의 capture_id로 override하거나 해당 비디오 skip
-
job 시작 시 stale workspace 감지 —
postprocessor-service.ts:80-83createCPCaptureByJob()후setModelWorkspace()호출 전에,/tmp/workspace/하위에 현재 capture_id가 아닌 다른 디렉토리가 존재하면 경고 로그 출력 + 삭제- 이는 방어적 조치로, cleanup 누락이나 컨테이너 재사용에 의한 stale workspace 영향을 차단
-
HTTP 403 에러의 명확한 로깅 —
upload-new-panos.task.tsinit()에서 API 호출 실패 시error.statusCode와error.body를 명시적으로 로그하여url: undefined만으로는 알 수 없는 실제 원인 파악 가능하도록 개선
단기 개선 (1주 이내)#
-
checkTaskFail의 중복 콜백 호출 방지 —base.container.ts:47-53- 현재
_callbackFailed가 실패마다 반복 호출되어 Promise가 이미 reject된 후에도 계속 호출됨 - 최초 1회만 콜백을 호출하도록 guard 추가 (e.g.,
_failedCallbackCalled플래그)
- 현재
-
failTask의 전체 큐 중단 로직 검토 —transfer.manager.ts:158-160- 단일 task 실패 시
_stop = true로 전체 큐를 중단하는 것이 의도된 동작인지 검토 - 대량 배치에서 일부 실패가 전체 작업을 중단시키는 문제
- 단일 task 실패 시
장기 개선 (재발 방지)#
- SQS 멱등성 보장: job 1012095이 SQS visibility timeout 만료로 재수신되어 workspace를 재생성한 것이 근본 트리거. SQS 메시지 수신 시
processing_status체크(postprocessor-service.ts:68-70)가 이미 존재하지만, 재처리 시start_{action}_agent상태가 아닌 경우 skip하지 못함. job 상태 기반 멱등성 검증 강화 필요 - EFS 메타데이터 무결성 검증: preprocessor → postprocessor 간 전달되는
cpcapture.json에 capture_id 검증 체크섬 추가 - 임베딩된 capture 참조 제거:
CPVideoMeta에서 전체srvVideo.capture객체 대신capture_id만 참조하도록 경량화 - Agent workspace 완전 격리: workspace 경로를
/tmp/workspace/{capture_id}/대신/tmp/workspace/{job_id}/로 변경하여 서로 다른 job 간 파일 간섭을 원천 차단
Monitoring#
- 추가할 메트릭:
url: undefined실패 횟수를 별도로 추적하는 커스텀 로그 또는 메트릭 - Datadog 쿼리 예시:
service:cupixworks-capture-postprocessor-agent status:error "TransferManager::failTask" "url: undefined"
service:cupixworks-api status:error @http.status_code:403 "Capture not found" @usr.team_domain:*
checkTaskFail의 Failed 비율이 Total의 30%를 초과하면 알림 트리거 권장
Risk Assessment#
- Risk level: medium
- 예상 복잡도: standard —
cpcapture.ts의fromMeta()메타데이터 검증과file-system.manager.ts의 workspace 격리가 핵심. 다른 agent 패키지(preprocessor, 3d-reconstruction, room)에도 동일한 메타데이터 로딩 패턴이 존재하므로 일관된 수정 필요
Revision History#
Revision 1#
Feedback: upload_url 이 누락된 이유를 더 자세하게 조사좀
판정:
| 피드백 항목 | 판정 | 근거 |
|---|---|---|
| upload_url 누락 원인 상세 조사 | 수용 | 기존 분석은 "API가 upload_url 없이 응답을 반환"이라고만 기술하고 서버 측 원인을 특정하지 못했음. 재조사 결과: (1) PanoSerializer (pano_serializer.rb:110-116)에서 upload_url은 resource_state_name ∈ [:created, :uploading, :missing]일 때만 반환되며, (2) Aws::S3::Presigner (storagable/resource.rb:111-131)는 로컬 암호화 서명으로 S3 네트워크 호출 없음 — S3 rate limiting/IAM throttling 가설 기각. (3) Datadog API 로그에서 capture 680039에 대한 214건의 HTTP 403 확인 (Cupix::Errors::NotFound, code ARG10002), capture 680042에 대한 246건 전부 HTTP 200 확인. (4) 403 원인은 CaptureRepository#permission_joins (base_repository.rb:327-353)에서 tridentconstruction 사용자의 metconus capture 접근 차단. (5) 근본 원인은 CPVideo.fromMeta() (cpvideo.ts:108-124)가 이전 job의 메타데이터에 임베딩된 stale capture_id를 검증 없이 사용한 것. |
변경 사항:
- Root Cause Summary: "API가 upload_url 없이 응답" → "잘못된 capture_id(680039)로 API 호출 → HTTP 403 → upload_url 미생성"으로 근본 원인 교정
- Technical Analysis > Code Path: API 서버 측 upload_url 생성 경로 (PanoSerializer → Resourcable → Storagable → Aws::S3::Presigner), 권한 검사 경로 (CaptureRepository#permission_joins → HTTP 403), agent HTTP 403 처리 경로, 잘못된 capture_id 전파 경로 (CPVideo.fromMeta의 stale metadata) 4개 섹션 추가
- Log Evidence: cupixworks-api 측 403 에러 214건 및 정상 200 응답 로그 추가
- Fix Recommendation: "upload_url 누락 시 재시도"에서 "메타데이터 capture_id 검증 + workspace 격리 + HTTP 403 로깅"으로 핵심 수정 대상 교정. S3 rate limiting 관련 장기 개선 항목 제거
추가 조사 내용:
tesla레포 (/home/ec2-user/repos/tesla): PanoSerializer, CaptureRepository, Resourcable, Storagable, ClientErrorController 코드 분석cupixworks레포 (/home/ec2-user/repos/cupixworks): Tesla SDK panoApi.js의 HTTP 에러 핸들링, cupixRetriableRequest의 재시도 코드 목록, CPVideo.fromMeta() 메타데이터 역직렬화, FileSystemManager.loadCPCaptureModel() 분석- Datadog 로그: cupixworks-api의 capture 680039 (403 × 214건) 및 capture 680042 (200 × 246건) 검증, cupixworks-capture-postprocessor-agent의 failTask 로그 패턴 분석
Revision 2#
Feedback: workspace 가 cleanup 되지 않는 원인을 다시 찾아
판정:
| 피드백 항목 | 판정 | 근거 |
|---|---|---|
| workspace cleanup 실패 원인 재조사 | 수용 | 기존 분석은 "이전 metconus 작업이 남긴 것"이라고만 기술하고 cleanup이 왜 안 되었는지 코드 경로를 특정하지 못했음. 재조사 결과: (1) cleanUpAnythingRelatedModel() (base-service.ts:204-222)은 runByMessage()의 성공 경로(line 171)에서만 호출되며, 에러 경로의 handlingMessageErrors() (line 290-313)에서는 SQS 메시지 삭제만 수행하고 workspace cleanup을 호출하지 않음. (2) Datadog 로그에서 job 1012095이 20:03:37 최초 수신 → 20:09:51 workspace cleanup → 21:15:48 SQS 재수신 확인. 재수신 시 copySourceDir() (file-system.manager.ts:413-427)가 EFS에서 workspace를 재생성. (3) 재처리가 21:26:59에 RESC10000 에러로 실패 → handlingMessageErrors() 호출 → cleanup 미수행 → stale workspace 잔존 → 21:27:00에 job 1012296이 영향받음. |
변경 사항:
- Root Cause Summary: "이전 작업이 남긴 것"을 구체화 — SQS 재수신에 의한 workspace 재생성 + 에러 경로의 cleanup 누락이 stale workspace 잔존 원인임을 명시
- Technical Analysis > Code Path: 새 섹션 "5. Workspace Cleanup 실패 경로" 추가 —
cleanUpAnythingRelatedModel()이 성공 경로에서만 호출되는 코드 구조,handlingMessageErrors()의 cleanup 누락, SQS 재수신에 의한copySourceDir()재실행 경로 분석 - Log Evidence: workspace cleanup 타임라인 추가 — job 1012095의 최초 실행(20:03:37) → cleanup(20:09:51) → SQS 재수신(21:15:48) → RESC10000 에러(21:26:59) → job 1012296 실행(21:27:00) 시퀀스
- Fix Recommendation: "에러 경로에서 workspace cleanup 추가" (
base-service.ts:290-313)를 즉시 조치 #1으로 추가. "job 시작 시 stale workspace 감지" (postprocessor-service.ts:80-83)를 즉시 조치 #3으로 추가. 장기 개선에 "SQS 멱등성 보장"과 "workspace 경로를 job_id 기반으로 변경" 추가
추가 조사 내용:
cupixworks레포:BaseService(base-service.ts) 전체 job lifecycle 분석 —checkingQueue()→runByMessages()→runByMessage()→run()→cleanUpAnythingRelatedModel()성공 경로 및handlingMessageErrors()에러 경로 분석cupixworks레포:PostprocessorService(postprocessor-service.ts) —createCPCaptureByJob(),setModelWorkspace()호출 순서 분석cupixworks레포:FileSystemManager.copySourceDir()(file-system.manager.ts:413-445) — EFS에서 workspace로의 파일 복사 경로 분석cupixworks레포:CPUtils.deleteFolderRecursive()(cputils.ts:78-90) — 실제 workspace 삭제 구현 확인cupixworks레포:Constants(shared-config/src/constants.ts) —DefaultWorkspacePath = '/tmp/workspace',MaxCountWaitedToStopTask,CheckQueueInterval등 agent lifecycle 상수 확인- Datadog 로그:
cleanUpAnythingRelatedModel+680039→ 20:09:51 cleanup 1건 확인. job 1012095 로그 → 20:03:37 최초 수신, 21:15:48 재수신, 21:26:59 RESC10000 에러 확인.handlingMessageErrors로그 → modelId 1012095의 에러 처리 확인 (workspace cleanup 없음).runByMessage로그 → job 1012296이 21:27:00에 실행된 것 확인