[mythtv-commits] Ticket #13320: Python bindings not reconnecting to database after a long pause.
MythTV
noreply at mythtv.org
Sun Sep 16 20:56:36 UTC 2018
#13320: Python bindings not reconnecting to database after a long pause.
----------------------------------+--------------------------------
Reporter: sir-maniac | Owner: Raymond Wagner
Type: Bug Report - General | Status: new
Priority: minor | Milestone: needs_triage
Component: Bindings - Python | Version: Unspecified
Severity: medium | Resolution:
Keywords: | Ticket locked: 0
----------------------------------+--------------------------------
Comment (by rcrdnalor):
It seems to me, that this bug hides additional bugs:
For convenience, I add this piece of code in question here:
https://github.com/MythTV/mythtv/blob/master/mythtv/bindings/python/MythTV/_conn_mysqldb.py#L29
{{{
class LoggedCursor( MySQLdb.cursors.Cursor ):
"""
Custom cursor, offering logging and error handling
"""
def __init__(self, connection):
super(LoggedCursor, self).__init__(connection)
self.log = None
self.ping = ref(self._ping121)
if MySQLdb.version_info >= ('1','2','2'):
self.ping = ref(self._ping122)
self.ping()
def _ping121(self): self._get_db().ping(True)
def _ping122(self): self._get_db().ping()
}}}
1) According help of the python's MySQLdb driver, the statement
`ping(True)` was implemented in version 1.2.2.
See
{{{
>>> import MySQLdb
>>> help(MySQLdb._mysql.connection.ping)
Help on method_descriptor:
ping(...)
Checks whether or not the connection to the server is
working. If it has gone down, an automatic reconnection is
attempted.
This function can be used by clients that remain idle for a
long while, to check whether or not the server has closed the
connection and reconnect if necessary.
New in 1.2.2: Accepts an optional reconnect parameter. If True,
then the client will attempt reconnection. Note that this setting
is persistent. By default, this is on in MySQL<5.0.3, and off
thereafter.
Non-standard. You should assume that ping() performs an
implicit rollback; use only when starting a new transaction.
You have been warned
}}}
Note: The code in question implies the opposite.
2) I wrote a small test (see attachment), that checks the behavior of a
timed-out connection from MythTV's python bindings to mysql.
Note, that the default timeouts seem to be 8 hours, therefore I needed to
shorten them.
But other installations may override this to a much smaller value.
If I use `_ping122(), the timed out connection raises an uncaught
exception:
{{{
_mysql_exceptions.OperationalError: (2006, 'MySQL server has gone away')
}}}
If I use `_ping121(), the timed out connection reconnects to mysql.
This makes me think, that the ping with the `True` argument should be used
(`_ping121()`), even on systems with never versions of MySQLdb.
Note, that the statement about the reconnect setting in the help of
`ping()` is not entirely true:
{{{
By default, this is on in MySQL<5.0.3, and off thereafter.
}}}
On my systems, I get
{{{
MYSQL version : 10.1.34-MariaDB-0ubuntu0.18.04.1:
$ mariadb --help | grep '^reconnect'
reconnect TRUE
or
MYSQL version : 5.5.59-0ubuntu0.14.04.1:
$ mysql --help | grep ^reconnect
reconnect TRUE
}}}
The auto-reconnect feature is on by default on my installations.
Nevertheless, I get this trace-back `MySQL server has gone away` in my
test script, but mysql should automatically reconnect.
That's bad. See below for a proposed solution.
3) The `self.ping()` method of the class `LoggedCursor` is a weak
reference, which seems to be a left-over from #12491
See commit
https://github.com/MythTV/mythtv/commit/eb622a4b71943ce16d2fb7623cbabccd863172c4
of ticket #12491.
Please correct me, if I am wrong.
If I change these weak references to ping to a real references,
I can ping now the MySQLdb connection with both methods, without loosing
the connection to mysql.
And, I can use the `LoggedCursor.ping()` method from outside without any
problems.
Conclusio:
IMHO, the mentioned code snipped should look like this:
{{{
class LoggedCursor( MySQLdb.cursors.Cursor ):
"""
Custom cursor, offering logging and error handling
"""
def __init__(self, connection):
super(LoggedCursor, self).__init__(connection)
self.log = None
self.ping = self._ping121 ### XXX no weak
refererence
if MySQLdb.version_info[:3] >= (1, 2, 2): ### XXX correct
comparison
self.ping = self._ping122 ### XXX no weak
reference
self.ping()
def _ping121(self): self._get_db().ping() ### XXX correct API
of ping() for older versions
def _ping122(self): self._get_db().ping(True) ### XXX correct API
of ping() for newer versions
}}}
Please look at my attached script and the result.
--
Ticket URL: <https://code.mythtv.org/trac/ticket/13320#comment:3>
MythTV <http://www.mythtv.org>
MythTV Media Center
More information about the mythtv-commits
mailing list