Signed payment links, hashed refresh tokens, login-only leaderboard, load test tools
- /api/payment/orders/{id}/pay requires the short-lived signature that paymentUrl carries;
without it (or with another order's) it is the same 404 as an unknown order
- Session.refresh_token stores the SHA-256 of the token; migration accounts.0007 hashes the
existing rows so tokens clients already hold keep working
- /api/leaderboard requires a token (guests have one); names of children were scrapable
- RAG mock only for `manage.py test`, not any command with an argument named "test"
- tools/loadtest: user factory, load generator, fake GapGPT+Qdrant, with method notes
- security-before-production.md lists only open items; closed ones become a guards table
with the tests that hold them. Comments describe current behaviour, not history
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
41
tools/loadtest/README.md
Normal file
41
tools/loadtest/README.md
Normal file
@@ -0,0 +1,41 @@
|
||||
# لودتستِ دستیار
|
||||
|
||||
سه اسکریپت، برای اینکه «چند دانشآموزِ همزمان» هر بار با یک روش سنجیده شود. خروجیِ هر اجرا یک
|
||||
JSON است با زمانِ هر پرسش و هر درخواستِ صفحهی عادی؛ جمعبندی در خودِ خروجیِ ترمینال چاپ میشود.
|
||||
|
||||
| فایل | کار |
|
||||
|---|---|
|
||||
| `mkusers.py` | کاربرانِ آزمایشیِ غیرمهمان (شمارهی جعلیِ `0900…`، بیپیامک، بیسیگنال) با توکن و سه سوالِ متفاوت از بانکِ سوال برای هر کدام |
|
||||
| `loadtest.py` | N نفر همزمان میپرسند (استریم، دقیقاً مثلِ فرانت) و B نفرِ دیگر در خانه/آزمون/خلاصه/سهمیه میچرخند |
|
||||
| `fake_upstream.py` | جایگزینِ GapGPT و Qdrant برای آزمایشگاه: embedding، جوابِ استریم با زمانِ لاگنرمال (پیشفرض: میانهی ۵٫۲ و صدکِ ۹۰ِ ۱۳ ثانیه، از جوابهای واقعیِ سرور) و جستوجوی Qdrant |
|
||||
|
||||
## آزمایشگاه (بیهزینه، روی لپتاپ)
|
||||
|
||||
روی یک کپی از پروژه اجرا کنید تا دیتابیسِ اصلیِ لوکال پر نشود. Qdrant هم شبیهسازی میشود، چون
|
||||
از لپتاپ پهنای باندِ بالارفتن (هر بردار ~۳۰ کیلوبایت) جستوجوها را سریالی نشان میدهد؛ از خودِ
|
||||
سرور ۲۰ جستوجوی همزمان ۰٫۲۶ ثانیه است.
|
||||
|
||||
```bash
|
||||
python tools/loadtest/fake_upstream.py & # :8901 (FAKE_SIGMA=0 یعنی همیشه ۵٫۲ ثانیه)
|
||||
export DJANGO_DEBUG=0 CACHE_URL= NUM_PROXIES=0 AI_DAILY_QUOTA_FREE=1000 HEARTS_ENFORCED=0 RAG_FORCE_MOCK=0 \
|
||||
DJANGO_ALLOWED_HOSTS=127.0.0.1 OPENAI_BASE_URL=http://127.0.0.1:8901/v1 OPENAI_API_KEY=x \
|
||||
QDRANT_URL=http://127.0.0.1:8901 QDRANT_API_KEY=x
|
||||
LT_N=150 python manage.py shell -c "exec(open('tools/loadtest/mkusers.py').read())" | grep ^LTJSON | cut -c7- > users.json
|
||||
gunicorn --bind 127.0.0.1:8800 config.wsgi:application & # همان gunicorn.conf.py ِ سرور
|
||||
python tools/loadtest/loadtest.py http://127.0.0.1:8800 users.json 50 10 0 out.json --writes
|
||||
```
|
||||
|
||||
پیش از هر اجرا gunicorn را از نو بالا بیاورید (کشِ جوابِ هر worker خالی شود) و مطمئن شوید پروسهی
|
||||
قبلی واقعاً رفته است؛ وگرنه سوالهای تکراری از کش در ۰٫۱ ثانیه جواب میگیرند و عدد دروغ میگوید.
|
||||
|
||||
## سرورِ اصلی (هزینهی واقعی: ~۰٫۱۸ سنت برای هر جواب)
|
||||
|
||||
۱. بکاپ از دیتابیس (`docs/operations.md`). ۲. کاربرانِ آزمایشی را روی سرور با `mkusers.py` بسازید
|
||||
(`LT_PREFIX` یک پیشوندِ جعلی که روی سرور نیست) و خروجی را فقط در یک فایلِ 600 نگه دارید.
|
||||
۳. `loadtest.py` را با `https://mathapi.tadrisino2.ir` و بدونِ `--writes` اجرا کنید.
|
||||
۴. زمانِ داخلِ GapGPT برای هر پیام در `ai_tutor.Message.latency_ms` است؛ اختلافِ آن با زمانِ کلاینت
|
||||
یعنی کارِ سرورِ ما و صفِ انتظار برای نخِ آزاد. ۵. `manage.py delete_users --ids … --yes` و پاک کردنِ
|
||||
فایلِ توکنها.
|
||||
|
||||
سقفِ ساعتیِ دستیار برای مهمانها بر اساسِ IP است؛ با کاربرِ مهمان از یک ماشین بیش از ~۲۰ پرسش در
|
||||
ساعت ممکن نیست، برای همین `mkusers.py` کاربرِ غیرمهمان میسازد.
|
||||
Reference in New Issue
Block a user