我正在构建一个Django(3.0.5版)应用程序,它使用mysqlclient
(2.0.3版)作为数据库后端。此外,我还编写了一个Django命令,它运行一个使用python-telegram-botAPI编写的bot,因此这个bot的任务是无限期地运行,因为它必须随时响应命令
问题是大约24小时。在运行bot(不一定总是空闲)之后,在运行任何命令之后,我会得到一个django.db.utils.OperationalError: (2006, 'MySQL server has gone away')
异常
我绝对肯定MySQL服务器一直在运行,并且在我遇到这个异常时仍然在运行。MySQL服务器版本为5.7.35
我的假设是,一些MySQL线程会老化并关闭,因此在重用它们之后,它们不会得到更新
有没有人遇到过这种情况,知道如何解决
Traceback (most recent call last):
File "/opt/django/gip/venv/lib/python3.6/site-packages/telegram/ext/dispatcher.py", line 555, in process_update
handler.handle_update(update, self, check, context)
File "/opt/django/gip/venv/lib/python3.6/site-packages/telegram/ext/handler.py", line 198, in handle_update
return self.callback(update, context)
File "/opt/django/gip/gip/hospital/gipcrbot.py", line 114, in ayuda
perfil = get_permiso_efectivo(update.message.from_user.id)
File "/opt/django/gip/gip/hospital/telegram/funciones.py", line 33, in get_permiso_efectivo
u = Telegram.objects.get(idtelegram=userid)
File "/opt/django/gip/venv/lib/python3.6/site-packages/django/db/models/manager.py", line 82, in manager_method
return getattr(self.get_queryset(), name)(*args, **kwargs)
File "/opt/django/gip/venv/lib/python3.6/site-packages/django/db/models/query.py", line 411, in get
num = len(clone)
File "/opt/django/gip/venv/lib/python3.6/site-packages/django/db/models/query.py", line 258, in __len__
self._fetch_all()
File "/opt/django/gip/venv/lib/python3.6/site-packages/django/db/models/query.py", line 1261, in _fetch_all
self._result_cache = list(self._iterable_class(self))
File "/opt/django/gip/venv/lib/python3.6/site-packages/django/db/models/query.py", line 57, in __iter__
results = compiler.execute_sql(chunked_fetch=self.chunked_fetch, chunk_size=self.chunk_size)
File "/opt/django/gip/venv/lib/python3.6/site-packages/django/db/models/sql/compiler.py", line 1151, in execute_sql
cursor.execute(sql, params)
File "/opt/django/gip/venv/lib/python3.6/site-packages/django/db/backends/utils.py", line 100, in execute
return super().execute(sql, params)
File "/opt/django/gip/venv/lib/python3.6/site-packages/django/db/backends/utils.py", line 68, in execute
return self._execute_with_wrappers(sql, params, many=False, executor=self._execute)
File "/opt/django/gip/venv/lib/python3.6/site-packages/django/db/backends/utils.py", line 77, in _execute_with_wrappers
return executor(sql, params, many, context)
File "/opt/django/gip/venv/lib/python3.6/site-packages/django/db/backends/utils.py", line 86, in _execute
return self.cursor.execute(sql, params)
File "/opt/django/gip/venv/lib/python3.6/site-packages/django/db/utils.py", line 90, in __exit__
raise dj_exc_value.with_traceback(traceback) from exc_value
File "/opt/django/gip/venv/lib/python3.6/site-packages/django/db/backends/utils.py", line 86, in _execute
return self.cursor.execute(sql, params)
File "/opt/django/gip/venv/lib/python3.6/site-packages/django/db/backends/mysql/base.py", line 74, in execute
return self.cursor.execute(query, args)
File "/opt/django/gip/venv/lib/python3.6/site-packages/MySQLdb/cursors.py", line 206, in execute
res = self._query(query)
File "/opt/django/gip/venv/lib/python3.6/site-packages/MySQLdb/cursors.py", line 319, in _query
db.query(q)
File "/opt/django/gip/venv/lib/python3.6/site-packages/MySQLdb/connections.py", line 259, in query
_mysql.connection.query(self, query)
django.db.utils.OperationalError: (2006, 'MySQL server has gone away')
我已经尝试更改Django settings.py文件,因此我为CONN_MAX_AGE
设置了一个显式值,并且还为MySQL客户机wait_timeout
参数设置了一个值,即CONN_MAX_AGE
低于wait_timeout
设置.py:
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'OPTIONS': {
'read_default_file': '/opt/django/gip/gip/gip/my.cnf',
},
'CONN_MAX_AGE': 3600,
}
}
我的.cnf:
[client]
...
wait_timeout = 28800
不幸的是,行为完全相同:我在大约24小时内收到一个异常。在运行bot之后
将CONN_MAX_AGE
设置为None
也不会有任何区别
我按照@r-marolahy的建议安装了mysql-server-has-gone-away
python包,但它也不会有什么不同。运行了近24小时后,“消失”消息再次显示
我还尝试了关闭旧连接的方法:
from django.db import close_old_connections
try:
#do your long running operation here
except django.db.utils.OperationalError:
close_old_connections()
#do your long running operation here
仍然得到同样的结果
连接将因多种原因中断,而不仅仅是超时。 所以,简单地计划一下它的崩溃
计划A(最稳健的解决方案):
每当运行查询时,请检查错误,并使用代码重新连接并重新运行查询(或事务)
方案B(风险交易):
启用自动重新连接。如果您曾经使用多语句事务,那么这是不好的。在事务的中间自动重新连接会导致一个损坏的数据集(违反了“事务”的语义)。这是因为事务的第一部分是^ {CD1}}(由于断开连接),其余的是^ {CD2}}。p>
方案C(直截了当):
当有消息进来时连接;做好你的工作;然后断开连接。也就是说,大部分时间都是断开连接的。如果您可以有很多客户端连接(但很少做任何事情),那么这种方法是必要的
方案D(不值得考虑):
增加各种超时。当其他问题没有解决(网络故障)时,为什么还要麻烦解决一个问题(低超时)
我的偏好?C很容易,而且几乎总是足够的。A需要更多的代码,但却是“最好的”。C和A都可能更好
由于服务器超时,MySQL关闭连接时,django发生了此错误。要启用持久连接,请将
CONN_MAX_AGE
设置为秒的正整数,或将其设置为None
以实现无限持久连接(source)更新1: 如果上面建议的解决方案不起作用,您可能需要尝试mysql-server-has-gone-away包。我还没有试过,但在这种情况下可能会有所帮助
Update2:另一种尝试是尝试使用
try/except
语句捕获此OperationalError
并重置与close_old_connections
的连接更新3:如所述here
但是,Django ORM使用
asgiref.sync.sync_to_async
适配器,它只能在MySQL关闭连接之前工作。在这种情况下,使用channels.db.database_sync_to_async
(即退出时清理旧数据库连接的SyncToAsync
版本)可能会解决此问题您可以像下面那样使用它(source):
或者将其用作装饰:
确保首先遵循安装说明here
这通常是因为服务器端wait_timeout。服务器在等待超时秒后关闭连接。 您应该增加超时时间:
或者处理此类错误,重新连接并在发生错误时重试
另一个选项是定期(
wait_timeout - 1
)使用查询(如select 1
)ping服务器相关问题 更多 >
编程相关推荐