Django ทำงานในอนาคตอันใกล้


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งานเป็นระยะ(พูดทุก ๆ ห้านาทีหรือมากกว่านั้น) ซึ่งจะตรวจสอบว่ามีเหตุการณ์ใด ๆ เกิดขึ้นภายในห้านาทีที่ผ่านมาและดำเนินการตามวิธีการของฉัน

  2. ใช้celeryและกำหนดเวลาonEventElapsedโดยใช้etaพารามิเตอร์ที่จะเรียกใช้ในอนาคต (ภายในsaveเมธอดmodel )

เมื่อพิจารณาถึงตัวเลือกที่ 1 ทางออกที่อาจเกิดขึ้นได้ django-celery-beatได้ อย่างไรก็ตามดูเหมือนว่าจะแปลกเล็กน้อยในการเรียกใช้งานในช่วงเวลาคงที่สำหรับการส่งการแจ้งเตือน นอกจากนี้ฉันยังพบกับปัญหา (ที่อาจเกิดขึ้น) ที่จะ (อาจ) ทำให้เกิดโซลูชันที่ไม่สง่างาม:

  • ตรวจสอบทุกห้านาทีสำหรับเหตุการณ์ที่ผ่านไปในห้านาทีก่อนหน้าหรือไม่ ดูเหมือนจะสั่นคลอนเหตุการณ์บางอย่างอาจพลาดไป ศักยภาพวิธีแก้ปัญหา: เพิ่มเขตข้อมูลบูลีนให้กับรูปแบบที่ตั้งค่าไว้Trueเมื่อส่งการแจ้งเตือนแล้ว

จากนั้นอีกครั้งตัวเลือก 2 ก็มีปัญหาเช่นกัน:

  • ดูแลสถานการณ์ด้วยตนเองเมื่อมีการย้ายช่วงเวลาเริ่มต้น / สิ้นสุดกิจกรรม เมื่อใช้celeryงานเราจะต้องเก็บtaskID(ง่าย, ofc) และเพิกถอนงานเมื่อวันที่มีการเปลี่ยนแปลงและออกงานใหม่ แต่ผมได้อ่านว่าคื่นฉ่ายมีปัญหา (การออกแบบที่เฉพาะเจาะจง) เมื่อต้องรับมือกับงานที่จะดำเนินการในอนาคต: เปิดออกบน GitHub ฉันรู้ว่าสิ่งนี้เกิดขึ้นได้อย่างไรและทำไมมันถึงเป็นทุกอย่างยกเว้นเรื่องไร้สาระที่จะแก้ไข

ตอนนี้ฉันเจอห้องสมุดที่อาจแก้ปัญหาได้แล้ว:

  • celery_longterm_scheduler (แต่นี่หมายความว่าฉันไม่สามารถใช้คื่นฉ่ายอย่างที่ฉันเคยมีมาก่อนเพราะชั้น Scheduler ที่แตกต่างกันนี้ยังเกี่ยวข้องกับการใช้งานที่เป็นไปได้ของdjango-celery-beat ... การใช้หนึ่งในสองเฟรมเวิร์ก ใช้เวลานานขึ้นเล็กน้อย แต่ไม่ถึงเดือนใช่หรือไม่)
  • Django-apscheduler , apschedulerการใช้งาน อย่างไรก็ตามฉันไม่สามารถหาข้อมูลใด ๆ เกี่ยวกับวิธีจัดการกับงานที่จะดำเนินการในอนาคตอันใกล้

มีข้อบกพร่องพื้นฐานกับวิธีที่ฉันเข้าใกล้นี้หรือไม่? ฉันดีใจที่ได้รับอินพุตจากคุณ

ข้อสังเกต: ฉันรู้ว่านี่น่าจะเป็นความเห็นที่มีอยู่บ้าง แต่อาจมีสิ่งพื้นฐานที่ฉันพลาดไปไม่ว่าจะมีคนคิดว่าน่าเกลียดหรือสง่างามอะไรก็ตาม


1
ฉันจะบอกว่าวิธีการของคุณขึ้นอยู่กับว่าหลังจากเหตุการณ์ที่ผ่านไปผู้ใช้ต้องการการแจ้งเตือนอย่างไร ฉันมีปัญหาคล้ายกันซึ่งผู้ใช้จำเป็นต้องรู้ในวันถัดไปสำหรับการนัดหมายที่ไม่ได้รับเมื่อวันก่อน ดังนั้นในกรณีนี้ฉันทำงาน cron ตอนเที่ยงคืนและตามที่คุณแนะนำฟิลด์บูลีนเพื่อแท็กว่ามีการส่งการแจ้งเตือนหรือไม่ มันเป็นวิธีที่ง่ายและราคาไม่แพงในการทำ
Hayden Eastwood

1
ในความคิดของฉันคำตอบคือเกี่ยวกับจำนวนเหตุการณ์ที่คุณต้องส่ง หากคุณมีหลายร้อยเหตุการณ์ที่จะส่งทุกวันมันไม่สำคัญว่าในอนาคตจะเป็นเหตุการณ์เดียว: การใช้โซลูชั่นแรก (ปรับเวลาการเกิดซ้ำตามความต้องการของคุณ) คุณสามารถเรียกใช้งานการอ่านข้อมูลที่อัปเดต
Dos

@ HaydenEastwood มันไม่สำคัญเลยที่คน ๆ นั้นจะได้รับมันทันที แต่ภายใน 2-5 นาทีภายในวันสุดท้ายควรจะดี คุณทำอะไรที่คล้ายกับ opion 1 ของฉันหรือเปล่า
Hafnernuss

1
@Hafnernuss ใช่ - ฉันคิดว่าการเรียก cron แบบง่าย ๆ กับเขตข้อมูลในฐานข้อมูลว่าการส่งข้อความจะเหมาะกับกรณีของคุณหรือไม่
Hayden Eastwood

1
Dramatiq ใช้ Aproach อีกกว่าคื่นฉ่ายเมื่อ sheduling งาน (หน่วยความจำไม่หิวในคนงาน) และผลงานในกรณีของคุณอาจดูdramatiq.io/guide.html#scheduling-messages แต่อย่างที่พวกเขาพูด - นายหน้าข้อความไม่ใช่ DB - เมื่อคุณต้องการวางแผนเหตุการณ์ระยะยาวทางออกแรกของคุณดีกว่า ดังนั้นคุณสามารถรวมทั้งสอง: ใส่กิจกรรมเป็น MB พูด 1 วันและโดยหมดอายุพวกเขาจะไปที่ฐานข้อมูลและจะถูกส่งผ่าน cron
frost-nzcr4

คำตอบ:


2

เรากำลังทำอะไรแบบนี้ใน บริษัท ที่ฉันทำงานให้และวิธีแก้ปัญหาก็ค่อนข้างง่าย

มีจังหวะ cron / คื่นฉ่ายที่ทำงานทุกชั่วโมงเพื่อตรวจสอบว่ามีการส่งการแจ้งเตือนใด ๆ หรือไม่ จากนั้นส่งการแจ้งเตือนเหล่านั้นและทำเครื่องหมายว่าเสร็จสิ้น ด้วยวิธีนี้แม้ว่าเวลาการแจ้งเตือนของคุณจะเป็นเวลาหลายปีก็จะยังคงถูกส่งไป การใช้ ETA ไม่ใช่วิธีการรอนานมากแคช / amqp ของคุณอาจสูญเสียข้อมูล

คุณสามารถลดช่วงเวลาของคุณขึ้นอยู่กับความต้องการของคุณ แต่ให้แน่ใจว่าพวกเขาไม่ทับซ้อนกัน

หากหนึ่งชั่วโมงมีความแตกต่างของเวลามากเกินไปสิ่งที่คุณสามารถทำได้คือเรียกใช้ตัวกำหนดตารางเวลาทุกชั่วโมง ลอจิกจะเป็นอะไรที่ชอบ

  1. เรียกใช้งาน (ให้เรียกงานตัวจัดตารางเวลานี้) ทุกชั่วโมงที่ได้รับการแจ้งเตือนทั้งหมดที่จำเป็นต้องส่งในชั่วโมงถัดไป (ผ่านการขึ้นฉ่าย) -
  2. กำหนดเวลาการแจ้งเตือนเหล่านั้นผ่าน Apply_async (eta) - นี่จะเป็นการส่งจริง

การใช้วิธีการนั้นจะทำให้คุณได้ทั้งโลกที่ดีที่สุด (กทพ. และจังหวะ)


1
ขอบคุณ. นั่นคือสิ่งที่ฉันได้ทำ!
Hafnernuss
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.