Load test of 1000 players on the server: CPU is the ceiling (~135 req/s); player-simulation tools

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-13 19:48:00 +03:30
parent ba4ecff29e
commit e3c8962b7b
5 changed files with 150 additions and 0 deletions

View File

@@ -0,0 +1,31 @@
# manage.py shell -c "exec(open('tools/loadtest/mkplayers.py').read())" env: LT_N, LT_PREFIX
# Test players: fake 0900... phones, an active subscription (no paywall, unlimited hearts), a token,
# and for each one island of its grade with that island's questions and option ids.
import json, os, random
from datetime import timedelta
from django.utils import timezone
from accounts.authentication import issue_access_token
from accounts.models import User
from content.models import Node, Question
from subscription.models import Subscription
N = int(os.environ['LT_N']); PREFIX = os.environ['LT_PREFIX']
rnd = random.Random(11)
GRADES = [8, 9, 10, 11, 12, 4, 5, 6, 7, 3]
pool = {}
for g in GRADES:
nodes = []
for node in Node.objects.filter(unit__grade_id=g).order_by('?')[:40]:
qs = list(Question.objects.filter(lesson__node=node).prefetch_related('choices')[:6])
if len(qs) >= 4:
nodes.append({'nodeId': node.id, 'lessonId': qs[0].lesson_id,
'questions': [{'id': q.id, 'options': [c.id for c in q.choices.all()]} for q in qs]})
pool[g] = nodes
out = []
exp = timezone.now() + timedelta(days=1)
for i in range(N):
g = GRADES[i % len(GRADES)]
u, _ = User.objects.get_or_create(phone=f'{PREFIX}{i:04d}', defaults={'name': f'تست بار {i}', 'grade_id': g})
Subscription.objects.update_or_create(user_id=u.id, defaults={'status': 'active', 'expires_at': exp})
out.append({'userId': u.id, 'token': issue_access_token(u.id), 'grade': g, **rnd.choice(pool[g])})
print('LTJSON' + json.dumps(out))