Introduction

When you’re building a Flask app that interacts with a database, one of the key things to take care of is how efficiently your app connects to that database. Every time a user sends a request, your app connects to the database to fetch or update information. If your app has to open a new connection each time, it will become slow, especially when traffic increases. This is where database connection pooling comes into play.

In this blog, we’ll explain what connection pooling is, why it’s important for Flask apps, and how you can set it up for popular databases like PostgreSQL, MySQL, and SQLite. We’ll also look at some best practices for using connection pools efficiently.


What is a Database Connection Pool?

A database connection pool is like a collection of database connections that your app can reuse instead of creating a new connection for every single request. Think of it like a taxi stand where taxis (connections) are waiting to take passengers (requests) whenever needed. Once a request finishes, the connection is returned to the pool, ready for the next one.

Why Do We Need Connection Pooling in Flask?

  • Faster Performance: By reusing connections, your app doesn’t waste time opening new connections for each request.
  • Better Resource Management: Connection pooling helps avoid overloading the database by limiting the number of open connections.
  • Scalable Apps: As your app grows and traffic increases, connection pooling allows your app to handle more users without hitting a wall.

Setting Up Connection Pooling in Flask

Let’s look at how you can set up connection pools in Flask for PostgreSQL, MySQL, and SQLite.


1. PostgreSQL Connection Pooling with psycopg2

PostgreSQL is a popular choice for production Flask apps. To enable connection pooling, you can use the psycopg2 library with SimpleConnectionPool. Below is a simple setup:

import psycopg2
from psycopg2.pool import SimpleConnectionPool
from flask import Flask, g

app = Flask(__name__)

# Set up the connection pool
pool = SimpleConnectionPool(
    minconn=1, 
    maxconn=10,
    user="your_user", 
    password="your_password", 
    host="localhost", 
    port="5432", 
    database="your_database"
)

def get_db():
    if 'db' not in g:
        g.db = pool.getconn()
    return g.db

@app.teardown_appcontext
def close_db(error):
    db = g.pop('db', None)
    if db is not None:
        pool.putconn(db)

@app.route('/')
def index():
    conn = get_db()
    with conn.cursor() as cursor:
        cursor.execute("SELECT * FROM my_table")
        data = cursor.fetchall()
    return str(data)

if __name__ == '__main__':
    app.run(debug=True)
  • How it works: The SimpleConnectionPool creates a pool with a minimum of 1 and a maximum of 10 connections. Flask’s g object holds the connection for the duration of the request, and when the request ends, the connection is returned to the pool.

2. MySQL Connection Pooling with mysql-connector

For MySQL users, setting up a connection pool is also easy. Here’s how you can use mysql-connector to do it:

import mysql.connector.pooling
from flask import Flask, g

app = Flask(__name__)

# Set up the connection pool
connection_pool = mysql.connector.pooling.MySQLConnectionPool(
    pool_name="my_pool",
    pool_size=5,
    user="your_user",
    password="your_password",
    host="localhost",
    database="your_database"
)

def get_db():
    if 'db' not in g:
        g.db = connection_pool.get_connection()
    return g.db

@app.teardown_appcontext
def close_db(error):
    db = g.pop('db', None)
    if db is not None:
        db.close()

@app.route('/')
def index():
    conn = get_db()
    cursor = conn.cursor()
    cursor.execute("SELECT * FROM my_table")
    results = cursor.fetchall()
    cursor.close()
    return str(results)

if __name__ == '__main__':
    app.run(debug=True)
  • How it works: This example sets up a connection pool with a maximum size of 5 connections. Flask automatically closes the connection when the request is done.

3. SQLite Connection Pooling

SQLite is different from PostgreSQL or MySQL. It doesn’t require as many connections because it’s often used for small apps or in a development environment. However, you can still use a pool with SQLAlchemy’s SingletonThreadPool.

from sqlalchemy import create_engine
from flask import Flask

app = Flask(__name__)

# Set up SQLite connection with SingletonThreadPool
engine = create_engine(
    'sqlite:///my_database.db',
    poolclass=SingletonThreadPool
)

@app.route('/')
def index():
    with engine.connect() as connection:
        result = connection.execute("SELECT * FROM my_table")
        data = result.fetchall()
    return str(data)

if __name__ == '__main__':
    app.run(debug=True)
  • How it works: SingletonThreadPool makes sure that each thread uses one connection at a time, which is usually enough for SQLite in smaller apps.

Advanced Connection Pooling with SQLAlchemy

If you’re using SQLAlchemy with Flask, you get a robust connection pooling system out of the box. SQLAlchemy’s connection pooling integrates directly with the create_engine() function, providing flexibility and control over your database connections.

Here’s how you can set up a pool using SQLAlchemy’s QueuePool, which is the default pool used for most applications.

from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker

# Configure engine with QueuePool for pooling
engine = create_engine(
    "postgresql://user:password@localhost/mydb", 
    pool_size=10, 
    max_overflow=20
)

Session = sessionmaker(bind=engine)

@app.route('/')
def index():
    session = Session()
    result = session.execute("SELECT * FROM my_table")
    return str(result.fetchall())
  • How it works:
    • QueuePool: This pool handles concurrent connections by maintaining a fixed pool_size and allowing extra connections via max_overflow. In the example above, the pool will maintain up to 10 connections, and in case of extra demand, it can create up to 20 additional connections.
    • Session Management: We use sessionmaker to bind the pool to a session and execute queries.

Other Advanced Features of SQLAlchemy’s Connection Pooling:

  • Pre-Ping Connections: SQLAlchemy can automatically check if a connection is alive before using it, preventing errors from stale connections. You can enable this using pool_pre_ping=True.
engine = create_engine(
    "mysql+pymysql://user:password@localhost/mydb", 
    pool_pre_ping=True
)
  • Connection Recycling: SQLAlchemy also supports connection recycling, where old connections are closed and replaced after a certain amount of time, reducing the risk of database timeouts.

Best Practices for Connection Pooling in Flask

Now that you know how to set up connection pooling, here are a few tips to make sure your setup is efficient:

  1. Choose the Right Pool Size:
    • If your app is small or in development, a pool size of 5-10 connections is usually enough.
    • For larger apps, you might need a bigger pool depending on the traffic.
  2. Use Pre-Ping:
    • Some connections can become stale if they aren’t used for a long time. Use pre-ping to check if the connection is still alive before using it.
  3. Recycle Connections:
    • Set a pool_recycle time to avoid keeping connections open for too long, which might cause timeouts, especially in databases like MySQL.
  4. Monitor Your Database Connections:
    • Keep an eye on your database activity using tools like pg_stat_activity for PostgreSQL or SHOW PROCESSLIST for MySQL. This helps in adjusting the pool size based on actual usage.
  5. Use SQLAlchemy for ORM and Pooling:
    • If you are using SQLAlchemy with Flask, it automatically handles connection pooling through create_engine(), making your life easier. Here’s how you can use it:
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker

engine = create_engine(
    "postgresql://user:password@localhost/mydb", 
    pool_size=10, 
    max_overflow=20
)

Session = sessionmaker(bind=engine)

@app.route('/')
def index():
    session = Session()
    result = session.execute("SELECT * FROM my_table")
    return str(result.fetchall())

Conclusion

Connection pooling is one of the simplest ways to make your Flask app faster and more efficient. Whether you are using PostgreSQL, MySQL, or SQLite, a properly configured connection pool will reduce database connection time and improve scalability.

By following the steps and best practices outlined in this guide, you can ensure that your Flask app is ready to handle anything, from small traffic to large-scale production use.

With these simple optimizations, your app can serve users quickly and efficiently, without overwhelming your database.

Categorized in: