ํ”„๋กœํ•„

YuSoeun

๐Ÿข ๋น ๋ฅธ ๊ฑฐ๋ถ์ด๊ฐ€ ๋˜์ž. ๋“œ๋ฌธ๋“œ๋ฌธ ๊พธ์ค€ํžˆ๊ฐ€ ์•„๋‹Œ ์ด˜์ด˜ํžˆ ๊พธ์ค€ํ•˜๊ฒŒ!

๋“ค์–ด๊ฐ€๋ฉฐ

๋กœ๊ทธ ์—…๋กœ๋“œ ๋ฒ„ํŠผ์„ ๋ˆŒ๋ €๋”๋‹ˆ ๋ธŒ๋ผ์šฐ์ €๊ฐ€ 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

 

RELATED ARTICLES

more