우선 다른 해결방법도 있다.
이 분의 해결방법도 있고
https://blossoming-man.tistory.com/entry/%EC%9C%88%EB%8F%84%EC%9A%B0-celery%EA%B0%80-%EC%9E%91%EB%8F%99%EC%9D%84-%EC%95%88-%ED%95%98%EB%8A%94-%EC%9D%B4%EC%9C%A0-%ED%95%B4%EA%B2%B0%EC%B1%85
이 분의 해결방법도 있다.
https://velog.io/@jaewan/Celerywindow%EC%97%90%EC%84%9C-celery-task%EA%B0%80-%EC%8B%A4%ED%96%89%EB%90%98%EC%A7%80-%EC%95%8A%EB%8A%94-%EB%AC%B8%EC%A0%9C
아래에 제시될 해결방법과 다른 방법이다
django-celery-beat를 활용하여 함수를 스케줄링했다.
우선 redis설치하고 redis-server는 필수입니다. 다른 툴도 있지만 저는 이걸 사용했어요
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'skapi.apps.SkapiConfig',
'forcast',
'rest_framework',
'django_celery_beat',
'django_celery_results',
]
...
CELERY_BEAT_SCHEDULE = {
# 8시부터 16시까지 매 2시간마다 실행 (8, 10, 12, 14 시)
'update_every_2_hours': {
'task': 'skapi.tasks.periodic_update_congestion_data',
'schedule': crontab(hour='8,10,12,14'),
'args': ()
},
# 16시부터 22시까지 매시간 실행 (16, 17, 18, 19, 20, 21 시)
'update_every_hour': {
'task': 'skapi.tasks.periodic_update_congestion_data',
'schedule': crontab(hour='16-21'),
'args': ()
},
}
from __future__ import absolute_import, unicode_literals
import os
from celery import Celery
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'config.settings')
app = Celery('config')
app.config_from_object('django.conf:settings', namespace='CELERY')
app.autodiscover_tasks()
from __future__ import absolute_import, unicode_literals
from .celery import app as celery_app
__all__ = ('celery_app',)
from celery import shared_task
from .callapi import UpdateSkAPi
from django.db import transaction
from .models import AreaInfo
import logging
logger = logging.getLogger(__name__)
@shared_task()
def periodic_update_congestion_data():
logger.info("Starting to update congestion data.")
try:
with transaction.atomic():
AreaInfo.objects.all().delete()
logger.info("All AreaInfo records have been deleted.")
updater = UpdateSkAPi()
updater.update_congestion_data()
logger.info("Finished updating congestion data.")
except Exception as e:
logger.error(f"Error updating congestion data: {e}", exc_info=True)
celery -A proj worker -l info
celery -A proj beat -l
terminal에서 찍히는 정보를 해석했을 때 스케줄링에 맞추어 잘 호출이 진행 되지만(db의 데이터를 전부 지우는 함수) db의 데이터는 계속 생존해 있었다.
celery -A proj worker -l info --without-gossip --without-mingle --without-heartbeat -Ofair --pool=solo
celery -A proj beat -l info --scheduler django_celery_beat.schedulers:DatabaseScheduler
gossip: 워커들 사이에 상태 정보를 교환하는 메터니즘.(없다면 네트워크 부하와 메모리 사용 줄음)
mingle: 워커가 시작할 때 다른 워커가 현재 상태에 대한 정보를 교환(없다면 시작시간 줄음)
heartbeat: 워커가 여전히 살아있다는 신호,(없다면 메세징 부하 줄음)
Ofair: 여러 개의 큐에서 메시지를 고르게 가져가게하여 특정 워커가 과부화 되는 것 바지
pool=solo: 워커의 작업 로드 관리를 단순화, 공유 리소스에 대한 경쟁이나 복잡한/ 멀티스레딩/멀티프로세싱 이슈가 있을 때 도움 됨
필요없는 기능을 걷어내어 통신을 안정시키고, 작업 로드를 단순화 시켜서 된 것 같다.
아마 -Ofair --pool=solo가 큰 해결책이었던 것 같다.
하지만 진짜 문제를 찾기 위해 로그를 찍어봐야한다. 가 아니라 내 운영체제는 Windows
Celery 4.x 이후부터는 Windows를 공식적으로 지원하지 않는다.
다음부터는 자신의 환경(운영체제, 메모리, 용량, 같이사용하려는 툴과의 호환 등)과 툴이 호환되는지 확인해보자
celery -A proj beat -l info --scheduler django_celery_beat.schedulers:DatabaseScheduler
import logging
logger = logging.getLogger(__name__)
@shared_task()
def periodic_update_congestion_data():
logger.info("Starting to update congestion data.")
try:
with transaction.atomic():
AreaInfo.objects.all().delete()
logger.info("All AreaInfo records have been deleted.") # 로깅
updater = UpdateSkAPi()
updater.update_congestion_data()
logger.info("Finished updating congestion data.")
except Exception as e:
logger.error(f"Error updating congestion data: {e}", exc_info=True) # 로깅
LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'handlers': {
'file': {
'level': 'Debug', # 레벨로는 INFO, ERROR, DEBUG, CRITICAL이 있다.
'class': 'logging.FileHandler',
# 파일의 경로설정이다. 만약 따로 관리하고 싶다면 log/debug.log 이렇게 해도된다.
'filename': 'debug.log',
},
},
'loggers': {
'django': {
'handlers': ['file'],
'level': 'DEBUG',
'propagate': True,
},
},
}
LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'handlers': {
'file': {
'level': 'INFO',
'class': 'logging.FileHandler',
'filename': 'debug.log',
},
},
'loggers': {
'django': {
'handlers': ['file'],
'level': 'DEBUG',
'propagate': True,
},
},
}
DEBUG를 찍으면 로그내용이 너무많다. 위를 지우고 출력할 레벨의 로그만 확인해도 됩니다.