장고는 장래에 작업을 실행할 수 있습니다.


9

모델이 있다고 가정합니다 Event. 이벤트가 경과하면 초대 된 모든 사용자에게 알림 (이메일, 푸시 등)을 보내려고합니다. 다음과 같은 내용이 있습니다.

class Event(models.Model):
    start = models.DateTimeField(...)
    end = models.DateTimeField(...)
    invited = models.ManyToManyField(model=User)

    def onEventElapsed(self):
        for user in self.invited:
           my_notification_backend.sendMessage(target=user, message="Event has elapsed")

물론, 중요한 부분은 onEventElapsed언제 라도 호출하는 것 timezone.now() >= event.end입니다. 명심 end떨어져 현재 날짜에서 달 수 있습니다.

나는 이것을하는 두 가지 기본 방법에 대해 생각했습니다.

  1. cron지난 5 분 내에 이벤트가 경과했는지 확인하고 내 메소드를 실행 하는 주기적 작업 (예 : 5 분마다)을 사용하십시오.

  2. 나중에 실행될 모델을 사용하여 매개 변수를 사용 celery하고 스케줄 하십시오 .onEventElapsedetasave

옵션 1을 고려하면 가능한 해결책은 다음과 같습니다 django-celery-beat. 그러나 알림을 보내기 위해 일정 간격으로 작업을 실행하는 것은 약간 이상합니다. 또한 (아마도) 우아하지 않은 해결책을 초래할 수있는 (잠재적) 문제를 생각해 냈습니다.

  • 지난 5 분 동안 경과 한 이벤트가 있는지 5 분마다 확인 하시겠습니까? 흔들리는 것처럼 보일 수 있습니다. 일부 이벤트가 누락되었거나 다른 알림이 두 번 전송됩니다. 잠재적 해결 방법 : True알림이 전송 된 후 설정된 부울 필드를 모델에 추가하십시오 .

그런 다음 옵션 2에도 문제가 있습니다.

  • 이벤트 시작 / 종료 날짜 시간이 이동 된 상황을 수동으로 처리하십시오. 를 사용할 때 날짜가 변경되면 (easy, ofc) celery를 저장 taskID하고 작업을 취소하고 새 작업을 발행해야합니다. 그러나 셀러리는 미래에 실행되는 작업을 처리 할 때 셀러리에 (디자인 관련) 문제가 있음을 읽었습니다 .github의 Open Issue . 나는 이것이 어떻게 일어나는지 그리고 왜 해결하기가 사소한 것인지를 알고 있습니다.

이제 잠재적으로 내 문제를 해결할 수있는 라이브러리를 발견했습니다.

  • celery_longterm_scheduler (그러나 이것은 Differentend Scheduler 클래스로 인해 이전과 같이 셀러리를 사용할 수 없다는 것을 의미합니까? 이것은 또한 가능한 사용법과 관련이 있습니다 django-celery-beat... 두 프레임 워크 중 하나를 사용하면 작업을 대기열에 넣을 수 있습니까? 조금 더 오래 달렸지만 몇 달이 지나지 않았습니까?)
  • django-apscheduler 는을 사용합니다 apscheduler. 그러나 먼 미래에 실행되는 작업을 처리하는 방법에 대한 정보를 찾지 못했습니다.

내가 접근하는 방식에 근본적인 결함이 있습니까? 당신이 가진 모든 입력에 기뻐요.

주의 : 나는 이것이 어떤 견해에 근거한 것 같다는 것을 알고 있지만, 추악하거나 우아하다고 여겨지는 것에 관계없이 내가 놓친 매우 기본적인 것이있을 수 있습니다.


1
귀하의 접근 방식은 경과 된 이벤트가 끝난 후 최종 사용자에게 알림이 필요한 시간에 달려 있습니다. 비슷한 문제가 발생하여 사용자가 전날 누락 된 약속에 대해 다음 날만 알면됩니다. 따라서이 경우 자정에 크론 작업을 실행했으며 제안한대로 부울 필드를 사용하여 알림이 전송되었는지 여부를 태그했습니다. 그것은 매우 간단하고 계산적으로 저렴한 방법이었습니다.
헤이든 이스트우드

1
내 의견으로는, 당신이 보내야 할 사건의 수에 대한 대답입니다. 매일 수백 개의 이벤트가 전송되는 경우 미래의 단일 이벤트가 얼마나 먼지는 중요하지 않습니다. 첫 번째 솔루션을 사용하여 (필요에 따라 반복 시간을 조정) 업데이트 된 데이터를 읽는 작업을 실행할 수 있습니다.
Dos

@HaydenEastwood 사람이 즉시 수령하는 것이 중요하지는 않지만 종료일 내에 2-5 분 이내에는 괜찮습니다. 그래서 당신은 내 opion 1과 비슷한 것을 했습니까?
Hafnernuss

1
@Hafnernuss 예-메시지가 전송되었는지 여부에 대한 데이터베이스의 필드를 사용한 간단한 cron 호출이 귀하의 경우에 적합하다고 생각합니다.
헤이든 이스트우드

1
Dramatiq은 작업을 처리 할 때 (작업자에게 메모리가 고갈되지 않음) Celery 이외의 다른 방법을 사용하며 귀하의 경우에는 효과가있을 수 있습니다 ( dramatiq.io/guide.html#scheduling-messages 참조) . 그러나 그들이 말했듯이 (메시지 브로커는 DB가 아닙니다) 장기적인 이벤트를 계획해야 할 때 첫 번째 솔루션이 더 좋습니다. 따라서 두 가지를 결합 할 수 있습니다. 이벤트를 MB 단위로 (예 : 1 일), 만료하면 DB로 이동하여 cron을 통해 전송됩니다.
frost-nzcr4

답변:


2

우리는 내가 일하는 회사에서 이와 같은 일을하고 있으며 솔루션은 매우 간단합니다.

알림을 보내야하는지 확인하기 위해 1 시간마다 실행되는 크론 / 셀러리 비트를 사용하십시오. 그런 다음 해당 알림을 보내고 완료로 표시하십시오. 이렇게하면 알림 시간이 몇 년이 걸리더라도 여전히 전송됩니다. ETA를 사용하는 것은 대기 시간이 길지 않기 때문에 캐시 / amqp가 데이터를 잃을 수도 있습니다.

필요에 따라 간격을 줄일 수 있지만 겹치지 않도록하십시오.

한 시간이 너무 큰 시차이면, 매 시간마다 스케줄러를 실행하십시오. 논리는 다음과 같습니다

  1. 매시간마다 (셀러리 비트를 통해) 보내야하는 모든 알림을받는 작업 (이 스케줄러 작업이라고 함)을 매시간 실행합니다.
  2. apply_async (eta)를 통해 알림을 예약합니다. 실제 전송이됩니다.

이 방법론을 사용하면 최고의 세계 (에타와 비트)를 얻을 수 있습니다.


1
감사합니다. 바로 내가 한 일입니다!
Hafnernuss
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.