Angenommen, ich habe ein Modell Event
. Ich möchte allen eingeladenen Benutzern nach Ablauf des Ereignisses eine Benachrichtigung (E-Mail, Push, was auch immer) senden. Etwas in der Art von:
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")
Jetzt ist es natürlich entscheidend, onEventElapsed
immer dann aufzurufen timezone.now() >= event.end
. Beachten Sie, end
dass Monate vom aktuellen Datum entfernt sein können.
Ich habe über zwei grundlegende Möglichkeiten nachgedacht:
Verwenden Sie einen regelmäßigen
cron
Job (z. B. alle fünf Minuten oder so), der überprüft, ob in den letzten fünf Minuten Ereignisse aufgetreten sind, und meine Methode ausführt.Verwenden
celery
und planen SieonEventElapsed
mit demeta
Parameter, der in Zukunft ausgeführt werden soll (innerhalb der Modellmethodesave
).
In Anbetracht von Option 1 könnte eine mögliche Lösung sein django-celery-beat
. Es erscheint jedoch etwas seltsam, eine Aufgabe in einem festgelegten Intervall zum Senden von Benachrichtigungen auszuführen. Außerdem habe ich ein (potenzielles) Problem gefunden, das (wahrscheinlich) zu einer nicht so eleganten Lösung führen würde:
- Alle fünf Minuten nach Ereignissen suchen, die in den letzten fünf Minuten vergangen sind? scheint wackelig, vielleicht werden einige Ereignisse verpasst (oder andere erhalten ihre Benachrichtigungen zweimal gesendet?). Potenzielle Arbeitsumgebung: Fügen Sie dem Modell ein boolesches Feld hinzu, das nach dem
True
Senden von Benachrichtigungen festgelegt wird.
Andererseits hat Option 2 auch seine Probleme:
- Kümmern Sie sich manuell um die Situation, in der die Start- / Endzeit eines Ereignisses verschoben wird. Bei der Verwendung
celery
müsste man dietaskID
(easy, ofc) speichern und die Aufgabe widerrufen, sobald sich die Daten geändert haben, und eine neue Aufgabe ausgeben. Aber ich habe gelesen, dass Sellerie ( designspezifische ) Probleme hat, wenn es um Aufgaben geht, die in der Zukunft ausgeführt werden: Open Issue on github . Mir ist klar, wie das passiert und warum es alles andere als trivial zu lösen ist.
Jetzt bin ich auf einige Bibliotheken gestoßen, die möglicherweise mein Problem lösen könnten:
- celery_longterm_scheduler ( Bedeutet dies jedoch, dass ich Sellerie aufgrund der unterschiedlichen Scheduler-Klasse nicht wie zuvor verwenden kann? Dies
django-celery-beat
hängt auch mit der möglichen Verwendung von ... zusammen. Mit einem der beiden Frameworks ist es weiterhin möglich, Jobs in die Warteschlange zu stellen (das sind nur ein bisschen länger, aber nicht Monate entfernt?) - django-apscheduler , verwendet
apscheduler
. Ich konnte jedoch keine Informationen darüber finden, wie Aufgaben behandelt werden sollen, die in ferner Zukunft ausgeführt werden.
Gibt es einen fundamentalen Fehler in der Art und Weise, wie ich mich dem nähere? Ich freue mich über alle Eingaben, die Sie haben könnten.
Hinweis: Ich weiß, dass dies wahrscheinlich auf einer gewissen Meinung basiert, aber vielleicht gibt es eine sehr grundlegende Sache, die ich übersehen habe, unabhängig davon, was von manchen als hässlich oder elegant angesehen werden könnte.
quelle
Antworten:
Wir machen so etwas in der Firma, für die ich arbeite, und die Lösung ist ganz einfach.
Lassen Sie einen Cronery / Beat-Beat ausführen, der stündlich ausgeführt wird, um zu überprüfen, ob eine Benachrichtigung gesendet werden muss. Senden Sie dann diese Benachrichtigungen und markieren Sie sie als erledigt. Auf diese Weise wird Ihre Benachrichtigungszeit auch dann gesendet, wenn sie Jahre im Voraus liegt. Die Verwendung von ETA ist NICHT der Weg für eine sehr lange Wartezeit. Ihr Cache / Amqp kann die Daten verlieren.
Sie können Ihr Intervall je nach Ihren Anforderungen reduzieren, aber stellen Sie sicher, dass sie sich nicht überlappen.
Wenn eine Stunde zu viel Zeitunterschied ist, können Sie jede Stunde einen Scheduler ausführen. Logik wäre so etwas wie
Mit dieser Methode erhalten Sie beide besten Welten (eta und beat).
quelle