개인의 기록
  • 소개
  • 프로젝트
  • 글
  • 링크

© 2026 newgirok

← YouTube Shorts 자동화

알람 정비 — SNS 파싱과 KST 변환 수정

2026년 8월 3일
cloudwatch-notifierEventBridgecronapi

전혀 다른 두 버그를 같은 날 잡았다. 하나는 알림이 이상하게 뜨는 문제, 하나는 업로드 시각 자체가 틀어지는 문제다.

cloudwatch-notifier — 수식 알람 파싱

metric_query 기반(수식) 알람이 뜨면 함수명이 "알 수 없음"으로, Namespace가 undefined로 찍혔다. 원인은 세 가지가 겹쳐 있었다.

수식 알람은 Dimensions가 Trigger 최상위가 아니라 Trigger.Metrics[].MetricStat.Metric.Dimensions에 중첩돼 있다.

if (!functionNameFromDimension && alarm.Trigger.Metrics) {
  for (const m of alarm.Trigger.Metrics) {
    const dim = m.MetricStat?.Metric.Dimensions?.find((d) => (d.name ?? d.Name) === 'FunctionName');
    if (dim) {
      functionNameFromDimension = dim.value ?? dim.Value;
      break;
    }
  }
}

Namespace도 마찬가지로 최상위가 아니라 Metrics[] 안에 있어서, 폴백 순서를 만들었다.

const namespace =
  alarm.Trigger.Namespace ??
  alarm.Trigger.Metrics?.find((m) => m.MetricStat)?.MetricStat?.Metric.Namespace ??
  'AWS/Lambda';

dlq-notifier, cloudwatch-notifier 워커는 함수명을 역산할 때도 문제가 있었다. Terraform 맵 키는 언더스코어(dlq_notifier)인데 알람 이름은 대시(dlq-notifier) 기준이라 매칭이 안 됐다. 역산 자체도 -worker-가 없는 두 워커를 놓쳐서, 아예 명시적 매핑 테이블로 바꿨다.

const FUNCTION_NAMES: Record<string, string> = {
  'script': 'shorts-script-worker-prod-handler',
  ...
  'dlq-notifier': 'shorts-dlq-notifier-prod-handler',
  'cloudwatch-notifier': 'shorts-cloudwatch-notifier-prod-handler',
};

const workerKey = alarm.AlarmName
  .replace(/^prod-/, '')
  .replace(/-error-rate$/, '')
  .replace(/_/g, '-');
const functionName = functionNameFromDimension ?? FUNCTION_NAMES[workerKey] ?? `shorts-${workerKey}-prod-handler`;

패턴으로 추측하는 방식은 결국 예외 케이스가 계속 나온다. 워커 개수가 뻔한데 그냥 맵으로 못박는 게 나았다.

api — EventBridge cron의 KST → UTC 변환 누락

이건 더 심각했다. 채널 스케줄러에서 "매일 오전 9시"로 저장한 스케줄이 실제로는 UTC 9시, 즉 KST로 밤 18시에 돌고 있었다.

// 표준 5필드 cron(KST) → EventBridge 6필드 cron(UTC) 변환
// EventBridge는 UTC 기준이므로 KST 시간에서 9시간을 뺀다.
function toEventBridgeCron(cron: string): string {
  ...
  let ebHour = hour;
  let adjustedDow = dow;
  if (hour !== '*') {
    const kstHour = parseInt(hour, 10);
    const utcHour = (kstHour - KST_OFFSET + 24) % 24;
    ebHour = String(utcHour);
    // KST 시간이 09:00 미만이면 UTC로 변환 시 전날이 됨 → 주간 스케줄 요일 하루 앞으로 조정
    if (kstHour < KST_OFFSET && dom === '*' && dow !== '*') {
      adjustedDow = dow.replace(/\b([0-6])\b/g, (_, n) => String((parseInt(n, 10) - 1 + 7) % 7));
    }
  }
  ...
}

DB에는 KST 기준 cron이 그대로 저장돼 있어서 문제없었다. EventBridge 규칙을 만드는 시점에 변환을 아예 안 하고 있었던 거다. hour='*'인 매시간 스케줄은 변환할 게 없어서 그대로 뒀고, 요일 스케줄은 KST 자정~오전 9시 사이 시간대일 때 UTC로 넘어가면서 전날로 밀리는 것까지 같이 보정했다.

기존에 잘못 생성된 규칙은 채널 스케줄을 다시 저장해야 고쳐진다. 코드만 고친다고 이미 만들어진 EventBridge 규칙까지 자동으로 갱신되진 않는다.

← 이전 글알림 통합 — DLQ·CloudWatch Slack 리팩터
다음 글 →보안 강화 — 채널 소유권 검증과 IAM 최소권한, S3 SSE