[End-Gamers] AI ๋ถ์์ ๋ฐฑ๊ทธ๋ผ์ด๋๋ก - Celery·Redis ๋น๋๊ธฐ ํ์ดํ๋ผ์ธ๊ณผ Slack ์๋ฆผ ์ฐ๋
๋ค์ด๊ฐ๋ฉฐ
๋ก๊ทธ ์ ๋ก๋ ๋ฒํผ์ ๋๋ ๋๋ ๋ธ๋ผ์ฐ์ ๊ฐ 60์ด ๋์ ๋น๊ธ๋น๊ธ ๋๋ค.
์ฌ์ฉ์ ์ ์ฅ์์ ์ด ์๊ฐ์ ํ์์์์ด ๋๊ฑฐ๋, ๋ต๋ตํด์ ํญ์ ๋ซ์๋ฒ๋ฆฌ๊ธฐ ๋ฑ ์ข์ ์๊ฐ์ด๋ค.
์ด ๋ณ๋ชฉ์ ํด๊ฒฐํ๊ธฐ ์ํด Celery๋ฅผ ๋์ ํ์ฌ ์์ ์ ๋ฐฑ๊ทธ๋ผ์ด๋๋ก ๋ถ๋ฆฌํ๊ธฐ๋ก ๊ฒฐ์ ํ๋ค.

1. ๋น๋๊ธฐ๋ก ๋ฐ๊พธ๋ฉด ๋ญ๊ฐ ๋ฌ๋ผ์ง๋
๋๊ธฐ์ ๋น๋๊ธฐ์ ์ฐจ์ด๋ ์์ ์ '์ฃผ๋๊ถ'์ ์ธ์ ํด๋ผ์ด์ธํธ์๊ฒ ๋๋ ค์ฃผ๋๋์ ์๋ค.
[๋๊ธฐ]
ํด๋ผ์ด์ธํธ → POST /analyze → AI ๋ถ์ (60์ด) → ์๋ต ๋ฐํ
↑ 60์ด ๋์ ์ฐ๊ฒฐ์ด ์ด์์์ด์ผ ํจ
[๋น๋๊ธฐ]
ํด๋ผ์ด์ธํธ → POST /analyze → "์ ์๋จ" ์ฆ์ ์๋ต
Celery ํ์ ์์
๋ฑ๋ก
→ Worker๊ฐ AI ๋ถ์ (๋ฐฑ๊ทธ๋ผ์ด๋)
→ ์๋ฃ ์ Slack ์๋ฆผ
๋น๋๊ธฐ๋ก ์ ํํ๋ฉด ํด๋ผ์ด์ธํธ๋ ์ ๋ก๋ ์ฆ์ ์๋ต์ ๋ฐ๋๋ค. ๋ฌด๊ฑฐ์ด AI ๋ถ์์ ๋ฐฑ๊ทธ๋ผ์ด๋์์ ์์์ ๋์๊ฐ๊ณ , ์์ ์ด ๋๋๋ฉด Slack ์นํ ์ ํตํด ๊ฒฐ๊ณผ๋ฅผ ๋ฐ์๋ณด๊ฒ ๋๋ค.
2. ์ํคํ ์ฒ
์ธ๋ถ์ ๊ฑฐ์ฐฝํ ํ ์๋น์ค(SQS, RabbitMQ ๋ฑ)๋ฅผ ๋ถ์ด๊ธฐ๋ณด๋ค๋, ๋จ์ผ EC2 ์ธ์คํด์ค ์์์ ๋ชจ๋ ์๋น์ค๊ฐ ํจ๊ป ๋์๊ฐ๋ ์ฌํํ ๊ตฌ์กฐ๋ฅผ ํํ๋ค.
FastAPI (uvicorn)
โโ ์์ฒญ ๋ฐ์ผ๋ฉด Celery ํ์ ๋ฑ๋ก → ์ฆ์ "์ ์๋จ" ์๋ต
Redis
โโ Celery ๋ธ๋ก์ปค (์์
ํ)
Celery Worker
โโ ํ์์ ์์
๊บผ๋ด์ Bedrock ํธ์ถ → ๋ถ์ → S3 ์ ์ฅ → Slack ์๋ฆผ
์ธ๋ถ ํ ์๋น์ค ์์ด EC2 ํ๋์์ ๋ค ๋๋ฆฐ๋ค. ๋จ์ํ๊ณ ๊ด๋ฆฌํ ๊ฒ ์๋ค.
3. Slack ์๋ฆผ 3์ข
๋ถ์์ด ๋ฐฑ๊ทธ๋ผ์ด๋๋ก ๋์ด๊ฐ๋ฉด ์๋ฃ ์์ ์ ์ ๋ฐฉ๋ฒ์ด ์๋ค. ๊ทธ๋์ Slack ์นํ ์ ๋ฌ์๋ค.
| ์ด๋ฒคํธ | ์๋ฆผ ๋ด์ฉ |
|---|---|
| ๋ถ์ ์์ | ์ธ์๋ํธ ID, ๋ก๊ทธ ํ์ผ๋ช , ๋ด๋น AI |
| ๋ถ์ ์๋ฃ | ์ฌ๊ฐ๋, ์์ฝ, ๋ณด๊ณ ์ ๋งํฌ |
| RCA ์น์ธ | ์ต์ข ์น์ธ์, ์น์ธ ์๊ฐ |
๋ถ์ ์๋ฃ ์๋ฆผ์๋ ์ฌ๊ฐ๋(CRITICAL / HIGH / MEDIUM / LOW)๋ฅผ ์์์ผ๋ก ๋ฃ์๋ค.
4. ์ฝ๋ ๊ตฌ์กฐ
Celery ์ฑ ์ค์ :
# tasks/celery_app.py
celery_app = Celery(
"incident-autopsy",
broker="redis://localhost:6379/0",
backend="redis://localhost:6379/0",
include=["tasks.analyze_task", "tasks.notify_task"]
)
ํ์คํฌ ๋ฑ๋ก:
# tasks/analyze_task.py
@celery_app.task
def analyze_incident(incident_id: str, log_content: str, ai_provider: str):
result = ai_dispatcher.analyze(log_content, ai_provider)
sqlite_repo.save_analysis(incident_id, result)
slack.notify_complete(incident_id, result)
FastAPI์์ ํ์ ๋ฃ๊ธฐ:
.delay()๊ฐ ์์ ์ ํ์ ๋ฃ๊ณ ๋ฐ๋ก ๋ฆฌํดํ๋ค.
@router.post("/api/v2/incidents")
async def upload_incident(file: UploadFile):
incident_id = save_to_s3(file)
analyze_incident.delay(incident_id, content, ai_provider) # ๋น๋๊ธฐ
return {"status": "accepted", "incident_id": incident_id}
5. ํธ๋ฌ๋ธ์ํ
ํ์คํฌ ๋ชจ๋ ์๋ ๋ฑ๋ก ๋๋ฝ
Worker๋ฅผ ์์ํ๋๋ฐ ํ์คํฌ๋ฅผ ์ธ์ํ์ง ๋ชป ํ๋ค.
[ERROR] Received unregistered task of type 'tasks.analyze_task.analyze_incident'
์ด๋ Celery ์ฑ ์์ฑ ์ include ์ต์
์ผ๋ก ํ์คํฌ ๋ชจ๋์ ๋ช
์ํด์ผ ํ๋๋ฐ ๋น ๋จ๋ ธ๊ธฐ ๋๋ฌธ์ด๋ค.
์ ์ฝ๋์ฒ๋ผ include ํ๋ผ๋ฏธํฐ๋ฅผ ์ถ๊ฐํด์ผ Worker๊ฐ ํ์คํฌ๋ฅผ ์ฐพ์ ์ ์๋ค.
v1 ์๋ํฌ์ธํธ Slack ์ฐ๋ ๋๋ฝ
v2 ์๋ํฌ์ธํธ์๋ Slack ์๋ฆผ์ ๋ฌ์๋๋ฐ, ๊ธฐ์กด v1 ์๋ํฌ์ธํธ๊ฐ ๊ทธ๋๋ก ๋จ์์์๋ค.
v1์ผ๋ก ๋ถ์ํ๋ฉด Slack์ด ์ ์จ๋ค๋ ๊ฑธ ๋ค๋ฆ๊ฒ ๋ฐ๊ฒฌํ๋ค.
์ ๊ธฐ๋ฅ์ ๋ถ์ธ๋ค๋ฉด ๊ธฐ์กด ๊ฒฝ๋ก๋ ๊ฐ์ด ํ์ธํด์ผ ํ๋ค.
Redis ์์ ๋ ์์ฒญ์ด ๋ธ๋กํน๋๋ ๋ฌธ์
๋ก์ปฌ ๊ฐ๋ฐ ํ๊ฒฝ์์๋ Redis๋ฅผ ์ ๋์ฐ๊ณ ํ ์คํธํ๋ ๊ฒฝ์ฐ๊ฐ ๋ง๋ค.
Redis๊ฐ ์์ผ๋ฉด Celery๊ฐ ์ฐ๊ฒฐ์ ๊ธฐ๋ค๋ฆฌ๋ฉด์ ์์ฒญ ์์ฒด๊ฐ ๋ฉ์ท๋ค.
๋ฐ๋ผ์ fallback์ ๋ง๋ค์๋ค. Redis ์ฐ๊ฒฐ ์คํจ ์ ๋๊ธฐ๋ก ์ง์ ์คํํ๋ค.
try:
analyze_incident.delay(incident_id, content, ai_provider)
except Exception:
# Redis ์์ผ๋ฉด ๋๊ธฐ ์คํ
analyze_incident(incident_id, content, ai_provider)
๊ฐ๋ฐ ํ๊ฒฝ์์๋ ๋๋ฆฌ์ง๋ง ํฐ์ง์ง ์๋๋ค.
fetch-guid fire-and-forget
incident-autopsy๊ฐ log-autogenerator์์ ์ฃผ๊ธฐ์ ์ผ๋ก ์๋ฌ GUID๋ฅผ ๊ฐ์ ธ์ค๋ ๊ธฐ๋ฅ๋ Celery ํ์ ๋ฑ๋กํ๋๋ฐ, Redis๊ฐ ์์ผ๋ฉด ๋ฑ๋ก ์์ฒด๊ฐ ๋ธ๋กํน๋๋ค.
๊ทธ๋์ ๋ฑ๋ก์ ์คํจํ๋ฉด ๊ทธ๋ฅ ๋์ด๊ฐ๋ fire-and-forget ๋ฐฉ์์ผ๋ก ๋ฐ๊ฟจ๋ค.
์ ํ์ ๊ธฐ๋ฅ์ ์คํจํด๋ ๋ฉ์ธ ํ๋ก์ฐ๊ฐ ๋ฉ์ถ๋ฉด ์ ๋๋ค๊ณ ์๊ฐํ๋ค.
6. ๊ฒฐ๊ณผ
๋ฐฐํฌ ํ 60์ด์ง๋ฆฌ ๋๊ธฐ๊ฐ ์ฌ๋ผ์ก๋ค.
1. ์ ๋ก๋ ์ฆ์ "์ ์๋จ"์ด ๋จ๊ณ ,
2. 1~2๋ถ ํ Slack์ ๋ถ์ ๊ฒฐ๊ณผ๊ฐ ๋ ์์จ๋ค.
์ฌ์ฉ์ ์ ์ฅ์์๋ ๋ถ ์๋๊ฐ ๋นจ๋ผ์ง ๊ฒ ์๋๋ผ, ๊ธฐ๋ค๋ฆฌ๋ ์๊ฐ์ด ์์ด์ง ๊ฒ์ฒ๋ผ ๋๊ปด์ง๋ค.
๋น๋๊ธฐ๊ฐ ๋ถ์ ์๋๋ฅผ ๋์ด์ง ์๋๋ค. ํ์ง๋ง ๊ธฐ๋ค๋ฆฌ๋ 60์ด์ ๋ค๋ฅธ ์ผ ํ๋ฉด์ ๊ธฐ๋ค๋ฆฌ๋ 60์ด๋ ๋ค๋ฅด๋ค.
End-Gamers | incident-autopsy



