Skip to content

Commit

Permalink
Don't enforce UUIDs for task ids (#120)
Browse files Browse the repository at this point in the history
Still used for DB backend, since it has some DB engine optimisations. The rest can be simple opaque strings
  • Loading branch information
RealOrangeOne authored Nov 21, 2024
1 parent 80f22bc commit 1e3f238
Show file tree
Hide file tree
Showing 5 changed files with 30 additions and 6 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,8 @@ result_id = result.id
calculate_meaning_of_life.get_result(result_id)
```

A result `id` should be considered an opaque string, whose length could be up to 64 characters. ID generation is backend-specific.

Only tasks of the same type can be retrieved this way. To retrieve the result of any task, you can call `get_result` on the backend:

```python
Expand Down
5 changes: 2 additions & 3 deletions django_tasks/backends/dummy.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
from copy import deepcopy
from functools import partial
from typing import List, TypeVar
from uuid import uuid4

from django.db import transaction
from django.utils import timezone
Expand All @@ -10,7 +9,7 @@
from django_tasks.exceptions import ResultDoesNotExist
from django_tasks.signals import task_enqueued
from django_tasks.task import ResultStatus, Task, TaskResult
from django_tasks.utils import json_normalize
from django_tasks.utils import get_random_id, json_normalize

from .base import BaseTaskBackend

Expand Down Expand Up @@ -40,7 +39,7 @@ def enqueue(

result = TaskResult[T](
task=task,
id=str(uuid4()),
id=get_random_id(),
status=ResultStatus.NEW,
enqueued_at=None,
started_at=None,
Expand Down
5 changes: 2 additions & 3 deletions django_tasks/backends/immediate.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
from functools import partial
from inspect import iscoroutinefunction
from typing import TypeVar
from uuid import uuid4

from asgiref.sync import async_to_sync
from django.db import transaction
Expand All @@ -11,7 +10,7 @@

from django_tasks.signals import task_enqueued, task_finished
from django_tasks.task import ResultStatus, Task, TaskResult
from django_tasks.utils import exception_to_dict, json_normalize
from django_tasks.utils import exception_to_dict, get_random_id, json_normalize

from .base import BaseTaskBackend

Expand Down Expand Up @@ -74,7 +73,7 @@ def enqueue(

task_result = TaskResult[T](
task=task,
id=str(uuid4()),
id=get_random_id(),
status=ResultStatus.NEW,
enqueued_at=None,
started_at=None,
Expand Down
14 changes: 14 additions & 0 deletions django_tasks/utils.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import inspect
import json
import random
import time
from functools import wraps
from traceback import format_exception
from typing import Any, Callable, List, TypedDict, TypeVar

from django.utils.crypto import RANDOM_STRING_CHARS
from django.utils.module_loading import import_string
from typing_extensions import ParamSpec

Expand Down Expand Up @@ -87,3 +89,15 @@ def exception_from_dict(exc_data: SerializedExceptionDict) -> BaseException:
raise TypeError(f"{type(exc_class)} is not an exception")

return exc_class(*exc_data["exc_args"])


def get_random_id() -> str:
"""
Return a random string for use as a task id.
Whilst 64 characters is the max, just use 32 as a sensible middle-ground.
This should be much faster than Django's `get_random_string`, since
it's not cryptographically secure.
"""
return "".join(random.choices(RANDOM_STRING_CHARS, k=32))
10 changes: 10 additions & 0 deletions tests/tests/test_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -163,3 +163,13 @@ def test_cannot_deserialize_non_exception(self) -> None:
with self.subTest(data):
with self.assertRaises((TypeError, ImportError)):
utils.exception_from_dict(data)


class RandomIdTestCase(SimpleTestCase):
def test_correct_length(self) -> None:
self.assertEqual(len(utils.get_random_id()), 32)

def test_random_ish(self) -> None:
random_ids = [utils.get_random_id() for _ in range(1000)]

self.assertEqual(len(random_ids), len(set(random_ids)))

0 comments on commit 1e3f238

Please sign in to comment.