๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ
  • ๐Ÿ‘ฉ๐Ÿปโ€๐Ÿ’ป ๐ŸŒฎ ๐Ÿ’ฌ
๐Ÿ› ๏ธ

AttributeError: 'DisabledBackend' object has no attribute '_get_task_meta_for'

by ๋ฐ”์ฟ„๋ฆฌ 2025. 2. 11.

 

 

Celery๋ฅผ ์ด์šฉํ•œ ํฌ๋กค๋ง ์˜ˆ์ œ

๊ฐœ์š”Airflow์™€ Celery๋ฅผ ๋น„๊ตํ–ˆ๋‹ค. ํฌ๋กค๋ง ๊ด€๋ฆฌ Airflow vs Celery๊ฐœ์š”๊ธฐ์กด ํ”„๋กœ์ ํŠธ์˜ ํฌ๋กค๋ง ์‹œ์Šคํ…œ์„ Airflow๋กœ ๊ด€๋ฆฌํ–ˆ๋‹ค.Airflow ์šด์˜ ์ค‘์ด๋˜ ์„œ๋ฒ„์— ๋ฌธ์ œ๊ฐ€ ๋งŽ์•˜๋Š” ๋ฐ, ๊ทธ ์ค‘์—์„œ ์ œ์ผ ํฐ ๋ฌธ์ œ๋Š” cpu ์ 

bonory.tistory.com

ํฌ๋กค๋ง ์˜ˆ์ œ๋ฅผ ์ง„ํ–‰ํ•˜๋ฉฐ ์ƒ๊ฒผ๋˜ ์˜ค๋ฅ˜ ๊ธฐ๋ก

 

๊ฐœ์š”

celery app์„ ํ™œ์„ฑํ™” ์‹œํ‚ค๊ณ , Fastapi app๋„ ํ™œ์„ฑํ™”ํ–ˆ๋‹ค.

celery_tasks.py

import requests
from bs4 import BeautifulSoup
from celery import Celery
import time

celery_app = Celery(
    "tasks",
    broker="redis://localhost:6379/0",
    backend="redis://localhost:6379/0"
)

@celery_app.task(bind=True)
def crawl_website_task(self, url: str):
    ...

app.py : FastAPI app

from fastapi import FastAPI, BackgroundTasks
from celery_tasks import crawl_website_task
from celery.result import AsyncResult

app = FastAPI()

@app.get("/")
def home():
    return {"message": "Welcome to the Celery Web Scraper API"}

@app.post("/crawl")
def start_crawling(url: str, background_tasks: BackgroundTasks):
    task = crawl_website_task.delay(url)
    return {"task_id": task.id, "message": f"Crawling started for {url}"}

@app.get("/task/{task_id}")
def get_task_status(task_id: str):

    task_result = AsyncResult(task_id)

    return {
        "task_id": task_id,
        "status": task_result.status,
        "result": task_result.result
    }

 

/crawl endpoint๋ฅผ ํ˜ธ์ถœํ•ด์„œ ํฌ๋กค๋ง์„ ์‹œ์ž‘ํ•˜๊ณ ,

โžœ  ~ curl -X POST "http://127.0.0.1:8000/crawl/?url=https://example.com"
{"task_id":"9f9e0b42-09d5-4fc1-9a76-21ce57397471","message":"Crawling started for https://example.com"}

 

์ƒํƒœ๋ฅผ ํ™•์ธํ•˜๊ธฐ ์œ„ํ•ด /task/{task_id} ํ˜ธ์ถœํ•˜๋‹ˆ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ–ˆ๋‹ค.

โžœ  ~ curl -X GET "http://127.0.0.1:8000/task/9f9e0b42-09d5-4fc1-9a76-21ce57397471"
Internal Server Error

 

FastAPI ๋กœ๊ทธ๋ฅผ ํ™•์ธํ•˜๋‹ˆ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์˜ค๋ฅ˜ ๋ฉ”์„ธ์ง€๋ฅผ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

AttributeError: 'DisabledBackend' object has no attribute '_get_task_meta_for'

→ ์ด ์˜ค๋ฅ˜๋Š” celery ๋ฐฑ์—”๋“œ๊ฐ€ ๋น„ํ™œ์„ฑํ™”๋˜์–ด์žˆ๋Š”๋ฐ ํƒœ์Šคํฌ๋ฅผ ์กฐํšŒํ•˜๋ ค๊ณ  ํ•  ๋•Œ ๋ฐœ์ƒํ•˜๋Š” ์˜ค๋ฅ˜์ด๋‹ค.

 

  • transport: redis://localhost:6379/0 → Celery๊ฐ€ Redis๋ฅผ ๋ฉ”์‹œ์ง€ ๋ธŒ๋กœ์ปค๋กœ ์‚ฌ์šฉ ์ค‘
  • results: redis://localhost:6379/0 → ๊ฒฐ๊ณผ ์ €์žฅ ๋ฐฑ์—”๋“œ๋กœ Redis ์‚ฌ์šฉ ์ค‘

ํ•˜์ง€๋งŒ, Celery ์‹คํ–‰ ์‹œํ‚ฌ ๋•Œ results: redis://localhost:6379/0 ์œผ๋กœ ๋ฐฑ์—”๋“œ ์ž˜ ํ™œ์„ฑํ™” ๋˜์–ด์žˆ์Œ์„ ํ™•์ธํ–ˆ๋‹ค.

๊ทธ๋Ÿผ FastAPI์—์„œ celery config๋ฅผ ๋ชป ์ฝ์–ด์„œ ์ƒ๊ธฐ๋Š” ๋ฌธ์ œ์ด๋‹ค.

 

celery_task.py ์— config๋ฅผ ์ง์ ‘ ๋ช…์‹œํ•ด์ค€๋‹ค.

celery_app.conf.update(
    result_backend="redis://localhost:6379/0", # ๋ฐฑ์—”๋“œ ์„ค์ • ๋ช…์‹œ์ ์œผ๋กœ ์ถ”๊ฐ€
    result_expires=3600, # ๊ฒฐ๊ณผ ์ €์žฅ ์‹œ๊ฐ„ (1์‹œ๊ฐ„)
    task_ignore_result=False, # ๊ฒฐ๊ณผ ์ €์žฅ ํ™œ์„ฑํ™” (๊ธฐ๋ณธ์ ์œผ๋กœ ๋น„ํ™œ์„ฑํ™”์ผ ์ˆ˜๋„ ์žˆ์Œ)
    broker_connection_retry_on_startup=True # Celery 6.0 ์ด์ƒ์—์„œ ํ•„์š”ํ•œ ์„ค์ • ์ถ”๊ฐ€
)

 

FastAPI app ์ชฝ์— ์ฝ”๋“œ๋„ ์ˆ˜์ •ํ•ด์ค€๋‹ค.

# ์ˆ˜์ • ์ „
@app.get("/task/{task_id}")
def get_task_status(task_id: str):

    task_result = AsyncResult(task_id)

    return {
        "task_id": task_id,
        "status": task_result.status,
        "result": task_result.result
    }
# ์ˆ˜์ • ํ›„
@app.get("/task/{task_id}")
def get_task_status(task_id: str):
    # Celery ๋ฐฑ์—”๋“œ ์„ค์ •์ด ์ ์šฉ๋˜์—ˆ๋Š”์ง€ ํ™•์ธ
    if celery_app.conf.result_backend is None or celery_app.backend is None:
        return {"error": "Celery backend is disabled in FastAPI"}

    # AsyncResult ํ˜ธ์ถœ
    task_result = AsyncResult(task_id, app=celery_app)

    return {
        "task_id": task_id,
        "status": task_result.status,
        "result": task_result.result
    }

 

  • ๋ฐฑ์—”๋“œ ์„ค์ • ์ ์šฉ ํ™•์ธ ๋จผ์ € ์ง„ํ–‰ํ•˜๊ณ 
  • ํ˜ธ์ถœ ํ• ๋•Œ celery app์„ ์ง์ ‘ ๋ช…์‹œํ•ด์ฃผ์—ˆ๋‹ค.

celery์™€ fastapi app๋ฅผ restart ์‹œํ‚ค๊ณ  ํ…Œ์ŠคํŠธ ์ง„ํ–‰

โžœ  ~ curl -X GET "http://127.0.0.1:8000/task/9f9e0b42-09d5-4fc1-9a76-21ce57397471"
{"task_id":"9f9e0b42-09d5-4fc1-9a76-21ce57397471","status":"SUCCESS","result":{"title":"Example Domain","links":["https://www.iana.org/domains/example"]}}

 

ํƒœ์ŠคํŠธ ์ƒํƒœ ์ž˜ ์ถœ๋ ฅ๋จ ํ™•์ธ