ES /docs

QMAws::runTask | error occurred during run ecs task - {

RCA: QMAws::runTask | ThrottlingException: Rate exceeded

Error Log#

Datadog Logs

text
QMAws::runTask | error occurred during run ecs task - {
  name: 'ThrottlingException',
  message: 'Rate exceeded',
  stack: 'ThrottlingException: Rate exceeded
    at Request.extractError (/tmp/agent/dist/node_modules/aws-sdk/lib/protocol/json.js:80:27)
    at Request.callListeners (/tmp/agent/dist/node_modules/aws-sdk/lib/sequential_executor.js:106:20)
    ...'
}

Impact#

  • Service: cupixworks-any-compute-agent
  • Team: arthtech
  • 발생 횟수: 40
  • 최초 발생: 2026-04-06T08:26:36.918Z
  • 최근 발생: 2026-04-07T10:00:43.675Z

Root Cause Summary#

cupixworks-any-compute-agentQMAws 클래스가 AWS ECS API를 호출할 때, AWS SDK 클라이언트에 maxRetriesretryDelayOptions를 설정하지 않아 SDK 기본 retry 정책(짧은 간격, exponential backoff 미적용)이 사용됩니다. 동시에, JobManager::checkingQueue가 SQS에서 수신한 메시지를 500ms 간격으로 순차 처리하면서 다수의 ECS listContainerInstances, describeContainerInstances, startTask API 호출을 짧은 시간에 집중 발생시킵니다. 여러 job이 동시에 대기 중일 때 1분 내에 17건 이상의 runTask begin 호출이 발생하여 AWS ECS API rate limit을 초과하고, ThrottlingException: Rate exceeded 에러가 발생합니다.

Technical Analysis#

Code Path#

  • Entry point: job.manager.ts:37checkingQueue 메서드가 SQS 메시지 수신 후 job 실행
  • job.manager.ts:72-77runJobs가 job 목록을 순차 실행하되 API 호출 간 rate limiting 없음
  • job.manager.ts:99_qmAws.runTask() 호출
  • qmAws.ts:117-168runTask 메서드 내에서 listContainerInstancesdescribeContainerInstancesstartTask 순서로 ECS API 3회 연속 호출
  • Failure point: qmAws.ts:164-167 — ECS API 호출 중 ThrottlingException 발생 시 catch 블록에서 에러 로깅 후 빈 배열 반환
typescript
// packages/cupix-tesla-compute-agent/src/model/qmAws.ts:6-23
export class QMAws {
	constructor(
		readonly awsRegion: string,
		readonly queueName: string
	) {
		AWS.config.update({ region: awsRegion });
		this._sqs = new AWS.SQS({ apiVersion: '2012-11-05' });
		this._ecs = new AWS.ECS({ apiVersion: '2014-11-13' });  // maxRetries 미설정
		this._autoScaling = new AWS.AutoScaling({ apiVersion: '2011-01-01' });
	}

비교: AwsEcsManager(base 패키지)는 올바르게 설정되어 있음:

typescript
// packages/base/src/manager/aws-ecs.manager.ts:21-25
this._ecs = new AWS.ECS({
	apiVersion: '2014-11-13',
	maxRetries: Constants.MaxRetries,          // 5회
	retryDelayOptions: {base: Constants.RetryInterval}  // 10000ms
});

JobManager::checkingQueue는 메시지가 있으면 500ms sleep 후 즉시 재귀 호출하여, 대기 중인 job이 많을 때 API 호출이 폭주합니다:

typescript
// packages/cupix-tesla-compute-agent/src/manager/job.manager.ts:37-50
private checkingQueue = async (_gmAws: QMAws) => {
	const messages = await _gmAws.receiveMessage();
	if (messages.length > 0) {
		const _jobList = this.createJobFromMessages(messages);
		await this.runJobs(_jobList, _gmAws);
		await CPUtils.sleep(500);           // 500ms만 대기 후 즉시 다음 batch
		await this.checkingQueue(_gmAws);   // 재귀 호출
	} else {
		// 메시지 없을 때만 10초 interval
		_gmAws.intervalTimer = setTimeout(() => {
			this.checkingQueue(_gmAws);
		}, Constants.CheckQueueInterval);
	}
};

runTask 메서드는 한 번의 호출에서 최대 3개의 ECS API를 순차 호출합니다:

typescript
// packages/cupix-tesla-compute-agent/src/model/qmAws.ts:117-168
runTask = async (awsClusterName: string, job: QMJob, instanceType: string) => {
	try {
		const containerInstanceArns = await this.listContainerInstances(awsClusterName, instanceType);  // API 1
		// ...
		const containerInstances = await this.describeContainerInstances(awsClusterName, containerInstanceArns);  // API 2
		for await (const containerInstance of containerInstances) {
			// ...
			tasks = await this.startTask(awsClusterName, containerInstance.containerInstanceArn, job);  // API 3 (반복)
		}
	} catch (error) {
		logger.error('QMAws::runTask | error occurred during run ecs task - %s', error);  // 여기서 에러 발생
		return [];
	}
};

Log Evidence#

사용한 Datadog 쿼리:

text
service:cupixworks-any-compute-agent status:error "ThrottlingException"
text
service:cupixworks-any-compute-agent "runTask" "begin"

에러 버스트 패턴 (2026-04-07 18:08 KST / 09:08 UTC)

1분 내에 동일 job들이 반복적으로 runTask를 시도하며 ThrottlingException 발생:

text
18:08:17 KST  QMAws::runTask | begin - job id: 5835, task def: cupix-capture-refinement-production-arm, instance_type: m7g.8xlarge, launch_mode: CUPIXWORKS
18:08:18 KST  QMAws::runTask | begin - job id: 5836, ...
18:08:19 KST  QMAws::runTask | begin - job id: 5837, ...
18:08:20 KST  QMAws::runTask | begin - job id: 5838, ...
18:08:20 KST  QMAws::runTask | begin - job id: 174389, task def: cupix-pano-postprocessor-production, instance_type: g6.2xlarge
18:08:21 KST  QMAws::runTask | begin - job id: 174390, task def: cupix-pano-postprocessor-production, instance_type: g6.2xlarge
18:08:21 KST  QMAws::runTask | begin - job id: 5839, ...
--- ThrottlingException errors ---
18:08:18 KST  QMAws::runTask | error occurred during run ecs task - { name: 'ThrottlingException', message: 'Rate exceeded' }
18:08:22 KST  QMAws::runTask | error occurred during run ecs task - { name: 'ThrottlingException', message: 'Rate exceeded' }
18:08:33 KST  QMAws::runTask | error occurred during run ecs task - { name: 'ThrottlingException', message: 'Rate exceeded' }
18:08:36 KST  QMAws::runTask | error occurred during run ecs task - { name: 'ThrottlingException', message: 'Rate exceeded' }
--- 실패한 job들이 재시도 ---
18:08:32 KST  QMAws::runTask | begin - job id: 5836, ... (2nd attempt)
18:08:33 KST  QMAws::runTask | begin - job id: 5837, ... (2nd attempt)
18:08:34 KST  QMAws::runTask | begin - job id: 5838, ... (2nd attempt)
18:08:35 KST  QMAws::runTask | begin - job id: 5835, ... (2nd attempt)
18:08:36 KST  QMAws::runTask | begin - job id: 5839, ... (2nd attempt)

7개 job이 4초 내에 시작되어 각각 최소 3개의 ECS API(listContainerInstances, describeContainerInstances, startTask)를 호출하므로, 4초 동안 ~21개 이상의 ECS API 호출이 발생합니다. ThrottlingException 후 재시도가 이어지면서 추가 API 호출이 누적됩니다.

Retry 로그 (SDK 기본 retry 또는 application-level retry):

text
2026-04-07T10:09:28.865Z  Attempt 1: Waiting 1000 ms before retrying...
2026-04-07T10:15:09.550Z  Attempt 1: Waiting 1000 ms before retrying...
2026-04-07T10:19:04.876Z  Retrying in 100ms...
2026-04-07T10:20:59.767Z  Retrying in 100ms...

100ms~1000ms의 짧은 retry 간격은 throttling 상황을 악화시킵니다.

3개 SQS 큐 동시 폴링: JobManager는 3개의 QMAws 인스턴스(기본, ARM, GPU)를 생성하여 동시에 큐를 폴링합니다 (job.manager.ts:14-17). 세 큐에 동시에 메시지가 있으면 ECS API 호출량이 3배로 증가합니다.

Fix Recommendation#

즉시 조치 (Critical)#

  • packages/cupix-tesla-compute-agent/src/model/qmAws.ts:21AWS.ECS 생성자에 maxRetriesretryDelayOptions를 추가하여 base 패키지의 AwsEcsManager와 동일한 설정 적용. maxRetries: 5, retryDelayOptions: { base: 10000 } (shared-config의 MaxRetries, RetryInterval 상수 사용).

단기 개선 (1주 이내)#

  • job.manager.ts:72-77runJobs 메서드에서 각 job 실행 사이에 최소 1-2초의 delay를 추가하거나, token bucket 패턴으로 ECS API 호출 속도를 제한.
  • job.manager.ts:42checkingQueue의 재귀 호출 전 sleep을 500ms에서 2-3초로 증가시켜 burst 완화.
  • qmAws.ts:117runTask 메서드에 ThrottlingException 감지 시 exponential backoff를 적용한 application-level retry 로직 추가.

장기 개선 (재발 방지)#

  • QMAws 클래스를 base 패키지의 AwsEcsManager 패턴으로 리팩토링하여 AWS SDK 설정을 일관되게 관리. 현재 compute-agent만 독자적인 QMAws 클래스를 사용하고 있어 설정 불일치가 발생.
  • ECS API 호출에 대한 centralized rate limiter 도입 (예: p-throttle 또는 bottleneck 라이브러리). 3개 큐의 호출을 하나의 rate limiter로 통합.
  • 대량 job 처리 시 ECS RunTask의 count 파라미터를 활용하여 단일 API 호출로 여러 task를 시작하는 방식으로 전환 (현재 startTask는 job당 1개 task만 시작).

Monitoring#

  • ECS API ThrottlingException 발생 빈도 추적:
text
service:cupixworks-any-compute-agent status:error "ThrottlingException"
  • runTask 호출 빈도 모니터링 (분당 호출 수):
text
service:cupixworks-any-compute-agent "QMAws::runTask | begin"
  • 1분 내 runTask begin 횟수가 10회 초과 시 알림 설정 권장.

Risk Assessment#

  • Risk level: medium
  • 예상 복잡도: standard — SDK 설정 변경은 trivial이나, rate limiting 도입은 테스트가 필요한 standard 수준의 작업