MeshService::run | error: {"stack":"Error: Execution timeout after 28800000ms for message type: exec
RCA: MeshService Execution Timeout (28800000ms)
Overview#
What Happened#
2026-04-30에 cupixworks-any-mesh-agent 서비스에서 BIM 모델 mesh 추출 작업이 8시간 타임아웃(28800000ms)에 도달하여 2건의 에러가 발생했다. us-west-2와 eu-central-1 리전에서 각각 1건씩 발생했으며, child process가 SIGKILL로 강제 종료되었다.
Quick Facts#
| Field | Value |
|---|---|
| exception.class | Error |
| exception.message | Execution timeout after 28800000ms for message type: execute |
| top_frame | /tmp/agent/dist/app.cjs:1593 |
| runtime | Node.js (bundled CJS) |
| env | production, us-west-2 / eu-central-1 |
Affected Teams#
| Team / Domain | Error Count | Impact |
|---|---|---|
| qatest3 | 2 | BIM mesh 추출 실패, mesh_state가 error로 전환됨 |
Timeline#
- 2026-04-30 13:43:57 KST — BIM ID 19229 mesh 추출 시작 (us-west-2)
- 2026-04-30 13:54:27 KST — BIM ID 1291 mesh 추출 시작 (eu-central-1)
- 2026-04-30 21:43:59 KST — BIM 19229 타임아웃 발생 (8시간 경과), child process SIGKILL
- 2026-04-30 21:54:29 KST — BIM 1291 타임아웃 발생 (8시간 경과), child process SIGKILL
- 2026-04-30 21:54:29 KST — 두 작업 모두 mesh_state → error 전환 및 SQS 메시지 삭제
Error Log#
MeshService::run | error: {"stack":"Error: Execution timeout after 28800000ms for message type: execute
at Timeout._onTimeout (/tmp/agent/dist/app.cjs:1593:29)
at listOnTimeout (node:internal/timers:581:17)
at process.processTimers (node:internal/timers:519:7)","message":"Execution timeout after 28800000ms for message type: execute"}
Impact#
- Service:
cupixworks-any-mesh-agent - Team: qatest3
- 발생 횟수: 2
- 최초 발생: 2026-04-30T12:43:59.766Z
- 최근 발생: 2026-04-30T12:54:29.726Z
Root Cause Summary#
ChildProcessManager의 sendMessage 메서드에 설정된 실행 타임아웃(28800000ms = 8시간)이 만료되어 에러가 발생했다. BIM 모델의 Autodesk Forge mesh 추출 작업(forge_bimmodel_extractor)이 child process에서 8시간 내에 완료되지 못한 것이 직접적인 원인이다. 이는 특정 BIM 모델(ID 19229, 1291)의 크기가 매우 크거나 Forge API 응답이 지연되어 추출 작업이 비정상적으로 오래 걸린 것으로 판단된다. 타임아웃 자체는 설계된 안전장치이며 정상 동작이지만, 8시간이라는 타임아웃 값이 실제 처리 한계를 적절히 반영하는지 검토가 필요하다.
Technical Analysis#
Code Path#
- Entry point:
src/app.ts:76—MeshService인스턴스 생성 및init()호출 MeshService생성자에서MeshExtractManager를CPX_EXTRACTOR_TIMEOUT과 함께 초기화:
this._meshExtractManager = new MeshExtractManager({
stdioMode: 'pipe',
executeTimeoutMs: Environment.CPX_EXTRACTOR_TIMEOUT,
});
CPX_EXTRACTOR_TIMEOUT의 기본값은CupixMeshExtractorTimeOut = 28800000(8시간):
export const CupixMeshExtractorTimeOut = 28800000; // ms (8 hours)
environment.ts에서 환경변수로 override 가능:
export const CPX_EXTRACTOR_TIMEOUT = checkNumberArgv(argv.extractor_timeout) || checkNumberArgv(process.env['CPX_EXTRACTOR_TIMEOUT'] || Constants.CupixMeshExtractorTimeOut);
MeshService::run에서runMeshExtractor→meshExtractManager.execute()호출:
const meshExtractorResults = await this.meshExtractManager.execute({
apiConfig:{
clientId: Environment.ADF_CLIENT_ID,
clientSecret: Environment.ADF_CLIENT_SECRET
},
urn: cpBim.forgeUrn,
path: cpBim.meshDirPath,
timeOut: Environment.CPX_EXTRACTOR_TIMEOUT,
formatType: cpBim.forgeFormatType,
region: cpBim.forgeRegion
});
MeshExtractManager::execute가ChildProcessManager::execute를 호출:
const result = await this.childProcessManager.execute<MeshExtractorResults>('execute', params);
- Failure point —
ChildProcessManager::sendMessage에서 타임아웃 타이머가 발동:
if (timeoutMs && timeoutMs > 0) {
pending.timer = setTimeout(() => {
this.pendingMessages.delete(message.id);
const error = new Error(`Execution timeout after ${timeoutMs}ms for message type: ${message.type}`);
logger.error(`ChildProcessManager::sendMessage | ${error.message}`);
if (this.process && !this.process.killed) {
logger.warn('ChildProcessManager::sendMessage | Killing child process due to timeout');
this.process.kill('SIGKILL');
}
reject(error);
}, timeoutMs);
}
SIGKILL전송 후 child process가 종료되고,MeshService::run의 catch 블록에서 에러 로깅 및updateErrorState호출:
} catch (error) {
logger.error('MeshService::run | error: %s', JSON.stringify(error, Object.getOwnPropertyNames(error)));
await this.updateErrorState(cpBim);
}
기대 동작: mesh 추출이 8시간 이내에 완료되고, 결과 파일을 zip으로 아카이브하여 S3에 업로드.
실제 동작: child process의 forge_bimmodel_extractor가 8시간 동안 응답을 반환하지 않아 타임아웃 발동, child process SIGKILL, BIM mesh_state를 error로 업데이트.
Log Evidence#
사용한 Datadog 쿼리:
service:cupixworks-any-mesh-agent status:error "MeshService::run"
service:cupixworks-any-mesh-agent "19229"
service:cupixworks-any-mesh-agent "1291"
BIM 19229 (us-west-2) 타임라인:
2026-04-30 13:43:57 KST | info | BaseService::runByMessage | id: 19229
2026-04-30 21:43:59 KST | error | ChildProcessManager::sendMessage | Execution timeout after 28800000ms for message type: execute
2026-04-30 21:43:59 KST | error | MeshService::run | error: {"stack":"Error: Execution timeout after 28800000ms..."}
2026-04-30 21:43:59 KST | error | ChildProcessManager::setupEventHandlers | Child process exited
2026-04-30 21:43:59 KST | error | ChildProcessManager::setupEventHandlers | Child process closed
2026-04-30 21:44:00 KST | info | BaseService::cleanUpAnythingRelatedModel | path: /tmp/workspace/19229
BIM 1291 (eu-central-1) 타임라인:
2026-04-30 13:54:27 KST | info | BaseService::runByMessage | id: 1291
2026-04-30 21:54:29 KST | error | ChildProcessManager::sendMessage | Execution timeout after 28800000ms for message type: execute
2026-04-30 21:54:29 KST | error | MeshService::run | error: {"stack":"Error: Execution timeout after 28800000ms..."}
2026-04-30 21:54:29 KST | error | ChildProcessManager::setupEventHandlers | Child process exited
2026-04-30 21:54:29 KST | error | ChildProcessManager::setupEventHandlers | Child process closed
2026-04-30 21:54:29 KST | info | BaseService::cleanUpAnythingRelatedModel | path: /tmp/workspace/1291
2026-04-30 21:54:29 KST | info | AwsQueueManager::deleteMessage | end - message id: ed0c8e13-986f-42b8-a0d4-882c6a73b675
두 경우 모두 정확히 8시간(28800000ms) 후에 타임아웃이 발생했다. 동일 시간대에 BIM 19304가 정상적으로 처리(21:57~21:59 KST, 약 2분)된 것으로 보아, 서비스 자체의 문제가 아닌 특정 모델의 복잡도/크기 문제로 판단된다.
정상 처리 예시 (BIM 19304):
2026-04-30 21:57:46 KST | info | BaseService::runByMessage | id: 19304
2026-04-30 21:59:26 KST | info | CPBim::fromMeshExtractor | filepaths count: 16
2026-04-30 21:59:43 KST | info | AwsS3Manager::uploadFileStreamToS3 | begin
Hypotheses Considered#
| # | Hypothesis | Evidence for | Evidence against | Verdict |
|---|---|---|---|---|
| H1 | BIM 모델 크기/복잡도가 과도하여 Forge extractor가 8시간 내에 완료 불가 | 정확히 8시간에 타임아웃 발생 (두 건 모두); 동일 시간대 BIM 19304는 2분 만에 정상 완료; 서로 다른 리전(us-west-2, eu-central-1)에서 동시 발생 | child process 내부 로그가 없어 실제 추출 진행률 확인 불가 | Confirmed |
| H2 | Autodesk Forge API 장애로 인해 추출 요청이 hang | 두 리전에서 동시 발생; Forge API가 응답 없이 hang하면 타임아웃에 도달할 수 있음 | 동일 시간대 BIM 19304가 정상 처리됨 (Forge 인증 및 추출 완료); 두 실패 건은 약 10분 차이로 시작되어 동시 장애 가능성 낮음 | Rejected |
| H3 | 메모리 부족으로 child process가 응답 불능 상태 진입 | child process가 별도 프로세스로 분리된 구조 (메모리 격리 목적 명시); 대형 모델 처리 시 메모리 과다 사용 가능 | SIGKILL 후 정상 종료 로그 기록됨; OOM killer 흔적 없음 (killed by signal이 아닌 timeout에 의한 SIGKILL) | Inconclusive |
Fix Recommendation#
즉시 조치 (Critical)#
- 없음. 현재 에러 처리가 정상 동작하고 있으며 (타임아웃 → error state 전환 → cleanup), 시스템 안정성에 영향 없음.
qatest3팀에 BIM ID 19229, 1291의 모델 크기/복잡도 확인 요청. 해당 모델이 의도적 테스트인지 실제 프로덕션 데이터인지 확인 필요.
단기 개선 (1주 이내)#
ChildProcessManager::sendMessage의 타임아웃 로그 레벨을warn으로 하향 검토. 8시간 타임아웃은 설계된 안전장치이며, 모든 모델이 8시간 내에 완료될 보장이 없으므로error보다warn이 적절할 수 있음.- child process에 주기적 progress 보고 메커니즘 추가 검토 — 현재는 추출 시작과 완료/타임아웃만 로깅되어 중간 진행 상황 파악 불가.
장기 개선 (재발 방지)#
- 모델 크기/complexity에 기반한 동적 타임아웃 설정 검토. 현재 모든 모델에 동일한 8시간 타임아웃이 적용됨.
- 대형 모델에 대한 사전 검증(예: Forge manifest에서 파일 크기 확인)을 추가하여 8시간 내 처리 불가능한 모델을 사전에 거부하거나 더 큰 리소스로 라우팅하는 방안.
- Forge 추출 진행률을 child process에서 주기적으로 parent에 보고하는 heartbeat 메커니즘으로 hang 감지를 개선.
Monitoring#
- 추출 작업 소요 시간 분포 메트릭 수집:
mesh_extraction_duration_ms(히스토그램) - 타임아웃 발생 빈도 알림:
service:cupixworks-any-mesh-agent "Execution timeout after" status:error
- 특정 BIM 모델의 반복 타임아웃 감지 (동일 ID가 재시도에서도 타임아웃되는 경우 자동 skip 필요)
Risk Assessment#
- Risk level: low
- 예상 복잡도: trivial — 에러 처리가 정상 동작 중이며, BIM state가 error로 전환되어 후속 파이프라인에 영향 없음. 근본적으로는 특정 대형 모델의 처리 한계 문제.