В коде неверен lookup is_null, дата не присваивается объектам, а offset пропустит записи после уменьшения выборки. Отправка Telegram и обновление БД также не образуют одну транзакцию.
class Order(models.Model):
В коде неверен lookup is_null, дата не присваивается объектам, а offset пропустит записи после уменьшения выборки. Отправка Telegram и обновление БД также не образуют одну транзакцию.
Короткий ответ
Что ответить на собеседовании
Подробный разбор
Ответ с пояснениями
Условие
class Order(models.Model): status = models.CharField(verbose_name='Статус') completed_date = models.DateTimeField(null=True)
def send_message(order: Order): # Отправляет сообщение в ТГ ...
def check_cancelled_orders(): batch = 10000 offset = 0
while True:
cancelled_orders = Order.objects.filter(
status='cancelled', completed_date__is_null=True
)[offset: offset+batch]
if not cancelled_orders:
break
offset += batch
completed_date = now()
for order in cancelled_orders:
send_message(order)
Order.objects.bulk_update(cancelled_orders, ['completed_date'])
Ответ
В коде неверен lookup is_null, дата не присваивается объектам, а offset пропустит записи после уменьшения выборки. Отправка Telegram и обновление БД также не образуют одну транзакцию.
Минимальная правка для одного worker:
from django.utils import timezone
def check_cancelled_orders():
while True:
orders = list(Order.objects.filter(
status='cancelled', completed_date__isnull=True,
).order_by('pk')[:100])
if not orders:
return
for order in orders:
send_message(order)
order.completed_date = timezone.now()
order.save(update_fields=['completed_date'])
Order и send_message взяты из условия. Выборка каждый раз начинается с оставшихся записей, без offset. При сбое после отправки, но до сохранения возможен повтор сообщения. Для production нужны отдельное состояние доставки/outbox и защита от нескольких workers; exactly-once без поддержки получателя не гарантируется. Размер батча и поля модели проверяют отдельно.