Skip to content

Clear throttle cache on ConsumerThrottleLimit.save #150

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Apr 25, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions main/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,5 @@


DURATION_MAPPING = {"minute": 60, "hour": 3600, "day": 86400, "week": 604800}

CONSUMER_THROTTLES_KEY = "consumer_throttles"
5 changes: 1 addition & 4 deletions main/consumer_throttles.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,12 @@
from django.core.cache import cache as default_cache
from django.core.exceptions import ImproperlyConfigured

from main.constants import DURATION_MAPPING
from main.constants import CONSUMER_THROTTLES_KEY, DURATION_MAPPING
from main.models import ConsumerThrottleLimit

log = logging.getLogger(__name__)


CONSUMER_THROTTLES_KEY = "consumer_throttles"


class AsyncBaseThrottle(ABC):
"""
Abstract class for throttling AsyncConsumer requests.
Expand Down
8 changes: 8 additions & 0 deletions main/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@
Classes related to models for main
"""

from django.core.cache import cache
from django.db.models import CharField, DateTimeField, IntegerField, Model
from django.db.models.query import QuerySet

from main.constants import CONSUMER_THROTTLES_KEY
from main.utils import now_in_utc


Expand Down Expand Up @@ -77,3 +79,9 @@ def __str__(self):
Auth {self.auth_limit}, \
Anon {self.anon_limit} \
per {self.interval}"

def save(self, **kwargs):
"""Override save to reset the throttles cache"""
cache.delete(CONSUMER_THROTTLES_KEY)
cache.close()
return super().save(**kwargs)
39 changes: 39 additions & 0 deletions main/models_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
"""main models tests"""

import pytest
from asgiref.sync import sync_to_async

from main.consumer_throttles import UserScopedRateThrottle
from main.factories import ConsumerThrottleLimitFactory


@pytest.mark.django_db
async def test_throttle_limit_save_reset_cache():
"""Saving changes to the throttle limit model should reset the cache"""
auth_limits = (20, 10)
anon_limits = (10, 5)
intervals = ("minute", "hour")

throttle_limit = await sync_to_async(ConsumerThrottleLimitFactory.create)(
auth_limit=auth_limits[0],
anon_limit=anon_limits[0],
interval=intervals[0],
)
scoped_throttle = UserScopedRateThrottle()
scoped_throttle.scope = throttle_limit.throttle_key
assert await scoped_throttle.get_rate() == {
"throttle_key": throttle_limit.throttle_key,
"auth_limit": auth_limits[0],
"anon_limit": anon_limits[0],
"interval": intervals[0],
}
throttle_limit.auth_limit = auth_limits[1]
throttle_limit.anon_limit = anon_limits[1]
throttle_limit.interval = intervals[1]
await throttle_limit.asave()
assert await scoped_throttle.get_rate() == {
"throttle_key": throttle_limit.throttle_key,
"auth_limit": auth_limits[1],
"anon_limit": anon_limits[1],
"interval": intervals[1],
}
Loading