[인프런] 실리콘밸리 엔지니어와 함께하는 샐러리(Celery) 학습 정리 2
2024.06.29 - [Study/django] - [인프런] 실리콘밸리 엔지니어와 함께하는 샐러리(Celery) 학습 정리 1
1. Scheduling and Periodic Task
1) Celery Monitoring Tool, Flower에 대해 알아보기
- 참고 페이지 : https://flower.readthedocs.io/en/latest/
- 실시간으로 작업 실행, worker 상태, 운영 지표를 제공받을 수 있다.
- 사용시 장점 :
- Task Monitoring : task progress와 히스토리를 모니터링 할 수 있다.
- Worker Monitoring : worker의 상태를 모니터링 할 수 있다.
- Real-time Updates : task를 실행 할 때마다 실시간 모니터링을 할 수 있다.
- Task Management : task 관리를 할 수 있다. 취소, 재시작 등의 작업을 스케줄링되었거나 작업 중인 작업에 지시할 수 있다.
- Worker management : worker 또 시작 정지 등의 관리를 할 수 있다.
- Broker Moniroring : redis나 rabbitMQ와 같은 broker도 모니터링 할 수 있다.
- Secure Access : 기본 HTTP 인증, OAuth2 등의 메커니즘이 지원된다.
- docker-compose 업데이트
version: "3.9"
services:
app:
build:
context: .
args:
- DEV=true
ports:
- "8000:8000"
volumes:
- ./app:/app
depends_on:
- redis
command: >
sh -c "
python manage.py makemigrations &&
python manage.py migrate &&
python manage.py runserver 0.0.0.0:8000
"
redis:
image: redis:latest
celery:
build:
context: .
volumes:
- ./app:/app
command: celery --app=worker worker -l INFO -Q celery,celery:1,celery:2
# command: celery --app=worker worker -l INFO -Q queue1
# command: celery --app=worker worker -l INFO
# command: celery --app=worker worker -l INFO -P gevent # for windows
depends_on:
- redis
celery-standalone:
build:
context: standalone_celery
volumes:
- ./standalone_celery:/app
command: celery --app=main worker -l INFO -Q celery3,celery:4,celery:5
# command: celery --app=main worker -l INFO -Q queue2
# command: celery --app=main worker -l INFO
depends_on:
- redis
flower:
image: mher/flower:latest
ports:
- "5555:5555"
environment:
- CELERY_BROKER_URL=redis://redis:6379/0
depends_on:
- celery
- celery-standalone
2) Celery Scheduling에 대해 알아보기
- 관련 페이지 : https://docs.celeryq.dev/en/stable/userguide/periodic-tasks.html#starting-the-scheduler
- Time-based : celery-beat을 사용해 카운트다운이나 ETA를 사용한다.
- Event-based : adhoc 개념이다.
- Dependency-based : 체이닝과 그룹핑 task이다.
- 개발용에는 명령어 끝에 -B를 추가하면 된다.
- 프로덕트용에는 따로 적용을 해줘야 한다. 공식 페이지를 참고한다.
1. celery.py에 설정하는 방법
app.conf.beat_schedule = {
"add-every-5-seconds": {
"task": timedelta(seconds=5),
"args": (10, 10),
# "kwargs": {"key": "value"},
# "options": {"queue": "celery"},
},
"add-every-minute": {
"task": "worker.tasks.add",
"scheduel": crontab(minute="*"),
"args": (20, 20),
},
}
3) Django Celery Beat과 Django Celery Result에 대해 알아보기
- celery-beat 설치 관련 문서 : https://github.com/celery/django-celery-beat?tab=readme-ov-file#installation
- celery-result 설치 관련 문서 : https://github.com/celery/django-celery-results?tab=readme-ov-file#installing
1. 설치
pip install django-celery-beat django-celery-results
2. settings.py에 추가
INSTALLED_APPS = [
...
"django_celery_beat",
"django_celery_results",
]
3. migration 실행
python manage.py makemigrations
python manage.py migrate
4. docker-compose 업데이트
- celery-standalone은 데이터베이스 설정이 안되어 있기 때문에 저장이 안된다. 주석 처리한다.
services:
app:
build:
context: .
args:
- DEV=true
ports:
- "8000:8000"
volumes:
- ./app:/app
environment:
POSTGRES_DB: app
POSTGRES_USER: root
POSTGRES_PASSWORD: admin
POSTGRES_HOST: db
depends_on:
- redis
command: >
sh -c "
python manage.py makemigrations &&
python manage.py migrate &&
python manage.py runserver 0.0.0.0:8000
"
redis:
image: redis:latest
ports:
- "6379:6379"
celery:
build:
context: .
volumes:
- ./app:/app
environment:
POSTGRES_DB: app
POSTGRES_USER: root
POSTGRES_PASSWORD: admin
POSTGRES_HOST: db
command: celery --app=worker worker -l INFO -Q celery, celery,1, celery,2
# command: celery --app=worker worker -l INFO -Q queue1
# command: celery --app=worker worker -l INFO
# command: celery --app=worker worker -l INFO -P gevent # for windows
depends_on:
- redis
# celery-standalone:
# build:
# context: standalone_celery
# volumes:
# - ./standalone_celery:/app
# environment:
# POSTGRES_DB: app
# POSTGRES_USER: root
# POSTGRES_PASSWORD: admin
# POSTGRES_HOST: db
# command: celery --app=main worker -l INFO -Q celery,3, celery,4, celery,5
# # command: celery --app=main worker -l INFO -Q queue2
# # command: celery --app=main worker -l INFO
# depends_on:
# - redis
flower:
image: mher/flower:master
ports:
- "5555:5555"
environment:
- CELERY_BROKER_URL=redis://redis:6379/0
depends_on:
- celery
# - celery-standalone
celery-beat:
build:
context: .
volumes:
- ./app:/app
environment:
POSTGRES_DB: app
POSTGRES_USER: root
POSTGRES_PASSWORD: admin
POSTGRES_HOST: db
command: celery -A worker beat -l INFO --scheduler django_celery_beat.schedulers:DatabaseScheduler
depends_on:
- redis
- db
db:
image: postgres:latest
ports:
- "5432:5432"
environment:
POSTGRES_DB: app
POSTGRES_USER: root
POSTGRES_PASSWORD: admin
5. settings.py 업데이트
# db변경
# DATABASES = {
# "default": {
# "ENGINE": "django.db.backends.sqlite3",
# "NAME": BASE_DIR / "db.sqlite3",
# }
# }
DATABASES = {
"default": {
"ENGINE": "django.db.backends.postgresql_psycopg2",
"NAME": os.environ.get("POSTGRES_DB"),
"USER": os.environ.get("POSTGRES_USER"),
"PASSWORD": os.environ.get("POSTGRES_PASSWORD"),
"HOST": os.environ.get("POSTGRES_HOST"),
"PORT": "5432",
}
}
# celery 설정 추가
# Celery Configuration Options
CELERY_TIMEZONE = TIME_ZONE
CELERY_TASK_TRACK_STARTED = True
CELERY_TASK_TIME_LIMIT = 30 * 60
CELERY_BROKER_URL = os.environ.get("CELERY_BROKER", "redis://127.0.0.1:6379/0")
# CELERY_RESULT_BACKEND = os.environ.get("CELERY_BACKEND", "redis://127.0.0.1:6379/0")
# CELERY_BROKER_URL = os.environ.get("CELERY_BROKER", "redis://redis:6379/0")
# CELERY_RESULT_BACKEND = os.environ.get("CELERY_BACKEND", "redis://redis:6379/0")
CELERY_RESULT_BACKEND = "django-db"
CELERY_TASK_SERIALIZER = "json"
CELERY_BEAT_SCHEDULER = "django_celery_beat.schedulers:DatabaseScheduler"
6. flower 버그 수정
- 최신 버전의 이미지와 패키지를 사용하면 flower가 데이터 동기화 실패를 한다는 문제가 있었다.
- docker 이미지
flower:
image: mher/flower:master
- poetry 버전
celery = "^5.2.0"
django-celery-beat = "^2.3.0"
django-celery-results = "^2.0.1"
4) 동적으로 tasks들을 레지스터해 보기
- 관련 페이지 : https://docs.celeryq.dev/en/stable/reference/celery.html#celery.Celery.autodiscover_tasks
- 사용하는 목적이 여러개가 있겠지만, 특정 app, 폴더에만 있는 tasks만 동작하게 만드는 경우가 적절한것 같다.
- autodiscover_tasks 분석:
autodiscover_tasks(packages=None, related_name='tasks', force=False)
- packages : 디렉토리의 위치 정의
- related_name : 기존과 다른 파일명일 경우 정의
1. 2개의 app을 가지고 있는 my_project의 경우
my_project/
├── manage.py
├── app1/
│ ├── __init__.py
│ └── tasks.py
├── app2/
│ ├── __init__.py
│ └── tasks.py
└── config/
├── __init__.py
└── celery.py
- 2개의 디렉토리 위치 정의
- config.celery는 생략 가능
- 각 app의 하위 폴더에도 task가 있는 경우, 재귀로 자동으로 찾는다. 정의를 해줘도 된다.
# config/celery.py
from celery import Celery
from celery.schedules import crontab
app = Celery('my_project')
app.config_from_object('config.settings', namespace='CELERY')
# 프로젝트 루트 디렉토리와 각 앱의 경로를 전달
app.autodiscover_tasks(['app1', 'app2', 'config.celery'])
# 다른 Celery 설정...
2. 각 폴더에 있는 tasks의 파일 이름이 다른 경우
- related_name 사용
# config/celery.py
from celery import Celery
from celery.loaders.base import autodiscover_tasks
app = Celery('my_project')
app.config_from_object('config.settings', namespace='CELERY')
# 파일명을 지정하여 autodiscover_tasks 호출
app.autodiscover_tasks(['app1', 'app2', 'app3'], related_name='my_tasks')
- task_modules 사용
app.autodiscover_tasks(['app1', 'app2', 'app3'], task_modules=['my_tasks'])
- 각 폴더별 이름이 다른 경우
app.autodiscover_tasks(
['app1', 'app2', 'app3'],
related_name={
'app1': 'my_tasks',
'app2': 'your_tasks',
'app3': 'their_tasks',
}
)