make streaks and the leaderboard live, and stop three AI chats from freezing the API
Found in a deeper pass over what the frontend's flow actually touches:
- Nothing in the app ever wrote StreakRecord: "days in a row" was 0 forever
for every real user. Answers and lesson/island completions now record the
day (Tehran time); a broken chain shows 0. A streak error never fails the
answer itself.
- /api/leaderboard only changed when someone ran rebuild_leaderboard by
hand. It is now computed live (60s cache); weekly counts island XP too.
- gunicorn ran 3 sync workers with a 30s timeout, so every "ask Pi" stream
pinned a whole worker (~10s, GapGPT buffers the answer) and three at once
queued the entire API. gunicorn.conf.py (read automatically from the
working directory) switches to gthread, 8 threads, 120s timeout.
- Every /api/ response now says Cache-Control: private, no-store, so turning
on caching in the ArvanCloud panel can never serve one student another's data.
- /api/user/summary named no active plan ever ("subscription app not
implemented yet" had long stopped being true).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
28
gunicorn.conf.py
Normal file
28
gunicorn.conf.py
Normal file
@@ -0,0 +1,28 @@
|
||||
"""
|
||||
تنظیماتِ gunicorn — خودِ gunicorn این فایل را از پوشهی کاری
|
||||
(WorkingDirectory=~/mathapp-v2 در unitِ systemd) خودکار میخواند، پس بدونِ
|
||||
دست زدن به /etc با همان deploy.sh به سرور میرسد. آرگومانهای خطِ فرمانِ
|
||||
unit (مثلِ `--workers 3` و `--bind`) بر این فایل مقدماند.
|
||||
|
||||
چرا لازم شد (۲۰۲۶-۰۹-۲۴): unit با workerهای sync و timeoutِ پیشفرضِ ۳۰
|
||||
ثانیه اجرا میشد. هر استریمِ «از پی بپرس» یک worker را تا پایانِ جواب (~۱۰
|
||||
ثانیه، چون GapGPT خودش تا آماده شدنِ کلِ جواب نگه میدارد) اشغال میکرد؛ سه
|
||||
دانشآموزِ همزمان با دستیار یعنی بقیهی اپ — نقشه، آزمون، همهچیز — در صف.
|
||||
جوابِ بالای ۳۰ ثانیه هم وسطِ کار کشته میشد.
|
||||
|
||||
gthread هر worker را چند نخی میکند: ۳ worker × ۸ نخ = ۲۴ درخواستِ همزمان.
|
||||
کدِ جنگو برای نخ امن است و SQLite با `OPTIONS.timeout=20` نوشتنِ همزمان را
|
||||
تحمل میکند. timeout در gthread به ضربانِ خودِ worker است، نه طولِ هر
|
||||
درخواست، پس استریمِ طولانی دیگر کشته نمیشود.
|
||||
"""
|
||||
|
||||
worker_class = 'gthread'
|
||||
threads = 8
|
||||
timeout = 120
|
||||
graceful_timeout = 30
|
||||
keepalive = 5
|
||||
|
||||
# worker بعد از چند هزار درخواست تازه میشود تا نشتِ حافظهی احتمالی جمع
|
||||
# نشود؛ jitter نمیگذارد هر سه با هم ریاستارت شوند.
|
||||
max_requests = 2000
|
||||
max_requests_jitter = 200
|
||||
Reference in New Issue
Block a user