현제의 현재이야기

[OSOD] 자동 메일 api, Apscheduler 본문

DRF/OSOD

[OSOD] 자동 메일 api, Apscheduler

현재의 현제 2023. 4. 9. 17:14

여태 매번 아침에 일어나서 메일 api를 직접 get해서 구독 메일을 회원들에게 뿌렸었다.

너무 귀찮고 DEBUG = TRUE로 해놨어서 누가 자꾸 api를 접속해서 무단으로 메일을 부리는 상황이 포착됐다. 이 얼마나 소름이 돋는가.

정말 악질인게 예전 구독 메일 엔드포인트였던 sendmail/ 을 치는 것을 보아 정말 사람이 접속해서 시도한 것이었다. 난 저때 폰도 안하고 컴도 안하고 있었음. 그래서 귀찮음 해결 + api 접속을 막기 위해서 자동 메일 api를 한시 빨리 개발햇어야 됐다.

 

pip install APScheduler를 해준다. 여러가지 뻘짓하다가(django-cron, schduler 등등..) sudo 및 cron을 사용하지 않아도 되는 스케줄러 발견.

django-cron은 로컬에서는 됐었는데 배포 후 서버에서 잘 작동되지 않았다. sudo 권한이 있어야 되는데 Paas에서는 터미널에서 뭐 하지마라고 하더라고., 실제로 sudo 명령이 안되었었다.

 

accounts/apps.py

from django.apps import AppConfig
from django.conf import settings


class AccountsConfig(AppConfig):

    default_auto_field = 'django.db.models.BigAutoField'
    name = 'accounts'

    def ready(self):
        from .scheduler import MyScheduler
        scheduler = MyScheduler()
        scheduler.scheduler.start()
  • 우선 apps.py를 통해서 서버가 돌아갈 때 스케쥴러를 불러오기 위해서 이런 코드를 작성해야 한다.
  • 중요한게 from.scheduler import MyScheduler를 먼저하게 되면 앱 시작 전에 import를 하기 때문에 오류가 발생한다. 그래서 위치가 중요함.
  • 그렇게 scheduler를 실행

accounts/scheduler.py

from apscheduler.schedulers.background import BackgroundScheduler
from .email import SubMailView
from django.test import RequestFactory
from django.http import HttpRequest

class MyScheduler: 
    def __init__(self):
        self.scheduler = BackgroundScheduler(max_instances=1)
        self.is_running = False  # 스케줄러 실행 여부
        self.job_id = 'my_job_id'
        self.scheduler.add_job(
            self.my_job, 
            'cron',
            day_of_week='*',
            hour=6,
            minute=30,
            second=00,
            id=self.job_id
        )
        self.sub_mail_view = SubMailView()
    def my_job(self):
        if self.is_running:  # 이미 실행중인 경우
            return
        try:
            self.is_running = True  # 스케줄러 실행 중으로 변경
            self.sub_mail_view.get(request=None)

        except Exception as e:
            print(e)
        finally:
            self.is_running = False  # 스케줄러 실행 종료로 변경
            self.scheduler.remove_job(self.job_id)
  • 자꾸만 함수가 두번 불러지길래 이런 뻘짓도 하였다. (결국 소용 없던 짓)
  • 우선 my_job()이 중복으로 실행되는 것을 방지하기 위해 is_running과 remove_job으로 실행과 삭제까지 트랜젝션을 유지하려고 노력하였다.
  • 그럼에도 불구하고 자꾸만 메일이 두번 보내지길래 화가나서 구글링을 시도
python manage.py runserver 0.0.0.0:8000 --noreload
  • 해결 방법이었다. 뭐 대충 읽어보면 앱이 시작될 때 한번 실행, 다시 한번 실행 된다나 뭐라나
  • 그래서 noreload로 서버를 배포함

오늘 수정을 마쳤는데, 과연 6시 반에 하나만 보내질지..

Comments