├── mysql_server_has_gone_away ├── __init__.py └── base.py ├── .gitignore ├── GUIDE.md ├── setup.py ├── README.md └── LICENSE /mysql_server_has_gone_away/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | dist 2 | mysql_server_has_gone_away.egg-info 3 | .idea -------------------------------------------------------------------------------- /GUIDE.md: -------------------------------------------------------------------------------- 1 | to publish: 2 | 1. Create api token on [pypi](https://pypi.org/manage/account/token/) 3 | 1. python3 -m pip install --user --upgrade twine 4 | 1. python3 setup.py sdist 5 | 1. python3 -m twine upload dist/* -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | from setuptools import setup, find_packages 2 | 3 | with open("README.md", "r") as fh: 4 | long_description = fh.read() 5 | 6 | setup( 7 | name="mysql_server_has_gone_away", 8 | version="1.0.0", 9 | description="Django myslq backend that fixes issue with long living connection", 10 | author='Andrew Koidan', 11 | author_email='deathangel908@gmail.com', 12 | license="MIT", 13 | url='https://github.com/akoidan/MySQL-server-has-gone-away', 14 | long_description=long_description, 15 | packages=find_packages(), 16 | long_description_content_type="text/markdown", 17 | ) 18 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # MySQL-server-has-gone-away 2 | 3 | This repository solves issue where database connection inside of django overlives MySQL database connection timeout specified in `/etc/my.cnf` `wait_timeout = xxxx`. [See this issue](https://stackoverflow.com/questions/26958592/django-after-upgrade-mysql-server-has-gone-away) 4 | 5 | 6 | ## How to use: 7 | 1. For Django 1.x and 2.x use `pip install mysql_server_has_gone_away==1.0.0` 8 | 9 | 1. For django 3.x use `pip install mysql_server_has_gone_away==2.0.0` 10 | 11 | 1. Put this engine into Django `settings.py`: 12 | 13 | ```python 14 | DATABASES = { 15 | 'default': { 16 | 'ENGINE': 'mysql_server_has_gone_away', 17 | #'NAME': 'database-name', 18 | #'USER': 'database-user', 19 | #'PASSWORD': 'database-password', 20 | #'HOST': 'localhost', 21 | } 22 | } 23 | ``` 24 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Andrew 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /mysql_server_has_gone_away/base.py: -------------------------------------------------------------------------------- 1 | """ 2 | https://stackoverflow.com/a/60894948/3872976 3 | """ 4 | 5 | import logging 6 | 7 | from django.db import OperationalError, InterfaceError, IntegrityError 8 | from django.db.backends.mysql import base 9 | 10 | logger = logging.getLogger('mysql_server_has_gone_away') 11 | 12 | def check_mysql_gone_away(db_wrapper): 13 | def decorate(f): 14 | def wrapper(self, query, args=None): 15 | try: 16 | return f(self, query, args) 17 | except (OperationalError, InterfaceError) as e: 18 | logger.warn("MySQL server has gone away. Rerunning query: %s", query) 19 | if ( 20 | 'MySQL server has gone away' in str(e) or 21 | 'Lost connection to MySQL server during query' in str(e) 22 | ): 23 | db_wrapper.connection.close() 24 | db_wrapper.connect() 25 | self.cursor = db_wrapper.connection.cursor() 26 | return f(self, query, args) 27 | # Map some error codes to IntegrityError, since they seem to be 28 | # misclassified and Django would prefer the more logical place. 29 | if e.args[0] in self.codes_for_integrityerror: 30 | raise IntegrityError(*tuple(e.args)) 31 | raise 32 | return wrapper 33 | 34 | return decorate 35 | 36 | 37 | class DatabaseWrapper(base.DatabaseWrapper): 38 | 39 | def create_cursor(self, name=None): 40 | 41 | class CursorWrapper(base.CursorWrapper): 42 | 43 | @check_mysql_gone_away(self) 44 | def execute(self, query, args=None): 45 | return self.cursor.execute(query, args) 46 | 47 | @check_mysql_gone_away(self) 48 | def executemany(self, query, args): 49 | return self.cursor.executemany(query, args) 50 | 51 | cursor = self.connection.cursor() 52 | return CursorWrapper(cursor) 53 | --------------------------------------------------------------------------------