Forums

How to catch mysql timeout error

I'm running a task that need to be connected to a mysql database via SSH tunel. I'm getting therefore the MySQLdb._exceptions.OperationalError: (4031, 'The client was disconnected by the server because of inactivity. See wait_timeout and interactive_timeout for configuring this behavior.') error. At my local machine I could easily fix this by adding a "hearbeat" function that pushes some dummy sql request and reconnects if it fails. However, at Pythonanywhere this doesn't seem to work, because I get a MySQLdb._exceptions.OperationalError: (2013, "Lost connection to MySQL server at 'reading initial communication packet', system error: 11") error at the try to reconnect. Could you help me how to fix this issue permanently? Many thanks in advance!

Check out the "Dealing with OperationalError 2006, 'MySQL server has gone away'" section on this help page -- the error you're getting is a variation on that one, and the hints and tips there will apply.

Hi, thanks but this doesn't work unfortunately. I don't use Django therefore I use the code at 2. handle errors manually. The problem is that within the exception block, the function self.connect throws another MySQLdb._exceptions.OperationalError: (2013, "Lost connection to MySQL server at 'reading initial communication packet', system error: 11"). I also already tried to add another try except within the except, but the second try of self.connect fails again, again with system error 11.

Could you share the exact code you're using (with any secret stuff like usernames, passwords, and the actual contents of queries replaced by placeholders)?

def connection_handler(retries=1): def decorator_connection(func): @functools.wraps(func) def wrapper_retry_connection(args, kwargs): attempt = 0 while attempt <= retries: try: return func(args, **kwargs) except MySQLdb.OperationalError: args[0].connect() return wrapper_retry_connection return decorator_connection

#this is all within some class:
@connection_handler(retries=2)
def execute(self, statement):
    self.cursor.execute(statement)
    self.connection.commit()

def connect(self):
    sshtunnel.SSH_TIMEOUT = 10.0
    sshtunnel.TUNNEL_TIMEOUT = 10.0
    self.db_name = 'XYZ'
    self.tunnel = sshtunnel.SSHTunnelForwarder(
        ('ssh.pythonanywhere.com'),
        ssh_username=self.ssh_username,
        ssh_password=self.ssh_password,
        remote_bind_address=self.remote_bind_address
    )
    self.tunnel.start()
    self.connection = MySQLdb.connect(
        user=self.user,
        passwd=self.passwd,
        host=self.host,
        port=self.tunnel.local_bind_port,
        db=self.db_name
    )
    self.cursor = self.connection.cursor()

#And this is the main script I'm running
ClassXY.execute("SELECT 1")
time.sleep(11000)
ClassXY.execute("SELECT 1")

Where are you running this code and where is your database hosted?

My database is hosted at Pythonanywhere/MySQL. I run the main script within a scheduled task at Pythonanywhere that imports the class XY from some file uploaded to the files section. I'm using Python 3.10.5.

In such case you don't need to run within the tunnel -- it's only required for connecting from outside of PythonAnywhere. Have a look at this help page.

Thank you very much, I will do it that way. I'd have one more question. I develop my codes locally in pycharm and then upload them via Git into Pythonanywhere. Now I would have to modify the code as soon as I upload it to pythonanywhere. Do you maybe know some way on how to do this automatically without manually deleting the block that creates the ssh tunnel in self.execute every time before the push to Pythonanywhere? For example, could you somehow recognize in some python function whether its currently executed local or on pythonanywhere?

I guess you can just have one file that is available only on server or locally and check if it exists

You could use this:

import os

# ...

running_on_pythonanywhere = os.environ.get("PYTHONANYWHERE_SITE") != None

Then, unless you happen to be setting the environment variable PYTHONANYWHERE_SITE on your local machine, you'll know where you're running.