dak ブログ

python、rubyなどのプログラミング、MySQL、サーバーの設定などの備忘録。レゴの写真も。

MySQL の Connection Pool

2023-01-05 23:13:44 | mysql
python の MySQL ライブラリでは、コネクションプールにコネクションがなくなると queue の例外が発生するため、例外を発生させずにブロックして待ち続けるか、タイムアウトさせるかを指定できるようにしてみました。

ブロックするには MySQLTimeoutConnectionPool(block=True) を指定します。
また、タイムアウトさせるには MySQLTimeoutConnectionPool(block=True, timeout=秒数) を指定します。

mysql-connector-python のプログラムを流用しています。
https://github.com/mysql/mysql-connector-python/blob/master/lib/mysql/connector/pooling.py

■ライブラリ
# -*- coding:utf-8 -*-
#
# MySQL Timeout Connection Pool
#

import threading
import queue
from mysql.connector.pooling import MySQLConnectionPool
from mysql.connector.pooling import PooledMySQLConnection
from mysql.connector.errors import PoolError


class MySQLTimeoutConnectionPool(MySQLConnectionPool):
    def __init__(self,
                 block=True, timeout=0,
                 pool_size=5, pool_name=None,
                 pool_reset_session=True,
                 **kwargs):
        self.block = block
        self.timeout = timeout
        super().__init__(pool_size=pool_size, pool_name=pool_name,
                         pool_reset_session=pool_reset_session,
                         **kwargs)


    def get_connection(self):
        with threading.RLock():
            try:
                cnx = self._cnx_queue.get(block=self.block,
                                          timeout=self.timeout)
            except queue.Empty as err:
                raise PoolError("Failed getting connection; pool exhausted") from err

            if (
                not cnx.is_connected()
                or self._config_version != cnx.pool_config_version
            ):
                cnx.config(**self._cnx_config)
                try:
                    cnx.reconnect()
                except InterfaceError:
                    self._queue_connection(cnx)
                    raise
                cnx.pool_config_version = self._config_version

            return PooledMySQLConnection(self, cnx)

■テスト用プログラム
コネクションを取得できない場合、5秒でタイムアウトさせます。
# -*- coding:utf-8 -*-

import sys
import time
sys.path.append('../../lib')
from mysql_timeout_connection_pool import MySQLTimeoutConnectionPool

config = {
    'host': '127.0.0.1',
    'port': 3306,
    'database': 'test1',
    'user': 'root',
    'password': None,
    'pool_size': 2,
    'block': True,
    'timeout': 5,
}

def main():
    conn_pool = MySQLTimeoutConnectionPool(
        host=config['host'],
        port=config['port'],
        database=config['database'],
        user=config['user'],
        password=config['password'],
        pool_size=config['pool_size'],
        block=config['block'],
        timeout=config['timeout']
    )

    try:
        conn1 = conn_pool.get_connection()
        print(f"conn1: {time.time()}")
        conn2 = conn_pool.get_connection()
        print(f"conn2: {time.time()}")
        conn3 = conn_pool.get_connection()
        print(f"conn3: {time.time()}")
    except Exception as e:
        print(f"exception: {time.time()}")
        print(e)

    return 0

if __name__ == '__main__':
    res = main()
    exit(res)

■実行結果
2つめのコネクションを取得し、5秒後にタイムアウトしています。
$ python test1.py
conn1: 1672927735.0839279
conn2: 1672927735.0845752
exception: 1672927740.0888727
Failed getting connection; pool exhausted


この記事についてブログを書く
« JavaScript で画像の各ピクセ... | トップ | Typescript で sharp による... »

mysql」カテゴリの最新記事