AWS SQS TLS handshake failure — transient network degradation
RCA: AwsQueueManager::deleteMessage | end - socket hang up
Overview#
What Happened#
2026-07-18 18:15:59 KST 에 cupixworks-capture-postprocessor-agent 가 ap-southeast-2 리전 SQS 큐로 DeleteMessage 호출을 시도하다 AWS SDK 의 재시도 예산을 소진한 뒤 socket hang up 으로 최종 실패했다. 동일 시간대에 ap-southeast-2 SQS 엔드포인트 IP 로 향하는 ECONNRESET 이 반복적으로 관측되었고, 다음 메시지 사이클(약 13초 뒤)부터는 정상 회복되어 단발성 리전 네트워크 flap 로 판단된다. 영향은 SQS 메시지 1건 삭제 실패로, ApproximateReceiveCount 재수신을 통해 재시도되거나 MaxReceiveCount 도달 시 DLQ 로 이동한다.
Quick Facts#
| Field | Value |
|---|---|
| exception.class | socket hang up (Node.js http agent — AWS SDK v2 wrapped) |
| exception.message | `AwsQueueManager::deleteMessage |
| top_frame | packages/base/src/manager/aws-queue.manager.ts:99 |
| runtime | Node.js / aws-sdk v2 (AWS.SQS, apiVersion 2012-11-05) |
| env | production, ap-southeast-2 |
Affected Teams#
| Team / Domain | Error Count | Impact |
|---|---|---|
| scs-assetfuture / cupixworks-capture-postprocessor-agent | 1 | SQS delete 실패 1건. 메시지가 visibility timeout 후 재수신되어 postprocessing 이 중복 실행될 위험 (idempotency 로 완화) |
Timeline#
- 2026-07-18 18:14:33 KST — warn
connect ECONNRESET 3.27.177.65:443(ap-southeast-2 SQS 엔드포인트) 및BaseService::agentScaleOut | undefined queueAttributes(SQSgetQueueAttributes실패) - 2026-07-18 18:14:45 KST — warn
connect ECONNRESET 3.27.179.174:443(다른 SQS 엔드포인트 IP) - 2026-07-18 18:14:47 KST — warn
undefined queueAttributes재발 - 2026-07-18 18:15:24 KST — warn
socket hang up+undefined queueAttributes(SDK 내부 재시도 로그 누출) - 2026-07-18 18:15:59 KST — error
AwsQueueManager::deleteMessage | end - socket hang up(SDK 재시도 5회 소진 후 최종 실패, 콜백 rejection) - 2026-07-18 18:16:12 KST — info
AwsQueueManager::deleteMessage | begin/end정상 성공 (ap-southeast-2, message id7b1516a6-...) → 네트워크 이슈 자체 회복 - 2026-07-18 18:19:19 KST — error
BaseService::handlingMessageErrors | ... "error":"undefined response"(관련 후속 처리, 별도 메시지 5aa3710d-...)
Error Log#
AwsQueueManager::deleteMessage | end - socket hang up
Impact#
- Service:
cupixworks-capture-postprocessor-agent - Team: scs-assetfuture
- 발생 횟수: 1
- 최초 발생: 2026-07-18 18:15:59 KST
- 최근 발생: 2026-07-18 18:15:59 KST
Root Cause Summary#
ap-southeast-2 리전의 AWS SQS 엔드포인트 (sqs.ap-southeast-2.amazonaws.com, IP 3.27.177.65, 3.27.179.174) 로 향하는 TCP 연결이 약 1분 30초 동안 ECONNRESET / socket hang up 로 반복 실패했다. AwsQueueManager::deleteMessage 는 aws-sdk v2 의 내장 재시도(MaxRetries=5, RetryInterval=10000ms 기반 지수 backoff) 에 의존하는데, 이 시간 창 동안 재시도 예산이 모두 소진되어 SDK 콜백이 최종적으로 err.message === 'socket hang up' 로 실패했다. 동일 리전 SQS 호출이 이벤트 직후(18:16:12) 정상 회복된 점, 그리고 최근 14일 동안 동일 서비스에서 같은 메시지가 단 1건만 발생한 점으로 볼 때 코드 결함이 아닌 리전 네트워크 flap 이 root cause 다.
Technical Analysis#
Code Path#
- Entry point:
packages/base/src/base-service.ts:224(deleteByMessage—@trace('delete-message')로 감싸진 얇은 wrapper) - 실제 호출:
packages/base/src/manager/aws-queue.manager.ts:77(deleteMessage— Promise 로 감싼sqs.deleteMessage콜백) - Failure point:
packages/base/src/manager/aws-queue.manager.ts:99— 콜백이err.message = 'socket hang up'을 받고reject(err) - 상위 catch:
packages/base/src/base-service.ts:107-111(checkingQueue의try/catch→handlingMessageErrors)
deleteMessage = (message: AWS.SQS.Message): Promise<void> => new Promise((resolve, reject) => {
if (this.debugMode) return resolve();
const queueUrl = this.queueUrl;
logger.info('AwsQueueManager::deleteMessage | begin - queue url: %s', queueUrl);
if (queueUrl == undefined) {
logger.error('AwsQueueManager::deleteMessage | end - undefined queueUrl');
return reject();
}
const messageReceiptHandle = message && message.ReceiptHandle;
if (messageReceiptHandle == undefined) {
logger.error('AwsQueueManager::deleteMessage | end - undefined messageReceiptHandle');
return reject();
}
const params: AWS.SQS.DeleteMessageRequest = {
QueueUrl: queueUrl,
ReceiptHandle: messageReceiptHandle
};
this.sqs.deleteMessage(params, (err: AWS.AWSError) => {
if (err) {
logger.error('AwsQueueManager::deleteMessage | end - %s', err.message);
reject(err);
} else {
logger.info('AwsQueueManager::deleteMessage | end - message id: %s', message.MessageId);
resolve();
}
});
});
SDK 재시도 설정:
this._sqs = new AWS.SQS({
apiVersion: '2012-11-05',
maxRetries: Constants.MaxRetries,
retryDelayOptions: {base: Constants.RetryInterval}
});
export const MaxRetries = 5;
export const RetryInterval = 10000; // ms
기대 동작: 일시적 네트워크 오류는 aws-sdk v2 가 자체 재시도(최대 5회, base 10초 지수 backoff)로 흡수해야 한다. 5회 재시도 후에도 회복되지 못하면 caller 가 실패를 인지한다.
실제 동작: ECONNRESET/socket hang up 이 최소 18:14:33 ~ 18:15:59 (약 86초) 동안 지속되어 SDK 재시도 예산을 초과했다. 콜백은 err.message = 'socket hang up' 으로 최종 실패했고, AwsQueueManager::deleteMessage | end - socket hang up 이 error 로 기록되었다. 12초 뒤(18:16:12) 동일 큐 URL 로 delete 가 정상 성공한 것으로 보아 원인은 서비스 코드가 아닌 리전 네트워크 flap 이다.
Log Evidence#
Datadog query 1 (클러스터 원본):
service:cupixworks-capture-postprocessor-agent status:error @environment:production "AwsQueueManager::deleteMessage"
Datadog query 2 (주변 컨텍스트, 4분 창):
service:cupixworks-capture-postprocessor-agent @environment:production
from: 2026-07-18T09:14:00Z, to: 2026-07-18T09:18:00Z
핵심 로그 (KST):
2026-07-18 18:14:33 warn connect ECONNRESET 3.27.177.65:443
2026-07-18 18:14:33 warn BaseService::agentScaleOut | undefined queueAttributes
2026-07-18 18:14:45 warn connect ECONNRESET 3.27.179.174:443
2026-07-18 18:14:47 warn BaseService::agentScaleOut | undefined queueAttributes
2026-07-18 18:15:24 warn socket hang up
2026-07-18 18:15:24 warn BaseService::agentScaleOut | undefined queueAttributes
2026-07-18 18:15:59 error AwsQueueManager::deleteMessage | end - socket hang up
2026-07-18 18:16:12 info AwsQueueManager::deleteMessage | begin - queue url: https://sqs.ap-southeast-2.amazonaws.com/002596530511/cupix-capture-postprocessor-agent-production
2026-07-18 18:16:12 info AwsQueueManager::deleteMessage | end - message id: 7b1516a6-fe2b-4bc3-ad77-06a3c82ecdaf
- IP
3.27.177.65,3.27.179.174은sqs.ap-southeast-2.amazonaws.com의 AWS 소유 대역이다. - 클러스터 frontmatter
regions: [ap-southeast-2]와 일치. 다른 리전(us-west-2) 트래픽은 같은 시간대 정상. - 14일 창에서 이 에러 문자열은 총 1건만 발생 (
service:cupixworks-capture-postprocessor-agent status:error "socket hang up"쿼리 결과).
관련 이전 인시던트 (status board):
2026-07-13-svc-cupixworks-capture-postprocessor-agent--unknown-1— 2026-07-13 18:53 ~ 18:57 UTC, 같은 서비스에서 짧게 회복된 degradation 발생 (별도 클러스터 2건). 이번 건과 동일한 flap 계열일 가능성 있으나 별도 지표로 상관관계 확정은 불가 — needs verification.
Hypotheses Considered#
| # | Hypothesis | Evidence for | Evidence against | Verdict |
|---|---|---|---|---|
| H1 | ap-southeast-2 리전 AWS SQS 네트워크 flap 으로 인한 일시적 연결 실패, SDK 재시도 예산 초과 | ECONNRESET 3.27.177.65:443 / 3.27.179.174:443 (SQS 리전 IP) 18:14:33~18:14:45, socket hang up 18:15:24 warn, 18:15:59 error, 12초 뒤 동일 큐 delete 정상 성공, 14일 창 유일 발생, regions: [ap-southeast-2] |
— | Confirmed |
| H2 | queueUrl 또는 ReceiptHandle 이 undefined 로 넘어와 조기 reject |
aws-queue.manager.ts:82-91 에서 그 경로는 각각 undefined queueUrl / undefined messageReceiptHandle 로그를 남김. 실제 로그는 socket hang up (SDK 콜백 err.message) 이라 다름 |
로그 문자열 자체가 그 분기가 아님을 증명 | Rejected |
| H3 | Receipt handle 만료(visibility timeout 초과) 후 SDK 가 ReceiptHandleIsInvalid 반환 |
이론적으로 가능 | AWS 는 이 경우 HTTP 400 + InvalidParameterValue/ReceiptHandleIsInvalid 를 반환하지 socket hang up (전송 계층 에러) 을 반환하지 않음. 또한 QueueVisibilityTimeout = 600s 로 여유가 큼 |
Rejected |
| H4 | 코드 결함 — 재시도 로직 부재로 인한 반복 실패 | — | aws-sdk v2 의 maxRetries=5, retryDelayOptions.base=10000 이 명시적으로 설정되어 있음 (aws-queue.manager.ts:17-21). 재시도가 이미 5회 수행된 후 실패한 것 |
Rejected |
| H5 | 다른 downstream 서비스(예: tesla API) 장애의 파생 | 같은 서비스에서 18:14:33/45 ECONNRESET 이 tesla API 가 아닌 SQS IP 대상 |
IP 대역이 AWS SQS 리전 IP 로 명확히 매핑됨. Tesla API 관련 504 는 별건(18:12:31)이며 시각이 다름 | Rejected |
Fix Recommendation#
즉시 조치 (Critical)#
없음. 이번 이벤트는 AWS 리전 네트워크의 일시적 flap 이며 서비스 코드 결함이 아니다. SDK 자체 재시도가 이미 5회 수행된 후 실패했고, 12초 후 동일 큐 delete 가 성공했으므로 즉시 배포/재기동이 필요한 상황이 아니다. 실패한 메시지는 SQS visibility timeout 만료 후 재수신되어 재처리되거나 MaxReceiveCount 도달 시 DLQ 로 이동한다.
단기 개선 (1주 이내)#
- 로그 severity 정합성 검토 —
packages/base/src/manager/aws-queue.manager.ts:99의logger.error(...)는 SDK 재시도가 모두 소진된 최종 실패에서만 호출되지만,socket hang up같은 transient network 실패도 error 로 남는다.err.code(예:NetworkingError,TimeoutError,ECONNRESET) 를 확인해 transient 계열은warn으로 다운그레이드하고 real error 만error로 남기는 방안을 고려. 방향만 제시, 코드 변경은 요구되지 않음 — 다른 서비스와의 로깅 컨벤션 확인 필요. - DeleteMessage 실패의 caller-level 처리 재확인 —
BaseService::checkingQueue(base-service.ts:107-111) 가 error 를 잡아handlingMessageErrors로 넘긴다.handlingMessageErrors는getApiErrorToDeleteMessage로 nodejs system error (err.errno && err.code && err.syscall) 를 감지해warn만 남기고 종료한다 (base-service.ts:245-248). 이번 케이스가 그 분기에 정확히 걸리는지 별도 로그로 확인 필요 — needs verification.
장기 개선 (재발 방지)#
ap-southeast-2리전 SQS 엔드포인트에 대한 별도 헬스체크/가용성 대시보드 도입. 이번처럼 SDK 자체 재시도 안에 flap 이 흡수되지 못하는 경우에 대비.AwsQueueManager의deleteMessage/getQueueAttributes/receiveMessage세 경로에서 발생하는NetworkingError를 카운터로 집계해 리전 flap 을 조기 감지.
Monitoring#
writing-datadog-monitoring-queries 가이드에 따라 timeseries widget 에 그대로 넣을 수 있는 문법으로 작성.
Rate of deleteMessage errors (서비스/리전별):
sum:datadog.estimated_usage.logs.ingested_events{service:cupixworks-capture-postprocessor-agent,status:error,@message:"AwsQueueManager::deleteMessage*"}.as_count()
간단히 로그 count 로 대체하려면 (Datadog Log Explorer analytics query 를 timeseries 로 사용):
logs("service:cupixworks-capture-postprocessor-agent status:error \"AwsQueueManager::deleteMessage\"").index("*").rollup("count").by("region")
Rate of transient network warnings (조기 감지):
logs("service:cupixworks-capture-postprocessor-agent status:warn (\"ECONNRESET\" OR \"socket hang up\")").index("*").rollup("count").by("region")
임계값 제안: 5분 창에 위 warn 카운트가 3회 이상이면 리전 flap 의심 알림.
Risk Assessment#
- Risk level: low — 단발성 발생(14일 창에 1건), 자체 회복, SQS 재수신으로 데이터 손실 없음.
- 예상 복잡도: trivial — 코드 변경 불필요. 필요시 로그 severity 조정 정도의 소폭 개선만 검토.