상시 서버 텔레그램 봇을 AWS Lambda 0원 서버리스로 전환한 실전 트러블슈팅 후기
1줄 요약
상시 가동 VM의 Long-Polling 봇을 AWS Lambda Function URL + DynamoDB + EventBridge 기반 0원 서버리스로 전환하면서 맞닥뜨린 C-바이너리 호환성(manylinux), asyncio MarshalError, 웹훅 30초 타임아웃 재시도 루프의 실전 해결 일지.
1. 아키텍처 전환: VM ➔ AWS Always Free Serverless
- 컴퓨팅: VM 상시 실행 (
python bot_main.py) ➔ AWS Lambda (월 100만 건 무료) - 엔드포인트: API Gateway 과금 배제 ➔ Lambda Function URL (무료 HTTPS 웹훅 수신)
- 상태 관리: 로컬 JSON 파일 ➔ Amazon DynamoDB (25GB 영구 무료)
- 스케줄링: cron 데몬 ➔ Amazon EventBridge (매일 09:00 KST 뉴스 스크래핑 트리거)
- 블로그 자동 배포: 로컬 git push ➔ PyGithub (GitHub REST API) 직접 커밋 생성
[서버리스 웹훅 아키텍처]
Telegram Server ──(Webhook POST)──> [Lambda Function URL]
│
┌──────────────┴──────────────┐
▼ ▼
[Amazon DynamoDB] [GitHub Repository]
(상태/세션 관리) (블로그 포스트 자동 커밋)2. 실전 트러블슈팅 3대 이슈
이슈 1. Windows 개발 환경의 C-Extension 바이너리 비호환 (502 Bad Gateway)
- 현상: Lambda 배포 후
ImportError: cannot import name ...발생하며 502 에러 반환. - 원인: Windows 개발 PC에서
pip install시pydantic_core,cryptography등의 C-확장 패키지가 Windows용.pyd바이너리로 설치되어 Linux(AL2023) 런타임에서 로드 실패. - 해결 조치:
build_zip.py패키징 스크립트에manylinux바이너리 강제 다운로드 옵션 적용.
bash
# Windows 환경에서 Linux용 Lambda 바이너리 강제 다운로드
pip install -r requirements.txt -t ./package \
--platform manylinux2014_x86_64 \
--only-binary=:all: \
--implementation cp이슈 2. Lambda 비동기 핸들러 직렬화 실패 (Runtime.MarshalError)
- 현상: 핸들러를
async def lambda_handler로 선언 시Object of type coroutine is not JSON serializable에러 발생. - 원인: AWS Lambda의 기본 Python 부트스트랩은
async def를await하지 않고 코루틴 객체 자체를 반환값으로 취급하여 직렬화 시도 중 에러 발생. - 해결 조치: 동기 핸들러 내에서
asyncio.run()으로 이벤트 루프를 생성하는 래퍼 패턴 적용.
python
import asyncio
async def main_async(event, context):
# python-telegram-bot 비동기 처리 로직
return {"statusCode": 200, "body": "OK"}
def lambda_handler(event, context):
"""Lambda 표준 진입점 (동기 래퍼)"""
return asyncio.run(main_async(event, context))이슈 3. AI 다국어 번역 지연으로 인한 텔레그램 웹훅 무한 재시도 루프
- 현상: Gemini API로 블로그 생성 및 영/일 번역 시 45초 이상 소요되자, 텔레그램 서버가 타임아웃(30초)으로 간주하고 동일 웹훅을 1분 간격으로 계속 재전송하여 중복 포스팅 발생.
- 해결 조치: 순차 처리되던 번역 API 호출을
asyncio.gather()병렬 처리로 전환하여 총 소요 시간을 18초 이내로 단축.
python
# 수정: 영문/일문 번역 병렬 처리로 응답 시간 50% 단축
translation_tasks = [
ai_processor.translate_blog_post_async(content, "English"),
ai_processor.translate_blog_post_async(content, "Japanese")
]
en_content, ja_content = await asyncio.gather(*translation_tasks)3. 핵심 체크포인트 (Gotchas)
- Lambda Function URL 콜드스타트: Python 패키지 크기가 커지면 콜드스타트가 2~3초 발생할 수 있으므로, 텔레그램 봇 응답은 최대한 빠르게 200 OK를 반환하거나 병렬 처리를 통해 30초 웹훅 타임아웃을 사수해야 한다.
- DynamoDB On-Demand 모드: 개인 프로젝트 규모에서는 프로비저닝(1 RCU/WCU) 대신 온디맨드 모드를 사용해도 영구 무료 프리티어(25 RCU/WCU 상당) 내에서 100% 0원으로 운영된다.
- Lambda 메모리 = CPU 파워: 메모리를 256MB에서 512MB로 올리면 네트워크 및 연산 속도가 비례하여 빨라져 AI 응답 지연을 방어하는 데 매우 효과적이다.
게시된 시간: 2026-08-21 16:37:13수정한 시간: 2026-08-15 13:57:00