MySQL server has gone away - Disconnect-Behandlung über Kasse-event-handler funktioniert nicht
Update 3/4:
Habe ich ein paar Tests gemacht und bewiesen, dass die Verwendung von checkout-event-handler, um zu überprüfen, trennt arbeitet mit Elixier. langsam glaube mein problem hat etwas zu tun mit Berufung Update: ich habe gerade widerlegt sich selbst durch den Aufruf session.commit()
von einem Teilprozess?session.commit()
in einem Teilprozess, aktualisiert Beispiel unten. Ich bin mit dem multiprocessing-Modul zum erstellen Teilprozess.
Hier ist der code, der zeigt, wie es funktionieren sollte (auch ohne Verwendung pool_recycle
!):
from sqlalchemy import exc
from sqlalchemy import event
from sqlalchemy.pool import Pool
from elixir import *
import multiprocessing as mp
class SubProcess(mp.Process):
def run(self):
a3 = TestModel(name="monkey")
session.commit()
class TestModel(Entity):
name = Field(String(255))
@event.listens_for(Pool, "checkout")
def ping_connection(dbapi_connection, connection_record, connection_proxy):
cursor = dbapi_connection.cursor()
try:
cursor.execute("SELECT 1")
except:
# optional - dispose the whole pool
# instead of invalidating one at a time
# connection_proxy._pool.dispose()
# raise DisconnectionError - pool will try
# connecting again up to three times before raising.
raise exc.DisconnectionError()
cursor.close()
from sqlalchemy import create_engine
metadata.bind = create_engine("mysql://foo:bar@localhost/some_db", echo_pool=True)
setup_all(True)
subP = SubProcess()
a1 = TestModel(name='foo')
session.commit()
# pool size is now three.
print "Restart the server"
raw_input()
subP.start()
#a2 = TestModel(name='bar')
#session.commit()
Update 2:
Bin ich gezwungen, eine andere Lösung finden als post 1.2.2 Versionen von MySQL-python-Tropfen Unterstützung für die reconnect-param. Hat jemand eine Lösung? :\
Update 1 (alte Lösung funktioniert nicht bei MySQL-python-Versionen > 1.2.2):
Eine Lösung gefunden werden: die übergabe connect_args={'reconnect':True}
zu den create_engine
aufrufen behebt das problem, automatisch die Verbindung wiederherstellt. Gar nicht zu benötigen scheint, wird der checkout-event-handler.
So, in dem Beispiel aus der Frage:
metadata.bind = create_engine("mysql://foo:bar@localhost/db_name", pool_size=100, pool_recycle=3600, connect_args={'reconnect':True})
Ursprünglichen Frage:
Ganz ein bisschen Googeln für dieses problem und noch nicht scheinen, um eine Lösung spezifisch für Elixier - ich bin versucht, die "Trennen Sie Die Handhabung - Pessimistisch" ein Beispiel aus der SQLAlchemy-docs behandeln MySQL trennt. Allerdings, wenn ich dies testen (durch einen Neustart des MySQL-Servers), den "MySQL server has gone away" - error ausgelöst, bevor meine checkout-event-handler.
Hier ist der code, den ich verwenden, um zu initialisieren Elixier:
##### Initialize elixir/SQLAlchemy
# Disconnect handling
from sqlalchemy import exc
from sqlalchemy import event
from sqlalchemy.pool import Pool
@event.listens_for(Pool, "checkout")
def ping_connection(dbapi_connection, connection_record, connection_proxy):
logging.debug("***********ping_connection**************")
cursor = dbapi_connection.cursor()
try:
cursor.execute("SELECT 1")
except:
logging.debug("######## DISCONNECTION ERROR #########")
# optional - dispose the whole pool
# instead of invalidating one at a time
# connection_proxy._pool.dispose()
# raise DisconnectionError - pool will try
# connecting again up to three times before raising.
raise exc.DisconnectionError()
cursor.close()
metadata.bind= create_engine("mysql://foo:bar@localhost/db_name", pool_size=100, pool_recycle=3600)
setup_all()
Ich erstellen Elixier entity-Objekte und speichern Sie Sie mit session.commit()
, bei denen ich sehe die "ping_connection" - Nachricht erzeugt von der Veranstaltung, die oben definiert werden. Allerdings, wenn ich starten Sie den mysql-server und testen Sie es erneut, schlägt es mit dem mysql server has gone away-Nachricht, kurz bevor die ping-Verbindung Ereignis.
Hier ist der stack-trace, ausgehend von den relevanten Zeilen:
File "/usr/local/lib/python2.6/dist-packages/elixir/entity.py", line 1135, in get_by
return cls.query.filter_by(*args, **kwargs).first()
File "/usr/local/lib/python2.6/dist-packages/sqlalchemy/orm/query.py", line 1963, in first
ret = list(self[0:1])
File "/usr/local/lib/python2.6/dist-packages/sqlalchemy/orm/query.py", line 1857, in __getitem__
return list(res)
File "/usr/local/lib/python2.6/dist-packages/sqlalchemy/orm/query.py", line 2032, in __iter__
return self._execute_and_instances(context)
File "/usr/local/lib/python2.6/dist-packages/sqlalchemy/orm/query.py", line 2047, in _execute_and_instances
result = conn.execute(querycontext.statement, self._params)
File "/usr/local/lib/python2.6/dist-packages/sqlalchemy/engine/base.py", line 1399, in execute
params)
File "/usr/local/lib/python2.6/dist-packages/sqlalchemy/engine/base.py", line 1532, in _execute_clauseelement
compiled_sql, distilled_params
File "/usr/local/lib/python2.6/dist-packages/sqlalchemy/engine/base.py", line 1640, in _execute_context
context)
File "/usr/local/lib/python2.6/dist-packages/sqlalchemy/engine/base.py", line 1633, in _execute_context
context)
File "/usr/local/lib/python2.6/dist-packages/sqlalchemy/engine/default.py", line 330, in do_execute
cursor.execute(statement, parameters)
File "/usr/lib/pymodules/python2.6/MySQLdb/cursors.py", line 166, in execute
self.errorhandler(self, exc, value)
File "/usr/lib/pymodules/python2.6/MySQLdb/connections.py", line 35, in defaulterrorhandler
raise errorclass, errorvalue
OperationalError: (OperationalError) (2006, 'MySQL server has gone away')
- Seien Sie vorsichtig mit
reconnect
parameter, da seine Unterstützung ist nicht standard, und es auch nicht richtig funktioniert. Finden Sie hier weitere Informationen: stackoverflow.com/questions/207981/... - Danke für den Tipp, dies ist besorgniserregend, dass test-reconnect-Szenarios gründlich.
Du musst angemeldet sein, um einen Kommentar abzugeben.
Die endgültige Abhilfe Berufung war
session.remove()
im start der Methoden vor Manipulation und das laden von elixir Personen. Was dieser tut, ist es wird wieder die Verbindung an den pool, so dass wenn es wieder verwendet, die pool-out-Ereignis wird ausgelöst, und unsere handler erkennt die Trennung. Von SQLAlchemy docs:Ganz wichtiges Stück von Informationen, die ich wünschte, es waren in der erwähnten Elixier docs. Aber dann habe ich denke, es wird davon ausgegangen Vorkenntnisse mit SQLAlchemy?
das eigentliche problem ist sqlalchemy geben Sie die gleiche session bei jedem Aufruf der sessionmaker Fabrik. Aufgrund dieser kann es passieren, dass eine spätere Abfrage wird mit einer viel früheren Sitzung geöffnet, solange Sie nicht nennen
session.remove()
auf der Sitzung. Sich erinnern zu müssen, ruftremove()
jedes mal, wenn Sie eine Sitzung ist jedoch kein Spaß und sqlalchemy bietet eine viel einfachere Sache: contexual "scoped" - sessions.Erstellen eine session-scoped einfach wickeln Sie Ihre sessionmaker:
Diese Weise erhalten Sie ein contexual gebunden session bei jedem Aufruf der Fabrik, was bedeutet, sqlalchemy ruft die
session.remove()
für Sie, sobald die aufrufende Funktion beendet wird. Siehe hier: sqlalchemy - Lebensdauer einer kontextuellen SitzungSind Sie mit der gleichen session für beide (vor und nach der mysqld neu starten) Operationen? Wenn dem so ist, die
"checkout"
Ereignis tritt nur auf, wenn neue Transaktion gestartet wird. Wenn Sie anrufencommit()
die neue Transaktion wird gestartet (wenn Sie den autocommit-Modus) und die Verbindung geprüft wird. So starten Sie mysqld nach Kasse.Den einfachen hack mit
commit()
oderrollback()
Anruf kurz vor der zweiten operation (und nach dem Neustart von mysqld) sollte dein problem lösen. Anders überlege mit dem neuen, frischen Sitzung jedes mal, wenn Sie warten lange Zeit nach der vorherigen commit.elixir.session
undsetup_all()
nicht verwenden session überhaupt. Sorry, mein Tipp zur Verwendung von frischen session ist eher für Reine SQLAlchemy, es nicht mit Active Record pattern verwendet Elixier. Abercommit()
/rollback()
hack sollte trotzdem funktionieren.Ich bin mir nicht sicher, ob dies das gleiche problem, dass ich hatte, aber hier geht:
Als ich bei der
MySQL server has gone away
ich löste es mitcreate_engine(..., pool_recycle=3600)
finden Sie http://www.sqlalchemy.org/docs/dialects/mysql.html#connection-timeoutspool_recycle=3
was noch nicht funktioniert :\