- Notifications
You must be signed in to change notification settings - Fork 349
Description
Running tests in a fairly large codebase, which mostly does integration/functional tests, etc. sets up Django application, make API calls to it, sets up database entities through mocks beforehand, etc. There are tests that use @pytest.mark.django_db(transaction=True)
, most don't.
The tests run mostly okay, but some times, for some reason, the exception about not being able to flush the database pops up. (attached at the bottom).
I have thought about the following: Maybe this happens because we are using Celery, and tests obviously run Celery tasks sometimes too. And Celery runs them in a separate thread, and when test finishes, task is still not finished, and we are trying to flush, and that's how it fails. So I tried fixing it by waiting for threads to finish before tearing down:
import threading from typing import Any pytest_plugins = ( 'api.test_utils.fixtures.auto', 'api.test_utils.fixtures.common', ) def pytest_runtest_teardown(item: Any, nextitem: Any) -> None: """ Wait for all non-daemon threads to finish before test cleanup. This should fix "couldn't flush the database" error that sometimes happens... """ # Get all active threads except main thread active_threads = [ t for t in threading.enumerate() if t != threading.main_thread() and not t.daemon ] if active_threads: logger.info('\nWaiting for threads to finish...', threads_num=len(active_threads)) for thread in active_threads: logger.info('Waiting for thread', thread_name=thread.name) thread.join(timeout=30) if thread.is_alive(): logger.info("Warning: Thread didn't finish in time", thread_name=thread.name)
This seemed to work... at first, but we're still getting the same error once in a couple of days. I couldn't find any correlation.
Looking for help and advice on this one!
Python version: 3.10.18
Package versions:
Django = "==4.2.24" django-extensions = "==3.2.3" psycopg2-binary = "==2.9.9" celery = "==5.4.0" pytest-django = "==4.8.0" pytest-mock = "==3.14.0" pytest = "==7.4.0"
This is the exception that happens:
__ ERROR at teardown of test_abc ___ [gw6] linux -- Python 3.10.18 /usr/local/bin/python /usr/local/lib/python3.10/site-packages/django/db/backends/utils.py:87: in _execute return self.cursor.execute(sql) E psycopg2.errors.QueryCanceled: canceling statement due to statement timeout The above exception was the direct cause of the following exception: /usr/local/lib/python3.10/site-packages/django/core/management/commands/flush.py:73: in handle connection.ops.execute_sql_flush(sql_list) /usr/local/lib/python3.10/site-packages/django/db/backends/base/operations.py:451: in execute_sql_flush cursor.execute(sql) /usr/local/lib/python3.10/site-packages/django/db/backends/utils.py:67: in execute return self._execute_with_wrappers( /usr/local/lib/python3.10/site-packages/django/db/backends/utils.py:80: in _execute_with_wrappers return executor(sql, params, many, context) /usr/local/lib/python3.10/site-packages/django/db/backends/utils.py:84: in _execute with self.db.wrap_database_errors: /usr/local/lib/python3.10/site-packages/django/db/utils.py:91: in __exit__ raise dj_exc_value.with_traceback(traceback) from exc_value /usr/local/lib/python3.10/site-packages/django/db/backends/utils.py:87: in _execute return self.cursor.execute(sql) E django.db.utils.OperationalError: canceling statement due to statement timeout The above exception was the direct cause of the following exception: /usr/local/lib/python3.10/site-packages/pytest_django/fixtures.py:254: in _django_db_helper test_case._post_teardown() /usr/local/lib/python3.10/site-packages/django/test/testcases.py:1279: in _post_teardown self._fixture_teardown() /usr/local/lib/python3.10/site-packages/django/test/testcases.py:1313: in _fixture_teardown call_command( /usr/local/lib/python3.10/site-packages/django/core/management/__init__.py:194: in call_command return command.execute(*args, **defaults) /usr/local/lib/python3.10/site-packages/django/core/management/base.py:458: in execute output = self.handle(*args, **options) /usr/local/lib/python3.10/site-packages/django/core/management/commands/flush.py:75: in handle raise CommandError( E django.core.management.base.CommandError: Database test_postgres_gw6 couldn't be flushed. Possible reasons: E * The database isn't running or isn't configured correctly. E * At least one of the expected database tables doesn't exist. E * The SQL was invalid. E Hint: Look at the output of 'django-admin sqlflush'. That's the SQL this command wasn't able to run.