Harden auth, AI tutor, payments, and subscriptions
This commit is contained in:
@@ -29,29 +29,9 @@ class Command(BaseCommand):
|
||||
)
|
||||
|
||||
count = 0
|
||||
# ⚛️ atomic (بهازای هر رکورد، نه کل حلقه): این یک job دورهای رو
|
||||
# روی هزاران رکورد میتونه اجرا کنه. اگه کل حلقه یک atomic واحد
|
||||
# باشه، یک خطا روی رکورد هزارم، ابطالِ ۹۹۹ رکورد درستشدهی قبلی رو
|
||||
# هم rollback میکنه (و کل job باید از اول اجرا بشه). بهجاش هر
|
||||
# رکورد (save + signal که StatusChangeLog میسازه) جدا اتمیکه: یک
|
||||
# خطای مقطعی فقط همون رکورد رو نصفهکاره نگه نمیداره، رکوردهای
|
||||
# قبلی/بعدی مستقل میمونن.
|
||||
#
|
||||
# ⚛️🔒 اصلاح race condition (lost update): قبلاً همین آبجکتِ
|
||||
# progressِ خوندهشده از stale_qs (بدونِ قفل) مستقیماً save میشد.
|
||||
# اگه همزمان یک درخواستِ کاربرِ واقعی (touch_node_progress_on_answer
|
||||
# یا update_node_progress_on_lesson_completion در content/services.py،
|
||||
# هر دو با select_for_update) دقیقاً همون ردیف رو بهروزرسانی و
|
||||
# last_activity_at رو تازه میکرد، این کامند میتونست بدونِ اطلاع از
|
||||
# اون تغییرِ تازه، status رو با مقدارِ قدیمیِ در-حافظه به 'abandoned'
|
||||
# برگردونه — یعنی فعالیتِ تازهی کاربر توسط این جاب rollback/overwrite
|
||||
# میشد. حالا برای هر رکورد، فقط id از stale_qs گرفته میشه؛ ردیفِ
|
||||
# واقعی داخل transaction.atomic با select_for_update دوباره خونده و
|
||||
# قفل میشه (دقیقاً همون الگویی که مسیرِ کاربر استفاده میکنه)، و
|
||||
# شرطِ نصفهرها بودن (status='in_progress' و last_activity_at قدیمیتر
|
||||
# از threshold) بعد از گرفتنِ قفل دوباره چک میشه؛ اگه بین queryset
|
||||
# اولیه و گرفتنِ قفل، یک فعالیتِ کاربر همین ردیف رو تازه کرده باشه،
|
||||
# دیگه شرط برقرار نیست و این ردیف نادیده گرفته میشه (نه abandoned).
|
||||
# هر رکورد جدا اتمیک است (نه کل حلقه) تا خطای یک رکورد بقیه را rollback نکند.
|
||||
# id ها جدا گرفته میشوند و هر ردیف زیر select_for_update دوباره خوانده و
|
||||
# شرط abandoned بعد از قفل دوباره چک میشود، تا فعالیت همزمان کاربر overwrite نشود.
|
||||
stale_ids = list(stale_qs.values_list('id', flat=True))
|
||||
for progress_id in stale_ids:
|
||||
with transaction.atomic():
|
||||
|
||||
Reference in New Issue
Block a user