forge_bimmodel_extractor process() blocked on Forge API call — model-specific hang
RCA: ChildProcessManager::sendMessage | Execution timeout after 28800000ms for message type: execute
Overview#
What Happened#
2026-04-30에 cupixworks-any-mesh-agent 서비스에서 BIM 모델 mesh 추출 작업 2건이 8시간(28800000ms) 실행 제한 시간을 초과하여 timeout 에러가 발생했다. BIM ID 19229 (us-west-2)와 BIM ID 1291 (eu-central-1)이 영향을 받았으며, 동일 시간대 다른 BIM 작업들은 수 분 내에 정상 완료되었다.
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 |
| env | production, us-west-2 / eu-central-1 |
Affected Teams#
| Team / Domain | Error Count | Impact |
|---|---|---|
| qatest3 | 2 | BIM 모델 2건의 mesh 추출 실패, mesh_state가 error로 전환됨 |
Timeline#
- 2026-04-30 13:43:57 KST — BIM 19229 mesh 추출 작업 시작 (us-west-2 SQS 큐)
- 2026-04-30 13:54:27 KST — BIM 1291 mesh 추출 작업 시작 (eu-central-1 SQS 큐)
- 2026-04-30 21:43:59 KST — BIM 19229 timeout 발생 (8시간 경과), child process SIGKILL
- 2026-04-30 21:54:29 KST — BIM 1291 timeout 발생 (8시간 경과), child process SIGKILL
- 2026-04-30 21:54:29 KST — 양쪽 모두 cleanup 후 SQS 메시지 삭제 완료
Error Log#
ChildProcessManager::sendMessage | Execution timeout after 28800000ms for message type: execute
Impact#
- Service:
cupixworks-any-mesh-agent - Team: qatest3
- 발생 횟수: 2
- 최초 발생: 2026-04-30T12:43:59.764Z
- 최근 발생: 2026-04-30T12:54:29.724Z
Root Cause Summary#
forge_bimmodel_extractor의 process() 메서드가 동기적(synchronous)으로 실행되는 C++ 네이티브 바인딩인데, 특정 BIM 모델(ID 19229, 1291)에 대해 Autodesk Forge API 호출 또는 mesh 데이터 처리 중 무한 대기(hang) 상태에 빠졌다. ChildProcessManager는 executeTimeoutMs(8시간 = 28800000ms) 타이머를 설정하여 이 상황을 감지하고 child process를 SIGKILL로 강제 종료했다. 근본 원인은 child process 내부의 extractBIMModel.process() 호출이 반환되지 않은 것이며, 이는 해당 BIM 모델의 Forge URN에 대한 다운로드/파싱 과정에서 네이티브 코드가 블로킹된 것으로 추정된다. 동일 시간대에 10건 이상의 다른 BIM 모델이 수 분 내에 정상 추출 완료된 점으로 볼 때, 모델 특이적 문제이다.
Technical Analysis#
Code Path#
- Entry point:
mesh-service.ts:101—MeshService.run(targetId)가 SQS 메시지에서 BIM ID를 받아 처리 시작 mesh-service.ts:112—this.runMeshExtractor(cpBim)호출mesh-service.ts:184—this.meshExtractManager.execute(params)호출,timeOut: Environment.CPX_EXTRACTOR_TIMEOUT전달
this._meshExtractManager = new MeshExtractManager({
stdioMode: 'pipe',
executeTimeoutMs: Environment.CPX_EXTRACTOR_TIMEOUT,
});
mesh-extract.manager.ts:70—this.childProcessManager.execute<MeshExtractorResults>('execute', params)호출child-process.manager.ts:186-198—execute()메서드에서effectiveTimeout을this.options.executeTimeoutMs에서 가져옴
async execute<T = unknown>(type: string, data?: unknown, timeoutMs?: number): Promise<T> {
if (!this.isRunning) {
await this.start();
}
const message: Message = {
id: randomUUID(),
type,
data
};
const effectiveTimeout = timeoutMs ?? this.options.executeTimeoutMs;
return this.sendMessage(message, effectiveTimeout);
}
child-process.manager.ts:213-225—sendMessage()에서setTimeout으로 timeout 타이머 설정, timeout 시 child process를 SIGKILL로 종료
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);
}
- Failure point:
mesh-extractor.process.ts:138— child process 내extractBIMModel.process()동기 호출이 반환되지 않음
const extractBIMModel = new BIM_MODEL_EXTRACTOR.extract_bimmodel();
const envName = CPX_ENVIRONMENT_NAME?.toLowerCase();
this.log(`MeshExtractorProcess::execute - Environment: ${envName}`);
extractBIMModel.setServer(envName);
extractBIMModel.setModelUrn(params.urn);
extractBIMModel.setOutputDirpath(params.path);
const result = extractBIMModel.process();
this.log(`MeshExtractorProcess::execute - process() result: ${result} (${typeof result})`);
if (result === true) {
const fileList = await CPUtils.getFiles(params.path);
this.log(`MeshExtractorProcess::execute - extracted ${fileList.length} files: ${JSON.stringify(fileList)}`);
extract = {
filepaths: fileList
};
} else {
this.log(`MeshExtractorProcess::execute - extraction failed, result: ${result}`);
throw new Error(`forge_bimmodel_extractor failed to extract mesh, process() returned: ${result}`);
}
- Timeout 값은
constants.ts:6에서 하드코딩:
export const CupixMeshExtractorTimeOut = 28800000; // ms (8 hours)
기대 동작: extractBIMModel.process()가 mesh 데이터를 추출하고 true/false를 반환해야 한다. 정상적인 경우 1~3분 내에 완료된다 (동일 시간대 다른 작업들은 runByMessage 후 수 분 내에 fromMeshExtractor | filepaths count: 16이 로깅됨).
실제 동작: 특정 BIM 모델에 대해 process() 메서드가 반환되지 않고 8시간 동안 블로킹됨. ChildProcessManager의 timeout 타이머가 만료되어 SIGKILL로 child process를 강제 종료함.
Log Evidence#
사용한 Datadog 쿼리:
service:cupixworks-any-mesh-agent (19229 OR 1291)
BIM 19229 타임라인:
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 | warn | ChildProcessManager::sendMessage | Killing child process due to timeout
2026-04-30 21:43:59 KST | error | MeshService::run | error: {"stack":"Error: Execution timeout after 28800000ms for message type: execute\n at Timeout._onTimeout (/tmp/agent/dist/app.cjs:1593:29)...","message":"Execution timeout after 28800000ms for message type: execute"}
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
2026-04-30 21:44:00 KST | info | AwsQueueManager::deleteMessage | begin - queue url: https://sqs.us-west-2.amazonaws.com/002596530511/cupix-tesla-mesh-agent-production
BIM 1291 타임라인:
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 | warn | ChildProcessManager::sendMessage | Killing child process due to timeout
2026-04-30 21:54:29 KST | error | MeshService::run | error: {"stack":"Error: Execution timeout after 28800000ms for message type: execute..."}
2026-04-30 21:54:29 KST | info | BaseService::cleanUpAnythingRelatedModel | path: /tmp/workspace/1291
2026-04-30 21:54:29 KST | info | AwsQueueManager::deleteMessage | begin - queue url: https://sqs.eu-central-1.amazonaws.com/002596530511/cupix-tesla-mesh-agent-production
정상 완료된 작업 비교 (동일 시간대):
service:cupixworks-any-mesh-agent "fromMeshExtractor"
2026-04-30 13:42:35 KST | info | CPBim::fromMeshExtractor | filepaths count: 16
2026-04-30 13:43:53 KST | info | CPBim::fromMeshExtractor | filepaths count: 20
2026-04-30 13:43:55 KST | info | CPBim::fromMeshExtractor | filepaths count: 16
2026-04-30 13:44:01 KST | info | CPBim::fromMeshExtractor | filepaths count: 16
2026-04-30 13:44:09 KST | info | CPBim::fromMeshExtractor | filepaths count: 16
14일간 전체 Execution timeout 에러:
service:cupixworks-any-mesh-agent status:error "Execution timeout"
14일 내 발생 건수: 이 2건의 에러만 존재 (BIM 19229, 1291). 이전에는 동일 패턴 없음.
Hypotheses Considered#
| # | Hypothesis | Evidence for | Evidence against | Verdict |
|---|---|---|---|---|
| H1 | 특정 BIM 모델의 Forge URN이 대용량이거나 비정상적 구조여서 forge_bimmodel_extractor C++ 네이티브 코드가 무한 대기 |
동일 시간대 다른 BIM 작업들은 1-3분 내 정상 완료. BIM 19229, 1291만 8시간 동안 응답 없이 hang. fromMeshExtractor 로그가 없음. |
child process 내부 로그가 없어 정확한 hang 지점 확인 불가 (native code) | Confirmed |
| H2 | Autodesk Forge API 전체 장애로 인한 타임아웃 | 두 건 모두 같은 날 발생 | 동일 시간대(13:41~13:45 KST)에 시작된 다른 BIM 작업 10건 이상이 정상 완료됨. us-west-2와 eu-central-1 양쪽 리전에서 발생하여 Forge API 리전 장애도 아님 | Rejected |
| H3 | child process 메모리 부족(OOM)으로 인한 hang | stdioMode: 'pipe'로 설정되어 있어 메모리 이슈 가능성 존재 |
OOM이면 OS가 kill하며 Child process exited 로그가 즉시 발생해야 하나, 실제로는 8시간 후 timeout에 의한 SIGKILL로 종료됨 |
Rejected |
| H4 | 네트워크 파티션/DNS 이슈로 Forge API 연결 hang | C++ 네이티브 코드가 내부적으로 HTTP 요청 시 무한 대기할 수 있음 | 모델 특이적 패턴과 일치하며, Forge API 자체의 문제보다는 특정 모델 처리 시 네이티브 코드의 동작이 원인 | Inconclusive |
Fix Recommendation#
즉시 조치 (Critical)#
constants.ts:6의CupixMeshExtractorTimeOut을 8시간에서 더 합리적인 값(예: 1-2시간)으로 줄이는 것을 검토. 정상 작업이 수 분 내에 완료되므로 8시간은 과도한 timeout.- 해당 BIM 모델(ID 19229, 1291)의 상태를 확인하고, 필요 시 mesh_state를 수동으로 리셋하여 재처리 또는 수동 검증.
단기 개선 (1주 이내)#
mesh-extractor.process.ts에서extractBIMModel.process()호출 전후로 시작 시각과 BIM URN을 info 레벨로 로깅하여, 어떤 모델에서 long-running 상태가 발생하는지 추적 가능하도록 개선.- child process 내부에서 자체적인 timeout 메커니즘 도입 검토 (예:
process()호출을 별도 worker thread에서 실행하고 AbortSignal 등으로 제어).
장기 개선 (재발 방지)#
forge_bimmodel_extractorC++ 네이티브 모듈에 내부 timeout 파라미터를 추가하여, 네이티브 레벨에서 HTTP 요청이나 데이터 처리에 대한 개별 timeout을 설정할 수 있도록 개선.extractBIMModel.process()가 동기적으로 블로킹하는 대신 비동기 인터페이스(callback 또는 Promise)를 제공하도록 네이티브 모듈 업데이트 검토.- 대용량/비정상 BIM 모델에 대한 사전 검증 로직 추가 (예: Forge 모델 메타데이터에서 크기/복잡도를 확인하고 임계치 초과 시 거부).
Monitoring#
- timeout 발생 시 즉시 알림을 받을 수 있도록 Datadog monitor 추가:
service:cupixworks-any-mesh-agent status:error "Execution timeout"
- mesh 추출 소요 시간을 추적하는 커스텀 메트릭 도입 검토 (start ~
fromMeshExtractor간 시간 차이) forge_bimmodel_extractor.process()실행 시간이 30분을 초과하면 warn 로그를 남기는 중간 체크포인트 추가 검토
Risk Assessment#
- Risk level: low
- 예상 복잡도: standard
- 14일 내 2건만 발생한 저빈도 이벤트. 정상적인 error handling flow가 동작하여 BIM mesh_state를 error로 업데이트하고 SQS 메시지를 삭제했으므로, 시스템 안정성에 대한 영향은 제한적. 다만 8시간 동안 agent 리소스를 점유하는 것은 비효율적이며, timeout 값 조정이 권장됨.