Reputation: 313
I’m using Django 4.2 connected to a MySQL 8.0.30 database. The server is nginx , with gunicorn (3 workers) and using WSGI.
I’m running asyncio for a function I need to run asynchronously because it's used by an async API broker, but here I'm just calling directly from a view, so it's direct and short-lived:
from django.db import connection
import asyncio
example_object = asyncio.run(make_query(name))
async def make_query(request, name):
object = await ModelExample.objects.filter(name=name).afirst()
return object
I’m having the following error on the afirst() query execution:
[4031] The client was disconnected by the server because of inactivity. See wait_timeout and interactive_timeout for configuring this behavior
Initially the code works fine, the error only starts after a few hours (maybe 8h). I can temporarily fix it by restarting the (nginx) error. It’s a low traffic website so it’s very possible the function is executed only once a day.
Because it requires 8hours of innactivity, it's not being easy to replicate or debug this.
What I've tried:
Django layer:
In my understanding, Django always opens a connection, executes a query and then closes a connection. This should happen in WSGI too, but the connection getting idle suggest otherwise. So I tried:
CONN_HEALTH_CHECKS
option to True, in the hopes that “if the health check fails, the connection will be re-established without failing the request”CONN_MAX_AGE
from the default 0 to “None” in the Django settings file, which according to Django docs, means an unlimited persistent database connection.None had effect.
If this is a Django issue, then my last guess would be a bug with “afirst()” (added in Django 4.1) when using MySQL somehow.
MySQL layer:
Found some reports attributing this issue to MySQL (also happening in Wordpress and PHP applications), so I tried:
SHOW VARIABLES
command shows me they are indeed currently set to 31536000."Whenever a connection was terminated due to inactivity, the thread pool plugin printed only a generic message about connections timing out; this often made analysis of such timeouts more difficult than necessary. A new INFO_LEVEL message makes it clear that a connection has been terminated due to inactivity in the thread pool, as well as which timeout value was used to make this determination. (Bug #34767607)"
So I updated the MySQL hoping to get more information, will let you know if I do.
Please let me know what you think, ideas or suggestions on how to debug this! Thanks in advance.
Upvotes: 2
Views: 6375
Reputation: 313
Answering this for future people that might have the same problem if they are using DigitalOcean.
It appears that the initial approach of configuring MySQL was correct, but it was not actually being applied to the DB. If you are using DigitalOcean, applying configurations via SSH to the droplet does not correspond to the actual configurations in the database cluster.
To resolve this, you need to use DigitalOcean's API to configure the database. The following changes to the variables seemed to solve the issue for me:
Django's async functionalities should work without issues in a low-traffic website with this configuration. Ofc may vary depending on your setup and requirements.
Upvotes: 3