I have django project, Mysql DB is on a separate host, connected by TCP. I have this script:
#!/usr/bin/env python
from asyncio import sleep, run
from django import setup as django_setup
django_setup()
from django.db import connections
from django.contrib.auth.models import User
from django.db import OperationalError, close_old_connections
async def test():
while True:
try:
objs=User.objects.all()
print(await objs.acount())
except KeyboardInterrupt:
break
except OperationalError as e: # Need to reconnect
print(f'main(): OperationalError: {e}')
# (1053, 'Server shutdown in progress')
# (2013, 'Lost connection to MySQL server during query')
# (2006, 'Server has gone away')
code=e.args[0]
if code in {1053, 2006, 2013, 2026}: # Only when it's restarting, and once
#await sync_to_async(conn.connect)()
close_old_connections()
print('After reconnect')
except Exception as e:
print(f'in _round() {type(e)}')
else:
pass
#breakpoint()
print('Sleeping')
await sleep(5)
run(test())
Then I use tcpkill to interrupt the connection:
tcpkill 'dst port 3306'
How do I instruct django to reconnect? I doesn't do it automatically, close_old_connection doesn't work, the output is then like this:
3
Sleeping
3
Sleeping
main(): OperationalError: (2013, 'Lost connection to MySQL server during query')
After reconnect
Sleeping
main(): OperationalError: (2013, 'Lost connection to MySQL server during query')
After reconnect
Sleeping
main(): OperationalError: (2013, 'Lost connection to MySQL server during query')
After reconnect
Sleeping
When looking into the code, I see it spawns cursor object from connection object, it doesn't work and then is closed, while probably connection object stays intact and keeps giving unusable cursors. I've tried connection.connect(), but it won't work, because the code is async.
close_old_connections() doesn't work, because for async all the objects will live in different thread. And probably I was calling it differently, when connect in sync_to_async wasn't working. So in the end this works:
await sync_to_async(reconnect)()
with this function:
def reconnect():
conn=connections['default']
conn.connect()