运行Flask服务器(Apache)几天时发生MySQL操作错误

2024-09-30 01:20:43 发布

您现在位置:Python中文网/ 问答频道 /正文

我在Apache下有一个Flask服务器,我将它用作应用程序的restapi,当服务器运行2-3天时,它突然停止工作并引发OperationalError: MySQL Connection not available.

错误总是发生在login方法,因为它是应用程序打开时的第一个调用(但所有方法都遵循相同的模式)。在

这是login方法:

@app.route(LOGIN_API_URL, methods=['POST'])
def login():
    if (request.method == 'POST'):
        cursor = connection.cursor(buffered=True, dictionary=True)
        cursor.execute('select * from users where username = %s', (request.form['username'],))
        user = cursor.fetchone()
        if user is None or user['password'] != str(request.form['password']):
            abort(403)
        else:
            cursor.execute('update users set last_login = (%s) where user_id = %s', str(int(round(time.time() * 1000))), user['user_id'],)
            utils.safe_commit(connection, cursor)
            return utils.sanitize_response({'status':200, 'message':'Logged in'})

safe_commit和{}都遵循:

^{pr2}$

一开始我认为问题是因为我没有在调用fetchone方法的游标中使用buffered=True。但是我在读了this之后添加了这个参数。在

这是我的wsgi文件:

#!/usr/bin/python
import sys
sys.path.append("/var/www/protestr/")
from protestr import app as application

这是我的sites-availableconf文件(我想说的是,我已经尝试了很多threads和{}参数的组合,这种组合使服务器在大多数时间内保持运行,通常为2-3天):

<VirtualHost *:80>
    ServerName protestr.tk
    DocumentRoot /var/www/protestr/

    WSGIDaemonProcess protestr user=www-data group=www-data processes=2 threads=25
    WSGIScriptAlias / /var/www/protestr/protestr.wsgi

    <Directory /var/www/protestr>
        WSGIProcessGroup protestr
        WSGIApplicationGroup %{GLOBAL}
        Require all granted
    </Directory>
</VirtualHost>

以下是error.log文件的内容:

[Fri May 12 03:34:14.967624 2017] [wsgi:error] [pid 18673:tid 2849002544] [remote 192.168.1.139:25727] [2017-05-12 03:34:14,963] ERROR in app: Exception on /api/v1/users/login [POST]
[Fri May 12 03:34:14.967812 2017] [wsgi:error] [pid 18673:tid 2849002544] [remote 192.168.1.139:25727] Traceback (most recent call last):
[Fri May 12 03:34:14.967861 2017] [wsgi:error] [pid 18673:tid 2849002544] [remote 192.168.1.139:25727]   File "/usr/local/lib/python2.7/dist-packages/flask/app.py", line 1982, in wsgi_app
[Fri May 12 03:34:14.967900 2017] [wsgi:error] [pid 18673:tid 2849002544] [remote 192.168.1.139:25727]     response = self.full_dispatch_request()
[Fri May 12 03:34:14.967937 2017] [wsgi:error] [pid 18673:tid 2849002544] [remote 192.168.1.139:25727]   File "/usr/local/lib/python2.7/dist-packages/flask/app.py", line 1614, in full_dispatch_request
[Fri May 12 03:34:14.967973 2017] [wsgi:error] [pid 18673:tid 2849002544] [remote 192.168.1.139:25727]     rv = self.handle_user_exception(e)
[Fri May 12 03:34:14.968007 2017] [wsgi:error] [pid 18673:tid 2849002544] [remote 192.168.1.139:25727]   File "/usr/local/lib/python2.7/dist-packages/flask/app.py", line 1517, in handle_user_exception
[Fri May 12 03:34:14.968043 2017] [wsgi:error] [pid 18673:tid 2849002544] [remote 192.168.1.139:25727]     reraise(exc_type, exc_value, tb)
[Fri May 12 03:34:14.968076 2017] [wsgi:error] [pid 18673:tid 2849002544] [remote 192.168.1.139:25727]   File "/usr/local/lib/python2.7/dist-packages/flask/app.py", line 1612, in full_dispatch_request
[Fri May 12 03:34:14.968111 2017] [wsgi:error] [pid 18673:tid 2849002544] [remote 192.168.1.139:25727]     rv = self.dispatch_request()
[Fri May 12 03:34:14.968144 2017] [wsgi:error] [pid 18673:tid 2849002544] [remote 192.168.1.139:25727]   File "/usr/local/lib/python2.7/dist-packages/flask/app.py", line 1598, in dispatch_request
[Fri May 12 03:34:14.968179 2017] [wsgi:error] [pid 18673:tid 2849002544] [remote 192.168.1.139:25727]     return self.view_functions[rule.endpoint](**req.view_args)
[Fri May 12 03:34:14.968251 2017] [wsgi:error] [pid 18673:tid 2849002544] [remote 192.168.1.139:25727]   File "/var/www/protestr/protestr.py", line 89, in login
[Fri May 12 03:34:14.968290 2017] [wsgi:error] [pid 18673:tid 2849002544] [remote 192.168.1.139:25727]     cursor = connection.cursor(buffered=True, dictionary=True)
[Fri May 12 03:34:14.968326 2017] [wsgi:error] [pid 18673:tid 2849002544] [remote 192.168.1.139:25727]   File "/usr/local/lib/python2.7/dist-packages/mysql/connector/connection.py", line 809, in cursor
[Fri May 12 03:34:14.968363 2017] [wsgi:error] [pid 18673:tid 2849002544] [remote 192.168.1.139:25727]     raise errors.OperationalError("MySQL Connection not available.")
[Fri May 12 03:34:14.968399 2017] [wsgi:error] [pid 18673:tid 2849002544] [remote 192.168.1.139:25727] OperationalError: MySQL Connection not available.

其他信息:

我正在香蕉派中的armbian(Debian)下运行Apache/2.4.10。在

我真的不知道为什么服务器在运行一段时间后会停止运行,我想我已经尝试了几乎所有的方法。在


编辑:在抛出login方法中的403错误之前,我还添加了cursor.close()。但这与此无关,因为我是唯一一个登录应用程序的人,而且我总是输入正确的凭据。在

编辑2:正如@stamaimer告诉我的那样,如果我在获取任何游标之前添加connection.ping(),它会很好地工作,但是这种方法对我来说似乎是一种很难理解的方法,我不知道这是不是一个好的解决方案,甚至不知道为什么MySQL服务器要断开连接。


Tags: 方法inappwsgiremoterequestloginerror
2条回答

这个例子有点粗糙,但有希望展示了处理断开连接的逻辑。具体细节取决于在特定框架中获得连接的方式。在

下面的代码假定使用^{};如果需要,可以使用不同的重试逻辑。在

它还假设您正在使用框架提供的应用程序的连接池。通常,您可以请求它重新连接,或者至少关闭空闲连接,以便另一个连接请求将创建一个新的连接请求。在

def reconnect_on_failure(func):
    @retry(OperationalError, delay=0.25, backoff=1.5, max_delay=5)
    @wraps(func)
    def reconnecting_func(*args, **kwargs):
        try:
            return func(*args, **kwargs)
        except OperationalError as e:
            if 'connect' in e.msg.lower():
                force_reconnection_somehow()  # Look at your connection pool API.
                raise  # We want to retry on it
            raise Exception('Unhandled MySQL error', e)  # Will not retry.
    return reconnecting_func


@reconnect_on_failure
def something(...):
    connection = get_connecton_somehow()  # Look at the framework API.
    # A transaction implicitly begins with the first statement executed.
    cursor = connection.cursor()
    result = cursor.execute(...)  # do stuff
    connection.commit()

代替过于宽泛的Exception,您可以使用一个更窄的类,例如针对您的应用程序;其思想是,引发任何OperationalError不会触发重试,它将立即引发一个Exception来报告问题。在

从Grender编辑:我添加了^{}装饰器,以避免AssertionError如{a3}所示。在

@9000s answer的基础上构建,使用参数reconnect=Truesee the corresponding code调用ping应该可以正常工作。这将发出ping,如果ping失败,请尝试重新连接到数据库。在

虽然这应该可以修复错误,但是您应该稍微挖掘一下,找到底层问题,即与MySQL的非功能连接。在

如前所述,这可能来自多个来源,因此您可以使用以下列表来指导您的搜索:

  • 在您发布的错误消息之前,日志中是否还有其他错误消息?在
  • 您是通过TCP/IP还是通过套接字连接到MySQL?也许可以尝试另一种变体,如果其中一种有效,另一种不起作用,这可能有助于确定问题所在。在
  • ^{}增大到一个较大的值,以确定它是否有效果。在
  • 您可能还想增加max_allowed_packetas this helped in other cases。在
  • 检查MySQL服务器日志中是否存在连接丢失的潜在问题。在
  • 还要检查操作系统的syslog,因为MySQL might get killed due to low memory,这可以修复by setting better values in config。在

希望这能帮助你找到根本原因。在

相关问题 更多 >

    热门问题