카테고리 없음

celery beat와 UTC시간 (오류 해결)

sorecord 2025. 3. 25. 15:21

celery beat를 이용해서 내가 원하는 알람시간의 스케줄을 저장하고 해당 알람시간이 되면 tasks.py를 실행시키는 코드를 짰다. 하지만 도저히 task.py가 실행되지 않았다. 


beat가 연결이 안되서 그런가 싶어서 테스트 코드를 작성했다. 

#celery.py
app.conf.beat_schedule = {
    'test_periodic_task': {
        'task': '앱이름.tasks.test_periodic_task',
        'schedule': crontab(minute='*/10'), #timedelta(seconds=10)  #minute=1 그냥 이렇게 적으면 매 1분이라는 시각에만 동작하는 것. 8시1분 9시1분 이런식
    },
}
@shared_task
def test_periodic_task():
    print("test Periodic task")
    return "Complete"

 

동작 코드 

celery -A config beat -l INFO
#다른 터미널
celery -A config worker --pool=gevent -l info

10분을 주기로 잘 실행이 되었다. 


하지만,

clocked, _ = ClockedSchedule.objects.get_or_create(
            clocked_time=시간입력
        )
        task = PeriodicTask.objects.create(
            clocked=clocked,
            name=f'Notification-{notification.id}',
            task='앱이름.tasks.send_notification',
            args=json.dumps([notification.id]),
            one_off=True,
        )

위와 같은 코드로 시간을 직접 저장하고 보냈을때 task가 실행되지 않았다. 


아무리 시간을 입력을 해도 task가 실행되지 않았다. 그러다 아래 코드에서 실마리를 발견했다.

python manage.py shell

from django_celery_beat.models import ClockedSchedule, PeriodicTask,CrontabSchedule
#task의 이름에 Notification이 들어간 값만 출력
print(PeriodicTask.objects.filter(name__contains="Notification").values())

#출력값
<PeriodicTaskQuerySet [..'name': 'Notification-28', 'task': '앱이름.tasks.send_notification', 
...'clocked_id': 9, ... 'date_changed': datetime.datetime(2025, 3, 25, 4, 41, 34, 30609, tzinfo=datetime.timezone.utc),
'description': ''}]>

 

위에서 확인한 부분은 datetime 부분이다. 난 분명 오후 1시??분으로 시간을 저장했는데 시간이 4시??분으로 저장이 되어있었다.admin에는 오후 1시??분으로 잘 저장이 되어있었다.


문제를 정리해보자면

1. DB에 저장된 값은 UTC 타임으로 저장

2. Admin에 입력된 값은 KST로 저장

3. 시간대가 일치하지 않으니 Celery Beat가 예약시간을 인식하지 못하는 것.

 

지금 내가 사용하던 코드는 KST시간을 그대로 저장하기에 beat는 9시간 늦게(UTC를 기준) 작업을 실행하려고 한 것이다.

Beat 스케줄러는 항상 UTC기준으로 작업을 실행한다.


 

아래와 같은 파일로 설정을 바꿔주었다. 

setting.py

...
CELERY_TIMEZONE = 'Asia/Seoul'#단지 사용자에게 보이는 시간만 변경
...

CELERY_ENABLE_UTC=True #모든 스케줄링은 UTC로 처리되며, 이 설정을 False로 해도 내부적으로 UTC를 사용
USE_TZ = True

 

그럼 문제를 해결하기 위해서는 KST시간을 UTC로 바꿔줘서 저장해주면 된다.


from django.utils import timezone
print("현재 Django 시간대:", timezone.get_current_timezone_name())  # Asia/Seoul이 나와야 함

위의 코드를 사용했더니 시간대값은 UTC가 나왔다. 이렇게 되면 UTC를 UTC로 변경을 하는 것이기에 의미가 없다.

그래서 아래 코드를 사용했다. 

from django.utils import timezone
from datetime import datetime
import pytz  # pip install pytz

# 1) 명시적으로 KST 시간대 생성
kst = pytz.timezone('Asia/Seoul')

kst_time = kst.localize(datetime.combine(
    날짜와 시간 입력
))
print("KST 시간:", kst_time)  # 2025-03-25 13:54:00+09:00

# 2) UTC로 변환
utc_time = kst_time.astimezone(pytz.UTC)
print("UTC 시간:", utc_time)  # 2025-03-25 04:54:00+00:00

 

해당 utc시간을 다시 ClockSchedule에 넣어주니 task가 잘 실행되었다. 

 # ClockedSchedule 생성 (UTC 사용)
 clocked, _ = ClockedSchedule.objects.get_or_create(clocked_time=utc_time)

추가 정보

 

from django_celery_beat.models import ClockedSchedule, PeriodicTask,CrontabSchedule

a=CrontabSchedule.objects.all()  
b=ClockedSchedule.objects.all()
a.delete()
b.delete() #이렇게 저장된 시간들을 삭제할 수 있다.

주의할 점은 task가 등록되어있는 시간을 지우면 오류가 발생할 수 있다. 


https://blog.mikihands.com/ko/whitedec/2025/2/3/django-celery-beat-crontab-clocked/

 

Django-Celery-Beat: Crontab과 Clocked를 활용한 예약 작업 설정

Django-Celery-Beat에서 Crontab과 Clocked를 활용한 예약 작업 설정 방법을 설명합니다. 특정 시각에 실행되는 작업과 한 번만 실행되는 작업을 설정하는 방법을 다룹니다.

blog.mikihands.com

 

문제시 비공개 처리하도록 하겠습니다.