Last active
March 20, 2018 16:27
-
-
Save zzzeek/b762218a5f855ec7d1c3a998fe996893 to your computer and use it in GitHub Desktop.
illustrate pymysql DB connection causing errors which resolve when we make sure they are recycled in greenletexit
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import eventlet | |
eventlet.monkey_patch() | |
import itertools | |
import pymysql | |
import random | |
from eventlet.green import time | |
import greenlet | |
def connect(): | |
return pymysql.connect(user="scott", passwd="tiger", host="127.0.0.1", db="test") | |
greenlet_id = itertools.count(1) | |
def do_work(connections, conn_index): | |
our_id = next(greenlet_id) | |
conn = connections[conn_index] | |
while True: | |
try: | |
print("greenlet %d working..." % our_id) | |
cursor = conn.cursor() | |
for i in range(10): | |
cursor.execute( | |
"insert into stuff (data) values (%s)", | |
(("some_data_%f" % random.random()), ) | |
) | |
cursor.close() | |
conn.commit() | |
cursor = conn.cursor() | |
cursor.execute("select sleep(%s)", (random.random(), )) | |
time.sleep(random.random()) | |
if cursor.description is None: | |
raise Exception("cursor.description not supposed to be none") | |
cursor.fetchall() | |
cursor.close() | |
conn.rollback() | |
time.sleep(random.random()) | |
except pymysql.Error as err: | |
print("error occurred, invalidating connection: %s" % err) | |
conn.rollback() | |
conn.close() | |
conn = connections[conn_index] = connect() | |
except Exception as err: | |
print("totally unexpected error occurred: %r" % err) | |
except greenlet.GreenletExit as ex: | |
print("exit exception: %r" % ex) | |
if ensure_greenlet_exit_handled: | |
conn.close() | |
conn = connections[conn_index] = connect() | |
break | |
if __name__ == '__main__': | |
ensure_greenlet_exit_handled = False | |
num = 10 | |
conn = connect() | |
cursor = conn.cursor() | |
cursor.execute("drop table if exists stuff") | |
cursor.execute( | |
"create table stuff(id integer primary key auto_increment, " | |
"data varchar(200))") | |
cursor.close() | |
conn.commit() | |
connections = [connect() for i in range(num)] | |
greenlets = [ | |
eventlet.spawn(do_work, connections, idx) | |
for idx in range(num)] | |
while True: | |
for idx in range(num): | |
time.sleep(random.random()) | |
print("kill...") | |
eventlet.greenthread.kill(greenlets[idx]) | |
time.sleep(.5) | |
greenlets[idx] = eventlet.spawn(do_work, connections, idx) | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
see also https://bitbucket.org/zzzeek/sqlalchemy/issues/3803/dbapi-connections-go-invalid-on