Skip to content

Commit 178578d

Browse files
committed
Fix AppRegistryNotReady error for tasks w/ model access
1 parent 2842de1 commit 178578d

4 files changed

Lines changed: 33 additions & 1 deletion

File tree

tests/test_executor.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
boom_retry_raises,
2323
boom_retry_thrice,
2424
boom_with_retry,
25+
count_users,
2526
echo,
2627
)
2728
from threadmill.backends.base import Broker
@@ -158,6 +159,29 @@ def test_run__processes_enqueued_tasks_end_to_end(self):
158159
assert {r.id for r in results} == {r.id for r in enqueued}
159160
assert all(r.status == TaskResultStatus.SUCCESSFUL for r in results)
160161

162+
def test_run__executes_model_task_in_spawned_worker(self):
163+
"""run() executes a model-accessing task in a spawned worker process."""
164+
original_start_method = multiprocessing.get_start_method()
165+
multiprocessing.set_start_method("spawn", force=True)
166+
try:
167+
enqueued = default_task_backend.enqueue(count_users)
168+
executor = TaskExecutor(
169+
backend=default_task_backend,
170+
workers=1,
171+
threads=1,
172+
queues=("default",),
173+
)
174+
run_thread = threading.Thread(target=executor.run, daemon=True)
175+
run_thread.start()
176+
time.sleep(3)
177+
executor.shutdown()
178+
run_thread.join(timeout=5)
179+
assert not run_thread.is_alive()
180+
result = default_task_backend.get_result(enqueued.id)
181+
assert result.status == TaskResultStatus.SUCCESSFUL
182+
finally:
183+
multiprocessing.set_start_method(original_start_method, force=True)
184+
161185
def test_worker_acquires_updates_and_acknowledges(self):
162186
"""Worker acquires, executes, and acknowledges via its own backend."""
163187
enqueued = default_task_backend.enqueue(echo, args=[42])

tests/testapp/settings.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@
8282
DATABASES = {
8383
"default": {
8484
"ENGINE": "django.db.backends.sqlite3",
85-
"NAME": ":memory:",
85+
"NAME": BASE_DIR / "db.sqlite3",
8686
}
8787
}
8888

tests/testapp/tasks.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,12 @@ def boom():
2222
raise ValueError("boom")
2323

2424

25+
@task()
26+
def count_users():
27+
"""Count all users in the database (tests model access in workers)."""
28+
from django.contrib.auth.models import User # noqa
29+
30+
2531
@task(queue_name="compute")
2632
def compute_workload():
2733
"""Calculate the first 1000 prime numbers."""

threadmill/executor.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
from queue import Empty
1616
from traceback import format_exception
1717

18+
import django
1819
from django.tasks import TaskResult, task_backends
1920
from django.tasks.base import TaskContext, TaskError, TaskResultStatus
2021
from django.tasks.signals import task_finished, task_started
@@ -146,6 +147,7 @@ def __init__(
146147

147148
def run(self) -> None:
148149
"""Start consumer execution inside this process."""
150+
django.setup()
149151
logger.info("Starting worker process %s", self.name)
150152
self.lock = threading.Lock()
151153
self.expired = threading.Event()

0 commit comments

Comments
 (0)