Skip to content

Commit 4ef2279

Browse files
committed
Add REQUEST_ID_SUBCLASSES
1 parent 27fdb93 commit 4ef2279

File tree

4 files changed

+38
-28
lines changed

4 files changed

+38
-28
lines changed

cvat/apps/redis_handler/apps.py

+26
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55

66
from contextlib import suppress
7+
from typing import cast
78

89
from django.apps import AppConfig
910
from django.conf import settings
@@ -23,10 +24,17 @@ def __getitem__(self, key: str | tuple) -> str:
2324
ACTION_TO_QUEUE = LayeredKeyDict()
2425
QUEUE_TO_PARSED_JOB_ID_CLS = {}
2526

27+
REQUEST_ID_SUBCLASSES = set()
28+
2629

2730
def initialize_mappings():
2831
from cvat.apps.redis_handler.rq import RequestId
2932

33+
def init_subclasses(cur_cls: type[RequestId] = RequestId):
34+
for subclass in cur_cls.__subclasses__():
35+
REQUEST_ID_SUBCLASSES.add(subclass)
36+
init_subclasses(subclass)
37+
3038
for queue_name, queue_conf in settings.RQ_QUEUES.items():
3139
if path_to_parsed_job_id_cls := queue_conf.get("PARSED_JOB_ID_CLASS"):
3240
parsed_job_id_cls = import_string(path_to_parsed_job_id_cls)
@@ -37,10 +45,28 @@ def initialize_mappings():
3745
)
3846

3947
for queue_selector in parsed_job_id_cls.QUEUE_SELECTORS:
48+
if not isinstance(queue_selector, (tuple, str)):
49+
raise ImproperlyConfigured("Wrong queue selector, must be either tuple or str")
4050
ACTION_TO_QUEUE[queue_selector] = queue_name
4151

4252
QUEUE_TO_PARSED_JOB_ID_CLS[queue_name] = parsed_job_id_cls
4353

54+
init_subclasses()
55+
# check that each subclass that has QUEUE_SELECTORS can be used to determine the queue
56+
for subclass in REQUEST_ID_SUBCLASSES:
57+
subclass = cast(RequestId, subclass)
58+
if subclass.LEGACY_FORMAT_PATTERNS and not subclass.QUEUE_SELECTORS:
59+
raise ImproperlyConfigured(
60+
f"Subclass {subclass.__name__} has LEGACY_FORMAT_PATTERNS - QUEUE_SELECTORS must be defined"
61+
)
62+
63+
if subclass.QUEUE_SELECTORS:
64+
for queue_selector in subclass.QUEUE_SELECTORS:
65+
if not ACTION_TO_QUEUE.get(queue_selector):
66+
raise ImproperlyConfigured(
67+
f"Queue selector {queue_selector!r} for the class {subclass.__name__!r} is missed in the queue configuration"
68+
)
69+
4470

4571
class RedisHandlerConfig(AppConfig):
4672
name = "cvat.apps.redis_handler"

cvat/apps/redis_handler/rq.py

+9-25
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,14 @@
77
from uuid import UUID
88

99
import attrs
10-
from django.core.exceptions import ImproperlyConfigured
1110
from django.utils.html import escape
1211
from rq.job import Job as RQJob
1312

14-
from cvat.apps.redis_handler.apps import ACTION_TO_QUEUE, QUEUE_TO_PARSED_JOB_ID_CLS
13+
from cvat.apps.redis_handler.apps import (
14+
ACTION_TO_QUEUE,
15+
QUEUE_TO_PARSED_JOB_ID_CLS,
16+
REQUEST_ID_SUBCLASSES,
17+
)
1518

1619

1720
class IncorrectRequestIdError(ValueError):
@@ -58,7 +61,7 @@ class RequestId:
5861
default=_default_from_class_attr("ACTION_DEFAULT_VALUE"),
5962
)
6063
ACTION_ALLOWED_VALUES: ClassVar[tuple[str]]
61-
QUEUE_SELECTORS: ClassVar[tuple]
64+
QUEUE_SELECTORS: ClassVar[tuple] = ()
6265

6366
@action.validator
6467
def validate_action(self, attribute: attrs.Attribute, value: Any):
@@ -128,16 +131,10 @@ def parse(
128131
) -> tuple[RequestId, str]:
129132

130133
actual_cls = cls
131-
subclasses = set()
132134
queue: str | None = None
133135
dict_repr = {}
134136
fragments = {}
135137

136-
def init_subclasses(cur_cls: type[RequestId] = RequestId):
137-
for subclass in cur_cls.__subclasses__():
138-
subclasses.add(subclass)
139-
init_subclasses(subclass)
140-
141138
try:
142139
# try to parse ID as key=value pairs (newly introduced format)
143140
fragments = dict(urllib.parse.parse_qsl(request_id))
@@ -151,12 +148,7 @@ def init_subclasses(cur_cls: type[RequestId] = RequestId):
151148

152149
match: re.Match | None = None
153150

154-
if cls is RequestId:
155-
init_subclasses()
156-
else:
157-
subclasses = (cls,)
158-
159-
for subclass in subclasses:
151+
for subclass in REQUEST_ID_SUBCLASSES if cls is RequestId else (cls,):
160152
for pattern in subclass.LEGACY_FORMAT_PATTERNS:
161153
match = re.match(pattern, request_id)
162154
if match:
@@ -169,14 +161,9 @@ def init_subclasses(cur_cls: type[RequestId] = RequestId):
169161
f"Unable to parse request ID: {escape(request_id)!r}"
170162
)
171163

172-
queue = ACTION_TO_QUEUE.get(
164+
queue = ACTION_TO_QUEUE[
173165
actual_cls.QUEUE_SELECTORS[0]
174-
) # each selector match the same queue
175-
if not queue:
176-
raise ImproperlyConfigured(
177-
"Job ID class must be set in the related queue config"
178-
)
179-
166+
] # each selector match the same queue
180167
fragments = match.groupdict()
181168
# "." was replaced with "@" in previous format
182169
if "format" in fragments:
@@ -201,9 +188,6 @@ def init_subclasses(cur_cls: type[RequestId] = RequestId):
201188
result = actual_cls(**dict_repr)
202189

203190
return (result, queue)
204-
205-
except ImproperlyConfigured:
206-
raise
207191
except Exception as ex:
208192
raise IncorrectRequestIdError from ex
209193

cvat/apps/redis_handler/serializers.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
from uuid import UUID
1111

1212
import rq.defaults as rq_defaults
13+
from django.db.models import TextChoices
1314
from django.utils import timezone
1415
from drf_spectacular.utils import extend_schema_field
1516
from rest_framework import serializers
@@ -23,10 +24,10 @@
2324
from cvat.apps.engine.utils import parse_exception_message
2425
from cvat.apps.lambda_manager.rq import LambdaRQMeta
2526
from cvat.apps.redis_handler.rq import CustomRQJob, RequestId
26-
from django.db.models import TextChoices
2727

2828
slogger = ServerLogManager(__name__)
2929

30+
3031
class RequestStatus(TextChoices):
3132
QUEUED = "queued"
3233
STARTED = "started"

cvat/apps/redis_handler/views.py

+1-2
Original file line numberDiff line numberDiff line change
@@ -23,12 +23,11 @@
2323
NonModelSimpleFilter,
2424
)
2525
from cvat.apps.engine.log import ServerLogManager
26-
from cvat.apps.redis_handler.serializers import RequestStatus
2726
from cvat.apps.engine.rq import is_rq_job_owner
2827
from cvat.apps.engine.types import ExtendedRequest
2928
from cvat.apps.redis_handler.apps import ACTION_TO_QUEUE
3029
from cvat.apps.redis_handler.rq import CustomRQJob, RequestId
31-
from cvat.apps.redis_handler.serializers import RequestSerializer
30+
from cvat.apps.redis_handler.serializers import RequestSerializer, RequestStatus
3231

3332
slogger = ServerLogManager(__name__)
3433

0 commit comments

Comments
 (0)