Django uzak gelecekte görevler (muhtemelen) yürütüyor


9

Bir modelim olduğunu varsayalım Event. Etkinlik sona erdiğinde davet edilen tüm kullanıcılara bir bildirim (e-posta, push, ne olursa olsun) göndermek istiyorum. Çizgileri boyunca bir şey:

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")

Şimdi, elbette, önemli olan onEventElapsedher an çağırmaktır timezone.now() >= event.end. Unutmayın end, geçerli tarihten aylar uzakta olabilir.

Bunu yapmanın iki temel yolunu düşündüm:

  1. cronSon beş dakika içinde herhangi bir olayın geçip geçmediğini kontrol eden ve yöntemimi yürüten periyodik bir iş (örneğin, her beş dakikada bir) kullanın.

  2. Gelecekte çalıştırılacak parametreyi kullanarak (modeller yöntemi dahilinde ) kullanın celeryve zamanlayın .onEventElapsedetasave

Seçenek 1 dikkate alındığında, potansiyel bir çözüm olabilir django-celery-beat. Ancak, bir görevi bildirim göndermek için belirli bir aralıkta çalıştırmak biraz garip görünüyor. Ek olarak (muhtemelen) çok şık olmayan bir çözümle sonuçlanacak (potansiyel) bir sorunla karşılaştım:

  • Son beş dakikada geçen olaylar için her beş dakikada bir kontrol edilsin mi? titrek görünüyor, belki bazı olaylar kaçırılır (ya da diğerleri bildirimlerini iki kez gönderir?). Potansiyel geçici çözüm: Truebildirimler gönderildikten sonra modele ayarlanan bir boole alanı ekleyin .

Sonra tekrar, seçenek 2'nin de sorunları var:

  • Bir olay başlangıç ​​/ bitiş tarihinin taşındığı durumla el ile ilgilenin. Kullanırken celery, taskIDtarihler değiştikten sonra (easy, ofc) depolamak ve görevi iptal etmek ve yeni bir görev vermek gerekir. Ama okudum, kereviz gelecekte yürütülecek görevlerle uğraşırken (tasarıma özgü) problemleri var: Github'da Açık Sayı . Bunun nasıl olduğunu ve neden çözülmesi önemsiz olan her şeyin olduğunu anlıyorum.

Şimdi, sorunumu çözebilecek bazı kütüphanelere rastladım:

  • celery_longterm_scheduler (Ama bu daha önce olurdu gibi çünkü tiplerimiz Zamanlayıcı sınıfının, kereviz kullanamaz demektir? olası kullanım içine Bu da bağlar django-celery-beat... iki çerçeveler herhangi kullanarak, o (yani işleri sıraya hala mümkün biraz daha uzun sürüyor, ancak aylar değil mi?)
  • django-apscheduler , kullanır apscheduler. Ancak, uzak gelecekte yürütülecek görevleri nasıl ele alacağına dair herhangi bir bilgi bulamadım.

Buna yaklaşmamın temel bir kusuru var mı? Sahip olabileceğiniz herhangi bir giriş için memnunum.

Uyarı: Bunun muhtemelen bazı fikirlere dayanan bir fikir olduğunu biliyorum, ancak bazıları tarafından çirkin veya zarif olarak kabul edilebilecek ne olursa olsun kaçırdığım çok temel bir şey olabilir.


1
Yaklaşımınızın, geçen etkinlikten ne zaman sonra son kullanıcının bildirime ihtiyacı olduğuna bağlı olduğunu söyleyebilirim. Ben kullanıcı sadece önceki gün kaçırmış herhangi bir randevu için ertesi gün bilmek gerekiyordu benzer bir sorun yaşadım. Bu durumda, gece yarısı bir cron işi yaptım ve önerdiğiniz gibi bildirimlerin gönderilip gönderilmediğini etiketlemek için bir boole alanına sahiptim. Bunu yapmanın çok basit ve hesaplı olarak ucuz bir yoluydu.
Hayden Eastwood

1
Bence cevap, kaç tane etkinlik göndermeniz gerektiğiyle ilgili. Her gün gönderilecek yüzlerce etkinliğiniz varsa, gelecekte ne kadar uzakta olacağı önemli değildir: ilk çözümü kullanarak (tekrarlama süresini ihtiyaçlarınıza göre uyarlayarak) güncellenmiş verileri okuyarak görevi çalıştırabilirsiniz.
Dos

@HaydenEastwood Kişinin hemen alması çok önemli değil, ancak bitiş tarihi içinde 2-5 dakika içinde iyi olmalı. Yani benim opion 1'e benzer bir şey mi yaptın?
Hafnernuss

1
@Hafnernuss Evet - Sanırım mesajın gönderilip gönderilmeyeceği konusunda veritabanında bir alan bulunan basit bir cron çağrısı sizin durumunuz için iyi bir seçim olacaktır.
Hayden Eastwood

1
Dramatiq, görevleri döken (işçi üzerinde aç bellek değil) Kerevizden başka bir yaklaşım kullanır ve sizin durumunuzda çalışabilir, bkz. Dramatiq.io/guide.html#scheduling-messages . Ancak dedikleri gibi - Message Broker DB değil - uzun vadeli bir etkinlik planlamanız gerektiğinde ilk çözümünüz daha iyidir. Böylece her ikisini birleştirebilirsiniz: olayları MB olarak koyun, diyelim ki 1 güne kadar, sona erme ile DB'ye giderler ve cron yoluyla gönderilirler.
frost-nzcr4

Yanıtlar:


2

Çalıştığım şirkette böyle bir şey yapıyoruz ve çözüm oldukça basit.

Herhangi bir bildirim gönderilmesi gerekip gerekmediğini kontrol etmek için her saat çalışan bir cron / kereviz ritmi yaptırın. Ardından bu bildirimleri gönderin ve tamamlandı olarak işaretleyin. Bu şekilde, bildirim süreniz yıllarca olsa bile, yine de gönderilir. ETA kullanmak çok uzun bir bekleme süresi için DEĞİLDİR, önbellek / amqp'niz verileri kaybedebilir.

İhtiyaçlarınıza bağlı olarak aralığınızı azaltabilirsiniz, ancak üst üste gelmediklerinden emin olun.

Bir saat bir zaman farkından çok büyükse, yapabileceğiniz şey her saatte bir zamanlayıcı çalıştırmaktır. Mantık şöyle bir şey olurdu

  1. bir saat içinde gönderilmesi gereken tüm bildirimleri (kereviz ritmi ile) alan saatlik bir görev (bu zamanlayıcı görevini çağıralım)
  2. Bu bildirimleri Apply_async (eta) ile planla - bu gerçek gönderim olacak

Bu metodolojiyi kullanmak her ikinizin de en iyi dünyalarını elde etmenizi sağlayacaktır (eta ve beat)


1
Teşekkür ederim. Ben de tam olarak bunu yaptım!
Hafnernuss
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.