8

Ich bin mir nicht sicher, ob dies möglich ist, aber ich suche nach einer Möglichkeit, die Verbindung zur mysql-Datenbank wiederherzustellen, wenn die Verbindung verloren ist. Alle Verbindungen werden in einer Warteschlange gehalten, aber das sollte nicht wichtig sein, denke ich. Ich bin mir sicher, wenn ich etwas Zeit hineinlege, kann ich mir eine Möglichkeit vorstellen, mich wieder mit der Datenbank zu verbinden. Allerdings warf ich einen Blick auf den Pymysql-Code, und ich sah, dass es in der Connection-Klasse eine 'ping' -Methode gibt, von der ich nicht genau weiß, wie sie zu verwenden ist.Python mysql (mit pymysql) automatische Wiederverbindung

Die Methode sieht so aus, als ob sie das erste Mal wieder verbindet, aber danach hat sie das Reconnect Flag wieder auf False gesetzt? Kann ich diese Methode verwenden oder gibt es eine andere Möglichkeit, die Verbindung herzustellen, wenn sie verloren geht? Auch wenn es nicht pymysql ist, wie gehen Leute an, Datenbank-Server gehen und Verbindung zum mysql Server wieder herstellen müssen?

def ping(self, reconnect=True): 
    ''' Check if the server is alive ''' 
    if self.socket is None: 
     if reconnect: 
      self._connect() 
      reconnect = False 
     else: 
      raise Error("Already closed") 
    try: 
     self._execute_command(COM_PING, "") 
     return self._read_ok_packet() 
    except Exception: 
     if reconnect: 
      self._connect() 
      return self.ping(False) 
     else: 
      raise 
+0

nicht sicher, ob dies von Nutzen sein wird, aber einen Blick auf dieses ReconnectingConnectionPool Rezept für Twisted nehmen https://gist.github.com/powdahound/174056 –

+1

ich es implementiert haben - https: // Kern .github.com/opensourcegeek/9822127 – opensourcegeek

+0

Pinging vor dem Ausführen einer Abfrage wird als ein Anti-Pattern betrachtet, das Ressourcen verschwendet und unzuverlässig ist: https://www.percona.com/blog/2010/05/05/checking-for-a -Live-Datenbank-Verbindung-als schädlich / –

Antwort

10

Endlich eine funktionierende Lösung, könnte jemand helfen.

from gevent import monkey 
monkey.patch_socket() 
import logging 

import gevent 
from gevent.queue import Queue 
import pymysql as db 

logging.basicConfig(level=logging.DEBUG) 
LOGGER = logging.getLogger("connection_pool") 


class ConnectionPool: 
    def __init__(self, db_config, time_to_sleep=30, test_run=False): 
     self.username = db_config.get('user') 
     self.password = db_config.get('password') 
     self.host = db_config.get('host') 
     self.port = int(db_config.get('port')) 
     self.max_pool_size = 20 
     self.test_run = test_run 
     self.pool = None 
     self.time_to_sleep = time_to_sleep 
     self._initialize_pool() 

    def get_initialized_connection_pool(self): 
     return self.pool 

    def _initialize_pool(self): 
     self.pool = Queue(maxsize=self.max_pool_size) 
     current_pool_size = self.pool.qsize() 
     if current_pool_size < self.max_pool_size: # this is a redundant check, can be removed 
      for _ in xrange(0, self.max_pool_size - current_pool_size): 
       try: 
        conn = db.connect(host=self.host, 
             user=self.username, 
             passwd=self.password, 
             port=self.port) 
        self.pool.put_nowait(conn) 

       except db.OperationalError, e: 
        LOGGER.error("Cannot initialize connection pool - retrying in {} seconds".format(self.time_to_sleep)) 
        LOGGER.exception(e) 
        break 
     self._check_for_connection_loss() 

    def _re_initialize_pool(self): 
     gevent.sleep(self.time_to_sleep) 
     self._initialize_pool() 

    def _check_for_connection_loss(self): 
     while True: 
      conn = None 
      if self.pool.qsize() > 0: 
       conn = self.pool.get() 

      if not self._ping(conn): 
       if self.test_run: 
        self.port = 3306 

       self._re_initialize_pool() 

      else: 
       self.pool.put_nowait(conn) 

      if self.test_run: 
       break 
      gevent.sleep(self.time_to_sleep) 

    def _ping(self, conn): 
     try: 
      if conn is None: 
       conn = db.connect(host=self.host, 
            user=self.username, 
            passwd=self.password, 
            port=self.port) 
      cursor = conn.cursor() 
      cursor.execute('select 1;') 
      LOGGER.debug(cursor.fetchall()) 
      return True 

     except db.OperationalError, e: 
      LOGGER.warn('Cannot connect to mysql - retrying in {} seconds'.format(self.time_to_sleep)) 
      LOGGER.exception(e) 
      return False 

# test (pytest compatible) ------------------------------------------------------------------------------------------- 
import logging 

from src.py.ConnectionPool import ConnectionPool 

logging.basicConfig(level=logging.DEBUG) 
LOGGER = logging.getLogger("test_connection_pool") 


def test_get_initialized_connection_pool(): 
    config = { 
     'user': 'root', 
     'password': '', 
     'host': '127.0.0.1', 
     'port': 3305 
    } 
    conn_pool = ConnectionPool(config, time_to_sleep=5, test_run=True) 
    pool = conn_pool.get_initialized_connection_pool() 
    # when in test run the port will be switched back to 3306 
    # so the queue size should be 20 - will be nice to work 
    # around this rather than test_run hack 
    assert pool.qsize() == 20