Closed MattBlack85 closed 3 years ago
could it be that the task isn't finished when the test checks the status?
The issue here is that sqlite table is locked when trying to write the task object using the middleware. Which is surprising, as I thought the task wouldn't execute until after the middleware has written, so must be something else causing the table to be locked due to threading.
Traceback (most recent call last):
File "/Users/abartlett/.pyenv/versions/3.8.1/envs/django_dramatiq/lib/python3.8/site-packages/dramatiq/broker.py", line 98, in emit_after
getattr(middleware, "after_" + signal)(self, *args, **kwargs)
File "/Users/abartlett/src/github/django_dramatiq/django_dramatiq/middleware.py", line 21, in after_enqueue
Task.tasks.create_or_update_from_message(
File "/Users/abartlett/src/github/django_dramatiq/django_dramatiq/models.py", line 16, in create_or_update_from_message
task, _ = self.using(DATABASE_LABEL).update_or_create(
File "/Users/abartlett/.pyenv/versions/3.8.1/envs/django_dramatiq/lib/python3.8/site-packages/django/db/models/query.py", line 608, in update_or_create
obj, created = self.select_for_update().get_or_create(defaults, **kwargs)
File "/Users/abartlett/.pyenv/versions/3.8.1/envs/django_dramatiq/lib/python3.8/site-packages/django/db/models/query.py", line 588, in get_or_create
return self.create(**params), True
File "/Users/abartlett/.pyenv/versions/3.8.1/envs/django_dramatiq/lib/python3.8/site-packages/django/db/models/query.py", line 453, in create
obj.save(force_insert=True, using=self.db)
File "/Users/abartlett/.pyenv/versions/3.8.1/envs/django_dramatiq/lib/python3.8/site-packages/django/db/models/base.py", line 726, in save
self.save_base(using=using, force_insert=force_insert,
File "/Users/abartlett/.pyenv/versions/3.8.1/envs/django_dramatiq/lib/python3.8/site-packages/django/db/models/base.py", line 763, in save_base
updated = self._save_table(
File "/Users/abartlett/.pyenv/versions/3.8.1/envs/django_dramatiq/lib/python3.8/site-packages/django/db/models/base.py", line 868, in _save_table
results = self._do_insert(cls._base_manager, using, fields, returning_fields, raw)
File "/Users/abartlett/.pyenv/versions/3.8.1/envs/django_dramatiq/lib/python3.8/site-packages/django/db/models/base.py", line 906, in _do_insert
return manager._insert(
File "/Users/abartlett/.pyenv/versions/3.8.1/envs/django_dramatiq/lib/python3.8/site-packages/django/db/models/manager.py", line 85, in manager_method
return getattr(self.get_queryset(), name)(*args, **kwargs)
File "/Users/abartlett/.pyenv/versions/3.8.1/envs/django_dramatiq/lib/python3.8/site-packages/django/db/models/query.py", line 1270, in _insert
return query.get_compiler(using=using).execute_sql(returning_fields)
File "/Users/abartlett/.pyenv/versions/3.8.1/envs/django_dramatiq/lib/python3.8/site-packages/django/db/models/sql/compiler.py", line 1416, in execute_sql
cursor.execute(sql, params)
File "/Users/abartlett/.pyenv/versions/3.8.1/envs/django_dramatiq/lib/python3.8/site-packages/django/db/backends/utils.py", line 66, in execute
return self._execute_with_wrappers(sql, params, many=False, executor=self._execute)
File "/Users/abartlett/.pyenv/versions/3.8.1/envs/django_dramatiq/lib/python3.8/site-packages/django/db/backends/utils.py", line 75, in _execute_with_wrappers
return executor(sql, params, many, context)
File "/Users/abartlett/.pyenv/versions/3.8.1/envs/django_dramatiq/lib/python3.8/site-packages/django/db/backends/utils.py", line 84, in _execute
return self.cursor.execute(sql, params)
File "/Users/abartlett/.pyenv/versions/3.8.1/envs/django_dramatiq/lib/python3.8/site-packages/django/db/utils.py", line 90, in __exit__
raise dj_exc_value.with_traceback(traceback) from exc_value
File "/Users/abartlett/.pyenv/versions/3.8.1/envs/django_dramatiq/lib/python3.8/site-packages/django/db/backends/utils.py", line 84, in _execute
return self.cursor.execute(sql, params)
File "/Users/abartlett/.pyenv/versions/3.8.1/envs/django_dramatiq/lib/python3.8/site-packages/django/db/backends/sqlite3/base.py", line 423, in execute
return Database.Cursor.execute(self, query, params)
django.db.utils.OperationalError: database table is locked
I can consistently get this test to fail using pytest-flakefinder
.
❯ pytest -k test_test.py -vv --flake-finder
=============================================================================== test session starts ================================================================================
platform darwin -- Python 3.8.1, pytest-6.2.4, py-1.10.0, pluggy-0.13.1 -- /Users/abartlett/.pyenv/versions/3.8.1/envs/django_dramatiq/bin/python
cachedir: .pytest_cache
django: settings: tests.settings (from ini)
rootdir: /Users/abartlett/src/github/django_dramatiq, configfile: setup.cfg, testpaths: tests
plugins: cov-2.11.1, django-4.2.0, flakefinder-1.0.0
collected 701 items / 700 deselected / 1 selected
tests/test_test.py::TestDramatiqTestCase::test_worker_consumes_tasks PASSED [ 2%]
tests/test_test.py::TestDramatiqTestCase::test_worker_consumes_tasks PASSED [ 2%]
tests/test_test.py::TestDramatiqTestCase::test_worker_consumes_tasks FAILED [ 2%]
tests/test_test.py::TestDramatiqTestCase::test_worker_consumes_tasks PASSED [ 2%]
tests/test_test.py::TestDramatiqTestCase::test_worker_consumes_tasks PASSED [ 2%]
tests/test_test.py::TestDramatiqTestCase::test_worker_consumes_tasks PASSED [ 2%]
tests/test_test.py::TestDramatiqTestCase::test_worker_consumes_tasks PASSED [ 2%]
tests/test_test.py::TestDramatiqTestCase::test_worker_consumes_tasks PASSED [ 2%]
tests/test_test.py::TestDramatiqTestCase::test_worker_consumes_tasks PASSED [ 2%]
tests/test_test.py::TestDramatiqTestCase::test_worker_consumes_tasks PASSED [ 2%]
tests/test_test.py::TestDramatiqTestCase::test_worker_consumes_tasks FAILED [ 2%]
tests/test_test.py::TestDramatiqTestCase::test_worker_consumes_tasks PASSED [ 2%]
tests/test_test.py::TestDramatiqTestCase::test_worker_consumes_tasks PASSED [ 2%]
tests/test_test.py::TestDramatiqTestCase::test_worker_consumes_tasks PASSED [ 2%]
tests/test_test.py::TestDramatiqTestCase::test_worker_consumes_tasks PASSED [ 2%]
tests/test_test.py::TestDramatiqTestCase::test_worker_consumes_tasks PASSED [ 2%]
tests/test_test.py::TestDramatiqTestCase::test_worker_consumes_tasks PASSED [ 2%]
tests/test_test.py::TestDramatiqTestCase::test_worker_consumes_tasks PASSED [ 2%]
tests/test_test.py::TestDramatiqTestCase::test_worker_consumes_tasks PASSED [ 2%]
tests/test_test.py::TestDramatiqTestCase::test_worker_consumes_tasks PASSED [ 2%]
tests/test_test.py::TestDramatiqTestCase::test_worker_consumes_tasks PASSED [ 2%]
tests/test_test.py::TestDramatiqTestCase::test_worker_consumes_tasks FAILED [ 2%]
tests/test_test.py::TestDramatiqTestCase::test_worker_consumes_tasks PASSED [ 2%]
tests/test_test.py::TestDramatiqTestCase::test_worker_consumes_tasks PASSED [ 2%]
tests/test_test.py::TestDramatiqTestCase::test_worker_consumes_tasks PASSED [ 2%]
tests/test_test.py::TestDramatiqTestCase::test_worker_consumes_tasks PASSED [ 2%]
tests/test_test.py::TestDramatiqTestCase::test_worker_consumes_tasks PASSED [ 2%]
tests/test_test.py::TestDramatiqTestCase::test_worker_consumes_tasks PASSED [ 2%]
tests/test_test.py::TestDramatiqTestCase::test_worker_consumes_tasks PASSED [ 2%]
tests/test_test.py::TestDramatiqTestCase::test_worker_consumes_tasks PASSED [ 2%]
tests/test_test.py::TestDramatiqTestCase::test_worker_consumes_tasks PASSED [ 2%]
tests/test_test.py::TestDramatiqTestCase::test_worker_consumes_tasks PASSED [ 2%]
tests/test_test.py::TestDramatiqTestCase::test_worker_consumes_tasks PASSED [ 2%]
tests/test_test.py::TestDramatiqTestCase::test_worker_consumes_tasks PASSED [ 2%]
tests/test_test.py::TestDramatiqTestCase::test_worker_consumes_tasks PASSED [ 2%]
tests/test_test.py::TestDramatiqTestCase::test_worker_consumes_tasks PASSED [ 2%]
tests/test_test.py::TestDramatiqTestCase::test_worker_consumes_tasks PASSED [ 2%]
tests/test_test.py::TestDramatiqTestCase::test_worker_consumes_tasks PASSED [ 2%]
tests/test_test.py::TestDramatiqTestCase::test_worker_consumes_tasks PASSED [ 2%]
tests/test_test.py::TestDramatiqTestCase::test_worker_consumes_tasks PASSED [ 2%]
tests/test_test.py::TestDramatiqTestCase::test_worker_consumes_tasks PASSED [ 2%]
tests/test_test.py::TestDramatiqTestCase::test_worker_consumes_tasks PASSED [ 2%]
tests/test_test.py::TestDramatiqTestCase::test_worker_consumes_tasks PASSED [ 2%]
tests/test_test.py::TestDramatiqTestCase::test_worker_consumes_tasks PASSED [ 2%]
tests/test_test.py::TestDramatiqTestCase::test_worker_consumes_tasks PASSED [ 2%]
tests/test_test.py::TestDramatiqTestCase::test_worker_consumes_tasks PASSED [ 2%]
tests/test_test.py::TestDramatiqTestCase::test_worker_consumes_tasks PASSED [ 2%]
tests/test_test.py::TestDramatiqTestCase::test_worker_consumes_tasks PASSED [ 2%]
tests/test_test.py::TestDramatiqTestCase::test_worker_consumes_tasks PASSED [ 2%]
tests/test_test.py::TestDramatiqTestCase::test_worker_consumes_tasks PASSED [ 2%]
===================================================================================== FAILURES =====================================================================================
.... <failures cut out for brevity>
============================================================================= short test summary info ==============================================================================
FAILED tests/test_test.py::TestDramatiqTestCase::test_worker_consumes_tasks - AssertionError: 'failed' != 'done'
FAILED tests/test_test.py::TestDramatiqTestCase::test_worker_consumes_tasks - AssertionError: 'failed' != 'done'
FAILED tests/test_test.py::TestDramatiqTestCase::test_worker_consumes_tasks - AssertionError: 'failed' != 'done'
================================================================== 3 failed, 47 passed, 700 deselected in 13.22s ===================================================================
I did try doing a retry on error in the test task, though it never seems to be a problem at that side, only when creating in the middleware.
I went through a test that seems to fail randomly from time to time
not sure about the cause nor I have investigated this deeply but maybe worth a look at some point