Merge branch 'fix_celery_once_backend' into 'master'

Fix celery once not working properly

See merge request allianceauth/allianceauth!1246
This commit is contained in:
Ariel Rin 2020-08-25 06:13:59 +00:00
commit eadd959d95
2 changed files with 51 additions and 10 deletions

View File

@ -5,7 +5,6 @@ from django.contrib.auth.models import User
from .hooks import ServicesHook from .hooks import ServicesHook
from celery_once import QueueOnce as BaseTask, AlreadyQueued from celery_once import QueueOnce as BaseTask, AlreadyQueued
from django.core.cache import cache from django.core.cache import cache
from time import time
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@ -22,14 +21,9 @@ class DjangoBackend:
@staticmethod @staticmethod
def raise_or_lock(key, timeout): def raise_or_lock(key, timeout):
now = int(time()) acquired = cache.add(key=key, value="lock", timeout=timeout)
result = cache.get(key) if not acquired:
if result: raise AlreadyQueued(int(cache.ttl(key)))
remaining = int(result) - now
if remaining > 0:
raise AlreadyQueued(remaining)
else:
cache.set(key, now + timeout, timeout)
@staticmethod @staticmethod
def clear_lock(key): def clear_lock(key):

View File

@ -1,11 +1,15 @@
from unittest import mock from unittest import mock
from celery_once import AlreadyQueued
from django.core.cache import cache
from django.test import TestCase from django.test import TestCase
from allianceauth.tests.auth_utils import AuthUtils from allianceauth.tests.auth_utils import AuthUtils
from allianceauth.services.tasks import validate_services from allianceauth.services.tasks import validate_services
from ..tasks import DjangoBackend
class ServicesTasksTestCase(TestCase): class ServicesTasksTestCase(TestCase):
def setUp(self): def setUp(self):
@ -24,3 +28,46 @@ class ServicesTasksTestCase(TestCase):
self.assertTrue(svc.validate_user.called) self.assertTrue(svc.validate_user.called)
args, kwargs = svc.validate_user.call_args args, kwargs = svc.validate_user.call_args
self.assertEqual(self.member, args[0]) # Assert correct user is passed to service hook function self.assertEqual(self.member, args[0]) # Assert correct user is passed to service hook function
class TestDjangoBackend(TestCase):
TEST_KEY = "my-django-backend-test-key"
TIMEOUT = 1800
def setUp(self) -> None:
cache.delete(self.TEST_KEY)
self.backend = DjangoBackend(dict())
def test_can_get_lock(self):
"""
when lock can be acquired
then set it with timetout
"""
self.backend.raise_or_lock(self.TEST_KEY, self.TIMEOUT)
self.assertIsNotNone(cache.get(self.TEST_KEY))
self.assertAlmostEqual(cache.ttl(self.TEST_KEY), self.TIMEOUT, delta=2)
def test_when_cant_get_lock_raise_exception(self):
"""
when lock can bot be acquired
then raise AlreadyQueued exception with countdown
"""
self.backend.raise_or_lock(self.TEST_KEY, self.TIMEOUT)
try:
self.backend.raise_or_lock(self.TEST_KEY, self.TIMEOUT)
except Exception as ex:
self.assertIsInstance(ex, AlreadyQueued)
self.assertAlmostEqual(ex.countdown, self.TIMEOUT, delta=2)
def test_can_clear_lock(self):
"""
when a lock exists
then can get a new lock after clearing it
"""
self.backend.raise_or_lock(self.TEST_KEY, self.TIMEOUT)
self.backend.clear_lock(self.TEST_KEY)
self.backend.raise_or_lock(self.TEST_KEY, self.TIMEOUT)
self.assertIsNotNone(cache.get(self.TEST_KEY))