두 가지를 붙였다. AWS 요금이 새는지 감시하는 Budget Alert, 그리고 Lambda 워커들 에러를 잡아주는 Sentry.
월 $10을 넘으면 80%, 100% 구간에서 각각 이메일이 오도록 Terraform으로 정의했다.
resource "aws_budgets_budget" "monthly" {
name = "prod-shorts-monthly"
budget_type = "COST"
limit_amount = "10"
limit_unit = "USD"
time_unit = "MONTHLY"
notification {
comparison_operator = "GREATER_THAN"
threshold = 80
threshold_type = "PERCENTAGE"
notification_type = "ACTUAL"
subscriber_email_addresses = ["newgirok@gmail.com"]
}
notification {
comparison_operator = "GREATER_THAN"
threshold = 100
threshold_type = "PERCENTAGE"
notification_type = "ACTUAL"
subscriber_email_addresses = ["newgirok@gmail.com"]
}
}
Lambda 워커가 여러 개 도는 구조라 트래픽이 튀면 요금도 같이 튄다. 미리 두 단계로 잡아둬야 나중에 청구서 보고 놀라지 않는다.
워커마다 Sentry 초기화 코드를 따로 짜기 싫어서 shared 패키지에 공용 함수를 하나 뒀다.
import * as Sentry from '@sentry/aws-serverless';
export function initSentry(): void {
if (!process.env.SENTRY_DSN) return;
Sentry.init({
dsn: process.env.SENTRY_DSN,
environment: process.env.NODE_ENV ?? 'development',
tracesSampleRate: 0,
});
}
export { Sentry };
SENTRY_DSN이 없으면 조용히 스킵한다. 로컬 개발 환경에서까지 Sentry로 이벤트가 날아가는 걸 막기 위해서다.
API와 워커 7개 전부 같은 패턴으로 붙였다. initSentry()를 최상단에서 호출하고, 실제 핸들러를 Sentry.wrapHandler로 감싼다.
const _handler: SQSHandler = async (event: SQSEvent) => {
...
};
export const handler = Sentry.wrapHandler(_handler);
wrapHandler가 unhandled exception을 자동으로 캡처해준다. 그동안은 워커가 죽으면 CloudWatch Logs에 들어가서 stack trace를 눈으로 찾아야 했는데, 이제 Sentry 대시보드에 바로 뜬다.
각 워커 serverless.yml에는 SENTRY_DSN SSM 참조를 한 줄씩 추가했다. 워커 7개 + API까지 총 8곳을 반복 작업했다.
원래 ADR에는 "Phase 7 이후 Clova Voice로 전환 검토"라는 문구가 있었다. 이 시점에 그 계획을 접었다.
-# ADR 002: TTS 엔진 — msedge-tts (→ Phase 7: Clova Voice)
+# ADR 002: TTS 엔진 — msedge-tts
...
-**Phase 7 이후:** Clova Voice로 전환 검토
-
-- 더 자연스러운 한국어 억양
-- 감정 표현 지원 (구독 유도 CTA에 효과적)
-- 월정액 비용 발생 → 수익화 이후 전환
-
월정액 비용이 발생하는 유료 TTS는 지금 규모에선 이득보다 부담이 크다고 판단했다. msedge-tts로 계속 간다.