Misalkan saya punya model Event
. Saya ingin mengirim pemberitahuan (email, push, apa pun) ke semua pengguna yang diundang setelah acara berlalu. Sesuatu di sepanjang garis:
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")
Sekarang, tentu saja, bagian penting adalah meminta onEventElapsed
kapan saja timezone.now() >= event.end
. Perlu diingat, end
bisa beberapa bulan lagi dari tanggal saat ini.
Saya telah memikirkan dua cara dasar untuk melakukan ini:
Gunakan
cron
pekerjaan berkala (misalnya, setiap lima menit atau lebih) yang memeriksa apakah ada peristiwa yang berlalu dalam lima menit terakhir dan mengeksekusi metode saya.Gunakan
celery
dan jadwalkanonEventElapsed
menggunakaneta
parameter yang akan dijalankan di masa depan (dalamsave
metode model ).
Mempertimbangkan opsi 1, solusi potensial bisa jadi django-celery-beat
. Namun, sepertinya agak aneh untuk menjalankan tugas pada interval tetap untuk mengirim pemberitahuan. Selain itu saya menemukan masalah (potensial) yang (kemungkinan) akan menghasilkan solusi yang tidak terlalu elegan:
- Periksa setiap lima menit untuk acara yang telah berlalu dalam lima menit sebelumnya? tampaknya goyah, mungkin beberapa acara tidak terjawab (atau yang lain menerima pemberitahuan dua kali?). Workaroung potensial: tambahkan bidang boolean ke model yang disetel
True
setelah pemberitahuan dikirimkan.
Kemudian lagi, opsi 2 juga memiliki masalah:
- Jaga situasi secara manual saat acara dimulai / berakhir datetime dipindahkan. Saat menggunakan
celery
, seseorang harus menyimpantaskID
(mudah, ofc) dan mencabut tugas begitu tanggal telah berubah dan mengeluarkan tugas baru. Tetapi saya telah membaca, bahwa seledri memiliki masalah (khusus desain) ketika berhadapan dengan tugas-tugas yang dijalankan di masa depan: Masalah Terbuka pada github . Saya menyadari bagaimana ini terjadi dan mengapa itu semua hanya sepele untuk dipecahkan.
Sekarang, saya telah menemukan beberapa perpustakaan yang berpotensi memecahkan masalah saya:
- celery_longterm_scheduler (Tapi apakah ini berarti saya tidak dapat menggunakan seledri seperti yang akan saya lakukan sebelumnya, karena kelas Penjadwal differend? Ini juga terkait dengan kemungkinan penggunaan
django-celery-beat
... Menggunakan salah satu dari dua kerangka kerja, apakah masih mungkin untuk mengantre pekerjaan (yang hanya berjalan sedikit lebih lama tetapi tidak beberapa bulan lagi?) - django-apscheduler , menggunakan
apscheduler
. Namun, saya tidak dapat menemukan informasi tentang cara menangani tugas yang dijalankan di masa depan yang jauh.
Apakah ada kelemahan mendasar dengan cara saya mendekati ini? Saya senang atas masukan yang mungkin Anda miliki.
Perhatikan: Saya tahu ini kemungkinan didasarkan pada pendapat tertentu, namun, mungkin ada hal yang sangat mendasar yang saya lewatkan, terlepas dari apa yang dapat dianggap oleh beberapa orang sebagai jelek atau elegan.
sumber
Jawaban:
Kami melakukan hal seperti ini di perusahaan tempat saya bekerja, dan solusinya cukup sederhana.
Memiliki irama cron / seledri yang berjalan setiap jam untuk memeriksa apakah ada pemberitahuan yang perlu dikirim. Kemudian kirim pemberitahuan itu dan tandai sebagai selesai. Dengan cara ini, bahkan jika waktu pemberitahuan Anda bertahun-tahun ke depan, itu masih akan dikirim. Menggunakan ETA BUKAN cara untuk menunggu waktu yang sangat lama, cache / amqp Anda mungkin kehilangan data.
Anda dapat mengurangi interval Anda tergantung pada kebutuhan Anda, tetapi pastikan mereka tidak tumpang tindih.
Jika satu jam terlalu besar dari perbedaan waktu, maka yang dapat Anda lakukan adalah, jalankan penjadwal setiap jam. Logika akan seperti itu
Menggunakan metodologi itu akan membuat Anda berdua dunia terbaik (eta dan beat)
sumber