see the real client IP behind ArvanCloud, and mark all notifications read in one call
Production is ArvanCloud -> nginx -> gunicorn, but NUM_PROXIES was 1, so DRF took ArvanCloud's edge IP as the client: every guest and every OTP request behind one edge shared a single throttle bucket (20 guest sessions an hour for everyone). Default is now 2, and /api/health reports clientIp so the proxy count can be checked from outside. PATCH /api/notifications/read-all replaces the frontend's one-PATCH-per-item loop, which spent the shared "read" budget 75 requests at a time. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -6,7 +6,9 @@ from rest_framework.throttling import ScopedRateThrottle
|
||||
from rest_framework.views import APIView
|
||||
|
||||
from .models import Notification
|
||||
from .serializers import MarkReadResponseSerializer, NotificationListResponseSerializer
|
||||
from .serializers import (
|
||||
MarkAllReadResponseSerializer, MarkReadResponseSerializer, NotificationListResponseSerializer,
|
||||
)
|
||||
|
||||
# سقفِ تعدادِ اعلانِ برگشتی؛ جلوی رشدِ نامحدودِ پاسخ برای کاربرِ قدیمی رو
|
||||
# میگیره. صفحهبندیِ واقعی (cursor) وقتی فرانت infinite-scroll اضافه کنه.
|
||||
@@ -60,3 +62,25 @@ class NotificationMarkReadView(APIView):
|
||||
notification.save(update_fields=['is_read'])
|
||||
|
||||
return Response(MarkReadResponseSerializer({'success': True}).data)
|
||||
|
||||
|
||||
class NotificationMarkAllReadView(APIView):
|
||||
"""
|
||||
PATCH /api/notifications/read-all — همهی اعلانهای کاربر خواندهشده.
|
||||
|
||||
دکمهی «همه خوانده شد» پیش از این برای هر اعلان یک درخواستِ جدا میزد؛
|
||||
حسابی با ۷۵ اعلان یعنی ۷۵ درخواستِ همزمان که سهمِ throttleِ read را
|
||||
(همان که /home و بقیه مصرف میکنند) یکجا میخورد.
|
||||
"""
|
||||
|
||||
permission_classes = [IsAuthenticated]
|
||||
throttle_scope = 'read'
|
||||
throttle_classes = [GuestAwareReadThrottle]
|
||||
|
||||
@extend_schema(request=None, responses=MarkAllReadResponseSerializer,
|
||||
tags=['Notifications (notifications)'])
|
||||
def patch(self, request):
|
||||
updated = Notification.objects.filter(
|
||||
user_id=request.user.id, is_read=False,
|
||||
).update(is_read=True)
|
||||
return Response(MarkAllReadResponseSerializer({'success': True, 'updated': updated}).data)
|
||||
|
||||
Reference in New Issue
Block a user