Add db connection pooling

This commit is contained in:
Peter Stockings
2025-07-23 21:58:43 +10:00
parent b5acb9e93e
commit a4c29e0d8f
3 changed files with 47 additions and 32 deletions

4
app.py
View File

@@ -204,3 +204,7 @@ if __name__ == '__main__':
# Bind to PORT if defined, otherwise default to 5000. # Bind to PORT if defined, otherwise default to 5000.
port = int(os.environ.get('PORT', 5000)) port = int(os.environ.get('PORT', 5000))
app.run(host='127.0.0.1', port=port) app.run(host='127.0.0.1', port=port)
@app.teardown_appcontext
def teardown_db(exception):
db.close_conn()

48
db.py
View File

@@ -1,51 +1,61 @@
import json import json
import os import os
import psycopg2 import psycopg2
from psycopg2 import pool
from psycopg2.extras import RealDictCursor from psycopg2.extras import RealDictCursor
from urllib.parse import urlparse from urllib.parse import urlparse
from flask import g from flask import g
class DataBase(): class DataBase():
def __init__(self, app=None): def __init__(self):
self.pool = None
def init_app(self, app):
db_url = urlparse(os.environ['DATABASE_URL']) db_url = urlparse(os.environ['DATABASE_URL'])
# if db_url is null then throw error
if not db_url: if not db_url:
raise Exception("No DATABASE_URL environment variable set") raise Exception("No DATABASE_URL environment variable set")
def getDB(self): self.pool = psycopg2.pool.SimpleConnectionPool(
db = getattr(g, 'database', None) 1, 20,
if db is None:
db_url = urlparse(os.environ['DATABASE_URL'])
g.database = psycopg2.connect(
database=db_url.path[1:], database=db_url.path[1:],
user=db_url.username, user=db_url.username,
password=db_url.password, password=db_url.password,
host=db_url.hostname, host=db_url.hostname,
port=db_url.port port=db_url.port
) )
db = g.database
return db
def close_connection(exception): app.teardown_appcontext(self.close_conn)
db = getattr(g, 'database', None)
if db is not None: def get_conn(self):
db.close() if 'db_conn' not in g:
g.db_conn = self.pool.getconn()
return g.db_conn
def close_conn(self, e=None):
db_conn = g.pop('db_conn', None)
if db_conn is not None:
self.pool.putconn(db_conn)
def close_all_connections(self):
if self.pool:
self.pool.closeall()
def execute(self, query, args=(), one=False, commit=False): def execute(self, query, args=(), one=False, commit=False):
conn = self.getDB() conn = self.get_conn()
cur = conn.cursor(cursor_factory=RealDictCursor) cur = conn.cursor(cursor_factory=RealDictCursor)
try:
cur.execute(query, args) cur.execute(query, args)
rv = None rv = None
if cur.description is not None: if cur.description is not None:
rv = cur.fetchall() rv = cur.fetchall()
if commit: if commit:
try:
conn.commit() conn.commit()
except:
conn.rollback()
cur.close()
return (rv[0] if rv else None) if one else rv return (rv[0] if rv else None) if one else rv
except Exception as e:
conn.rollback()
raise e
finally:
cur.close()
def get_http_functions_for_user(self, user_id): def get_http_functions_for_user(self, user_id):
http_functions = self.execute( http_functions = self.execute(

View File

@@ -16,6 +16,7 @@ environment = Environment(
def init_app(app): def init_app(app):
htmx.init_app(app) htmx.init_app(app)
db.init_app(app)
# Add all Flask's default Jinja2 globals and filters # Add all Flask's default Jinja2 globals and filters
environment.globals.update( environment.globals.update(