超时时重新连接MySQL

问题描述:

我有一个Python程序,该程序在后台运行数周,偶尔执行一次数据库查询.为此,我使用的是ORM peewee (2.2.1版).我正在使用MySQL作为后端.

I have a Python program which runs on background for weeks, and does database queries every once in a while. For that, I am using the ORM peewee (version 2.2.1). I am using MySQL as a backend.

最近,通常在运行程序几天后,访问数据库时经常遇到问题. peewee引发的错误是

Lately I've encountered a recurring problem with accessing the DB, usually after days of running the program. The error which is raised by peewee is

peewee.OperationalError: (2006, 'MySQL server has gone away')

回溯深入到peewee中.我将其发布在这里,但是由于我的virtualenv使文件名过长,因此我将其缩短了:

The traceback is deep in peewee. I post it here, but as my virtualenv makes filenames too long, I am shortening them:

  File ".../local/lib/python2.7/site-packages/peewee.py", line 2910, in save
    ret_pk = self.insert(**field_dict).execute()
  File ".../local/lib/python2.7/site-packages/peewee.py", line 2068, in execute
    return self.database.last_insert_id(self._execute(), self.model_class)
  File ".../local/lib/python2.7/site-packages/peewee.py", line 1698, in _execute
    return self.database.execute_sql(sql, params, self.require_commit)
  File ".../local/lib/python2.7/site-packages/peewee.py", line 2232, in execute_sql
    self.commit()
  File ".../local/lib/python2.7/site-packages/peewee.py", line 2104, in __exit__
    reraise(new_type, new_type(*exc_value.args), traceback)
  File ".../local/lib/python2.7/site-packages/peewee.py", line 2223, in execute_sql
    res = cursor.execute(sql, params or ())
  File ".../local/lib/python2.7/site-packages/MySQLdb/cursors.py", line 205, in execute
    self.errorhandler(self, exc, value)
  File ".../local/lib/python2.7/site-packages/MySQLdb/connections.py", line 36, in defaulterrorhandler
    raise errorclass, errorvalue
peewee.OperationalError: (2006, 'MySQL server has gone away')

我发现的

可能的解决方案尝试:

  • 这个问题中,其中一项评论建议偶尔对MySQL服务器执行ping操作,以使其保持活动状态(连接?).不过,我不确定如何通过ORM做到这一点. (我应该每小时简单地SELECT 1吗?)
  • 在4个月前打开的此github peewee问题中,错误被提及,但是据称在那里已经解决了(并且我正在使用较新的版本).
  • trac 7岁的问题中,一个建议是增加MySQL的超时时间为3天.
  • 在此论坛讨论中,建议增加MySQL的超时选项,但是提供了对MySQL JDBC连接器使用autoReconnect选项"的替代方法.我试图弄清楚Python的MySQLdb模块是否存在这样的选项,但找不到.
  • 我找到了 MySQL参考页关于重新连接行为,但是对于我对MySQL的理解有些复杂(通常我只使用ORM),而且我不知道如何从peewee中应用任何一个.
  • In this question, one of the comments suggest pinging the MySQL server every once in a while to keep it (the connection?) alive. I am not sure how to do it via the ORM, though. (should I simply SELECT 1 every hour, say?)
  • In this github peewee issue, which was opened 4 months ago, the same error is referred, though, it is claimed there that it is solved (and I am using a newer version).
  • In a 7 year old issue of trac, one suggestion is to increase the timeout of MySQL for 3 days.
  • In this forum discussion, the option of increasing MySQL's timeout is suggested, but an alternative of "using the autoReconnect option for the MySQL JDBC connector" is offered. I tried to figure out if such an option exists for Python's MySQLdb module, but couldn't find.
  • I have found this MySQL reference page on reconnection behaviour, but it's a bit complicated for my understanding of MySQL (usually I work only with ORMs), and I don't know how to apply any of it from peewee.

即使我能够对数据库执行ping操作以使连接保持更长的时间,但我认为在不需要连接时保持连接的活动仍然是一种不好的做法.有什么办法可以通过ORM重新打开连接吗?我认为ping和增加MySQL的超时都是变通办法,而真正的解决方案是在需要时重新连接(而真正的解决方案是我要的).

Even if I'm able to ping the database to keep the connection alive for longer periods, I think it is considered a bad practice to keep a connection alive when one doesn't really need it. Is there any way to reopen the connection via the ORM? I consider both pinging and increasing the timeout of MySQL as workarounds, while a real solution would be to reconnect when needed (and a real solution is what I'm asking for).

您必须捕获异常并根据哪个错误重新连接或执行其他操作.无论是连接超时,网络问题还是必须重新启动MySQL.

You have to catch the exception and based on which error, reconnect or to do something else. Whether it is a connection time out, or a network problem or the MySQL had to be restarted.

以下(伪)代码显示了如何执行此操作,但还有更多内容.您可能需要尝试几次,然后再纾困,或者也许每2分钟左右尝试一次.

The below (pseudoish) code shows how you could do that, but there is more to it. You'll want to try a few times and then bail out, or maybe try every 2 minutes or so.

while True:
    try:
        # do your database stuff
    except peewee.OperationalError as exc:
        # Oops! We have to try to reconnect

是否使用ORM并不重要.但是,ORM可能提供此功能.

Does not really matter whether you use an ORM or not. However, an ORM might offer this functionality.