Начну с объяснения архитектуры проекта. Есть бот, на aiogram, через которого создаются заказы. Заказы состоят из строк(товара), цены и идентификаторов принадлежности заказа.
Задача:
Скриптом обрабатывать все неоплаченные заказы и в случае, если заказ не оплачен уже больше чем N минут, то строки товара возвращаются в таблицу товара, а заказ удаляется.
Моя реализация:
while True:
users = MyUser.objects.all().exclude(bot_username='null')
now = timezone.now()
for admin_user_obj in users:
for order in User_purchase.objects.raw('SELECT id, time_created, chat_id, balance_to_return FROM user_purchases WHERE is_paid=FALSE and belongs=%s LIMIT 5', [admin_user_obj.id]):
if order.time_created + timezone.timedelta(minutes=admin_user_obj.booking_time) < now:
try:
bot_user = Bot_user.objects.get(belongs=admin_user_obj.id, chat_id=order.chat_id)
if order.balance_to_return:
bot_user.balance += order.balance_to_return
bot_user.active_orders -= 1
bot_user.save()
send_order_canceled(order, admin_user_obj)
for z in User_purchase.objects.raw('SELECT id, strings, item FROM user_purchases WHERE id=%s', [order.id]):
add_strings(z.item, z.strings)
except:
pass
order.delete()
Запросы на SQL, потому что иначе возникают ошибки MemoryError.
После запуска и мониторинга логов, скрипт начинает спамить мне строкой товара:
И клиент мне сообщил что его 1 строка товара превратилась в 23 миллиона, а несколько строк в брони превратились в 7 миллионов строк. Сказать что меня это удивило, ничего не сказать.
models.py
class User_purchase(models.Model):
class Meta:
db_table = 'user_purchases'
verbose_name = 'Платеж пользователя в боте'
verbose_name_plural = 'Платежи пользователей в боте'
chat_id = models.IntegerField()
belongs = models.IntegerField()
title = models.TextField()
strings = models.TextField()
amount = models.DecimalField(
decimal_places=2,
max_digits=10,
default=0
)
balance_to_return = models.DecimalField(
decimal_places=2,
max_digits=10,
default=0)
note = models.TextField(null=True, blank=True)
coupon = models.IntegerField(null=True, blank=True)
is_paid = models.BooleanField(null=True, blank=True, default=True)
item = models.IntegerField(null=True, blank=True)
time_created = models.DateTimeField(default=timezone.now)
time_of_commission = models.DateTimeField(default=timezone.now, null=True, blank=True)
docker-compose
db:
image: postgres:12.0-alpine
volumes:
- postgres_data:/var/lib/postgresql/data/
env_file:
- ./.env.prod.db
command: >
-c work_mem=512MB
-c maintenance_work_mem=256MB
-c max_wal_size=1GB
premium_daemon:
build: ./app
command: python manage.py premium_daemon
volumes:
- ./app/:/usr/src/app/
env_file:
- ./.env.prod
depends_on:
- db