-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Create sample celery task usage * Include compare celery vs aiotaskq sample code in tests * Add ref to sample code in README, add sample code README * Include populate_db step in the tests Signed-off-by: Imran Ariffin <ariffin.imran@gmail.com>
- Loading branch information
1 parent
a6b0149
commit 1b90962
Showing
32 changed files
with
779 additions
and
10 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
""" | ||
Define the aiotaskq application instance. | ||
This app instance provides access to all tasks defined within the application. | ||
""" | ||
|
||
from importlib import import_module | ||
from typing import TYPE_CHECKING, Any | ||
|
||
|
||
if TYPE_CHECKING: | ||
from .task import Task | ||
|
||
|
||
class App: | ||
"""Define the aiotaskq application instance.""" | ||
|
||
_task_registry: dict[str, "Task"] = {} | ||
|
||
def __getattribute__(self, name: str, /) -> Any: | ||
"""Get access to all task instances defined within the application.""" | ||
|
||
task_registry = object.__getattribute__(self, "_task_registry") | ||
if name in task_registry: | ||
return task_registry[name] | ||
return object.__getattribute__(self, name) | ||
|
||
def autodiscover_tasks(self, tasks_module_name: str = "tasks"): | ||
""" | ||
Search for all tasks defined within the application and imported them. | ||
The tasks are expected to be defined in files named as "tasks.py". | ||
""" | ||
|
||
import django # pylint: disable=import-outside-toplevel | ||
from django.apps import apps # pylint: disable=import-outside-toplevel | ||
|
||
django.setup() | ||
|
||
module_names: list[str] = [config.name for config in apps.get_app_configs()] | ||
for module_name in module_names: | ||
_ = import_module(module_name) | ||
try: | ||
_ = import_module(f"{module_name}.{tasks_module_name}") | ||
except ModuleNotFoundError: | ||
pass | ||
else: | ||
pass |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
"""Define util functions for use within the whole library.""" | ||
|
||
import os | ||
import sys | ||
from contextlib import contextmanager | ||
from importlib import import_module | ||
|
||
|
||
def import_from_cwd(import_path): | ||
"""Import module as if the caller is located in current working directory (cwd).""" | ||
with _cwd_in_path(): | ||
return import_module(import_path) | ||
|
||
|
||
# Private region | ||
|
||
|
||
@contextmanager | ||
def _cwd_in_path(): | ||
"""Context adding the current working directory to sys.path.""" | ||
cwd = os.getcwd() | ||
if cwd in sys.path: | ||
yield | ||
else: | ||
sys.path.insert(0, cwd) | ||
try: | ||
yield cwd | ||
finally: | ||
try: | ||
sys.path.remove(cwd) | ||
except ValueError: # pragma: no cover | ||
pass | ||
|
||
# Private region ends |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
from django.apps import AppConfig | ||
|
||
|
||
class ApiConfig(AppConfig): | ||
default_auto_field = "django.db.models.BigAutoField" | ||
name = "api" |
90 changes: 90 additions & 0 deletions
90
src/tests/apps/sample_app_django/api/management/commands/populate_db.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,90 @@ | ||
import logging | ||
import random | ||
import string | ||
|
||
from django.core.management import BaseCommand | ||
|
||
from ...models import User, Order | ||
from ...utils import chunker | ||
|
||
logger = logging.getLogger(__name__) | ||
|
||
|
||
class Command(BaseCommand): | ||
def add_arguments(self, parser): | ||
parser.add_argument("--n-users", type=int, default=1000) | ||
parser.add_argument("--n-orders-per-user", type=int, default=1000) | ||
parser.add_argument("--from-scratch", action="store_true") | ||
|
||
def handle(self, *args, **options): | ||
if options["from_scratch"]: | ||
_delete_all() | ||
_populate_users(n=options["n_users"]) | ||
_populate_orders(n_per_user=options["n_orders_per_user"]) | ||
|
||
|
||
def _delete_all(): | ||
r = Order.objects.all().delete() | ||
logger.debug("Deleted %s: %s", Order.__name__, r) | ||
r = User.objects.all().delete() | ||
logger.debug("Deleted %s: %s", User.__name__, r) | ||
|
||
|
||
def _populate_users(n: int) -> None: | ||
users: list[User] = [] | ||
username_length: int = User._meta.get_field("username").max_length | ||
random_username_generator = RandomStringGenerator(length=username_length) | ||
for _ in range(n): | ||
username_random: str = random_username_generator.generate() | ||
user = User(username=username_random) | ||
users.append(user) | ||
|
||
for user_chunk in chunker(users, size=10_000): | ||
User.objects.bulk_create(user_chunk) | ||
print(f"Bulk-created {len(user_chunk)} random User(s)") | ||
|
||
|
||
def _populate_orders(n_per_user: int) -> None: | ||
user_ids: list[int] = list(User.objects.all().values_list("id", flat=True)) | ||
order_name_length: int = Order._meta.get_field("name").max_length | ||
random_order_name_id_generator = RandomStringGenerator(length=order_name_length) | ||
|
||
for user_ids_chunk in chunker(user_ids, size=1000): | ||
orders: list[Order] = [] | ||
|
||
for user_id in user_ids_chunk: | ||
for _ in range(n_per_user): | ||
order = Order( | ||
user_id=user_id, | ||
name=random_order_name_id_generator.generate(), | ||
price=random.uniform(0.0, 5_000.00), | ||
) | ||
orders.append(order) | ||
|
||
Order.objects.bulk_create(orders) | ||
print(f"Created {len(orders)} random Order(s) for {len(user_ids_chunk)} users") | ||
|
||
|
||
class MaxRandomStringTryReached(Exception): | ||
pass | ||
|
||
|
||
class RandomStringGenerator: | ||
max_tries = 10 | ||
|
||
def __init__(self, length: int): | ||
self.length = length | ||
self.existing: set[str] = set() | ||
|
||
def generate(self) -> str: | ||
tries = 0 | ||
while True: | ||
s = ''.join( | ||
random.choice(string.ascii_uppercase + string.digits) for _ in range(self.length) | ||
) | ||
if s not in self.existing: | ||
self.existing.add(s) | ||
return s | ||
tries += 1 | ||
if tries > self.max_tries: | ||
raise MaxRandomStringTryReached |
Oops, something went wrong.