| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 1 | 2 | 3 | ||||
| 4 | 5 | 6 | 7 | 8 | 9 | 10 |
| 11 | 12 | 13 | 14 | 15 | 16 | 17 |
| 18 | 19 | 20 | 21 | 22 | 23 | 24 |
| 25 | 26 | 27 | 28 | 29 | 30 | 31 |
- 프로그래머스
- 프로젝트
- 파이썬
- 백준
- 채팅
- 개발일지
- 가상환경
- Git
- poetry
- re-id
- 마스킹
- WebSocket
- 미니프로젝트
- Commpot
- 1주차
- 알고리즘
- 정보처리기사
- js
- 2주차
- 정보처리기사실기
- vscode
- sql
- resnet50
- WIL
- channels
- REDIS
- WHERE절
- 장고
- github
- Class
- Today
- Total
개발일기
[Django] Schedule과 crontab 사용하기 본문
Schedule 라이브러리
- 특정한 작업(함수)를 주기적으로 실행/작업하기 위하여 사용하는 스케줄러
- 리눅스 OS 환경의 crontab, 윈도우 OS 환경의 작업 스케줄러와 같은 역할을 하고 실행할 주기, 날짜, 시간, 요일 등 을 지정하여 원하는 시점에 작업을 실행하거나 원하는 주기로 반복 실행하도록 구현할 수 있다.
pip install schedule
https://schedule.readthedocs.io/en/stable/
schedule — schedule 1.2.0 documentation
schedule.readthedocs.io
Crontab
- 리눅스 운영체제에서 배치 작업을 스케쥴링 하기 위한 프로그램
- 특정 시각에 작업이 실행되게끔 할 수도 있고, 정기적인 작업 스케쥴링을 할 수 있다.
- Crontab 규칙
분 : 0~59
시간 : 0-24
일 : 0~31
월 : 1~12
요일 : 0~7(0 또는 7=일요일, 1=월, 2=화 . 3=수 , 4=목, 5=금=6, 토7=일)
사용자명 /etc/crontab , /etc/cron.d에 저장될 경우 필요
작업명령 실행할 명령을 한줄로 쓴다
*(분) *(시간) * (월) *(요일) *([사용자명]) 실행명령 순으로 설정
* * * * * 유저 이름 명령어
┬ ┬ ┬ ┬ ┬
│ │ │ │ └─ 요일 (0 - 6) (0:일요일, 1:월요일, 2:화요일, …, 6:토요일)
│ │ │ └─ 월 (1 - 12)
│ │ └─일 (1 - 31)
│ └─ 시 (0 - 23)
└─ 분 (0 - 59)
- 예시
1. 매분, 매시간, 매일, 매월, 즉 1분만다 /home/ubuntu/start.sh 파일을 실행
* * * * * root /home/ubuntu/start.sh
2. 0분, 4시, 매일, 매월, 매일, 즉 매일 4시에 /home/ubuntu/start.sh 파일을 실행
0 4 * * * root /home/ubuntu/start.sh
3. 10분 간격, 4시, 매일, 매월, 매일, 즉 매일 4시, 4시 10분, 4시 20분, 4시 30분 /home/ubuntu/start.sh파일을 실행
*/10 4 * * * root /home/ubuntu/start.sh
4. 6시간마다 /home/ubuntu/start.sh 파일을 실행
0 */6 * * * root /home/ubuntu/start.sh
5. 평일(월요일~금요일) 08:00에 /home/ubuntu/start.sh 파일을 실행
0 8 * * 1-5 root /home/ubuntu/start.sh
6. 주말(일요일, 토요일) 08:00 에 /home/ubuntu/start.sh 파일을 실행
0 8 * * 0,6 root /home/ubuntu/start.sh
7. 매일 새벽 5시에 재부팅하기
0 5 * * * root /sbin/shutdown -r now
혹시 cron표현식을 작성하기 어렵다면 아래 사이트를 참고하면 좋다..!
Crontab.guru - The cron schedule expression editor
crontab.guru
사용 목적
내 경우에는, 구독 자동갱신과 취소, 채팅기록정리, 자동구매확정을 위해서 스케쥴링을 구현했다.
이렇게 주기적으로 반복실행되는 작업은 schedule과 crontab을 사용하여 처리해줄 수 있다.
이후에 배포를 고려하여 crontab으로 변경하였다.
어째서 crontab으로 변경을 하였는가?
schedule 라이브러리를 사용할 경우에는 스케줄링 함수의 변경사항을 적용시킬 때마다 서버다운을 해야하는 문제점이 있다. 하지만, ubuntu 환경에서(우리는 ubuntu를 사용했다.) crontab을 작동시킬 경우(crontab 명령어를 수정할 때)에는 서버를 다운시키지 않고도 변경사항을 적용시킬 수 있다.
코드 보기(Schedule 라이브러리)
def scheduling():
# 구독 자동갱신, 채팅기록 삭제, 자동구매확정
RelatedSubscriptionandChatandPoint.subscription_update()
RelatedSubscriptionandChatandPoint.chatlog_delete()
RelatedSubscriptionandChatandPoint.pointpaid()
return Response({"msg":"완료"}, status=status.HTTP_202_ACCEPTED)
class RelatedSubscriptionandChatandPoint:
@classmethod
def subscription_update(cls):
"""
구독 자동 갱신, 구독 취소
(다음 결제일은 4주 뒤) (포인트 차감)
"""
# 다음 결제일이 오늘의 날짜 이전인 구독들을 삭제(보안목적)
Subscribe.objects.filter(next_payment__lt=timezone.now().date(), subscribe=True).delete()
# 구독 갱신 및 구독취소할 사용자 필터링
subscribe_users = Subscribe.objects.filter(next_payment=timezone.now().date(), subscribe=True, is_cancel=False)
cancel_users = Subscribe.objects.filter(next_payment=timezone.now().date(), subscribe=True, is_cancel=True)
# 구독취소
for cancel_user in cancel_users:
with transaction.atomic():
cancel_user.subscribe = False
cancel_user.is_cancel = False
cancle_user.save()
# 구독갱신
for subscribe_user in subscribe_users:
with transaction.atomic():
total_point = PointStatisticView.get_total_point(subscribe_user.user)
# 구독료 9900원
if total_point >= 9900:
Point.objects.create(user=subscribe_user.user, point_type_id=6, point= 9900)
subscribe_user.subscribe = True
subscribe_user.next_payment = F('next_payment') + timedelta(weeks=4)
# 테스트용 (1시간 뒤)
# subscribe_user.next_payment = F('next_payment') + timedelta(hours = 1)
subscribe_user.save()
else:
subscribe_user.subscribe = False
subscribe_user.save()
@classmethod
def chatlog_delete(cls):
# 일주일 전 채팅은 지워지도록
one_week_ago = timezone.now() - timedelta(days=7)
RoomMessage.objects.filter(created_at__lte = one_week_ago).delete()
@classmethod
def pointpaid(cls):
# 배송완료 후 일주일이 지난 경우, 자동 포인트차감 진행
one_week_ago = timezone.now() - timedelta(days=7)
items = OrderItem.objects.filter(updated_at__lte = one_week_ago, order_status = 5)
if items:
for item in items:
item.order_status = 6
item.save()
seller = item.seller.user
user = item.bill.user
total_point = item.amount * item.price
# 유저 포인트 적립하기, 판매자에게 포인트 지불
order_point_create(user, seller, total_point)
우리는 스케줄을 매일 자정마다 실행토록 하기로 했다.
import schedule
import time
# 매일 자정마다 작업 실행
schedule.every().day.at("00:00").do(scheduling)
# 테스트용 한시간에 한 번씩 확인하기
schedule.every().hours.at("00:00").do(scheduling)
while True:
schedule.run_pending()
time.sleep(1)
이렇게 schedule을 활용하여 스케쥴링을 구현할 수 있다.
하지만 내 경우에는, 위에서도 말했지만, 코드수정으로 인한 서버다운을 원치않기 때문에 crontab을 이용하는 방법으로 바꾸게 되었다.
코드 보기(crontab 활용)
class CrontabView(APIView):
def post(self, request):
# 구독 자동갱신, 채팅기록 삭제, 자동구매확정
RelatedSubscriptionandChatandPoint.subscription_update()
RelatedSubscriptionandChatandPoint.chatlog_delete()
RelatedSubscriptionandChatandPoint.pointpaid()
return Response({"msg":"완료"}, status=status.HTTP_202_ACCEPTED)
이렇게 post api를 사용하는 것으로 바뀌었다.
ubuntu에서의 명령어:
- 작업 할당
crontab -e
위 커맨드를 입력하면 vim과 같은 텍스트 편집기가 열리는데(만약 첫 실행이면, nano사용할 것인지, vim사용할 것인지 물음) 텍스트 편집기를 이용해 작업을 할당하면 된다.
# 기본 실행하는 쉘의 종류
SHELL = bin/bash
# 매일 자정에 스케쥴링 진행
0 0 * * * curl -X POST https://example.com/{요청보낼 api주소}/
만약에 api 요청을 할 때 body에 넣을 데이터가 있다면 POST와 api 주소 사이에 -d 옵션을 사용하여 요청바디에 데이터를 추가해주면 된다..!!
- 할당된 작업리스트 확인
crontab -l
혹은 삭제할 일이 있다면..
- crontab 작업리스트 삭제
crontab -r
구독 관련 코드가 더 자세히 보고 싶다면?
2023.06.10 - [Project Portfolio] - [구독 해지예약 및 취소, 구독 재신청 구현]
'Project Portfolio' 카테고리의 다른 글
| [구독 해지예약 및 취소, 구독 재신청 구현] (0) | 2023.06.10 |
|---|---|
| [결제] KG이니시스 결제 구현하기 (feat. 포인트충전) (0) | 2023.06.09 |
| [JS] 달력 날짜 누르면 날짜에 해당하는 저축, 소비, 지출 불러오기 (0) | 2023.05.29 |
| [JS] 달력 만들기 (0) | 2023.05.26 |
| 장고 DRF 검색기능과 페이지네이션 (0) | 2023.05.10 |