fix: address PostgreSQL too many clients by adding CONN_MAX_AGE and fixing pool OPTIONS merge

Agent-Logs-Url: https://github.com/suitenumerique/docs/sessions/e16a8fd1-46f1-4536-830d-bfe68e43ea29

Co-authored-by: AntoLC <25994652+AntoLC@users.noreply.github.com>
This commit is contained in:
copilot-swe-agent[bot] 2026-03-30 18:17:30 +00:00 committed by GitHub
parent f166e75921
commit 0379bbaab5
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 43 additions and 25 deletions

View file

@ -41,7 +41,8 @@ These are the environment variables you can set for the `impress-backend` contai
| CONVERSION_FILE_MAX_SIZE | The file max size allowed when uploaded to convert it | 20971520 (20MB) |
| CONVERSION_FILE_EXTENSIONS_ALLOWED | Extension list managed by the conversion service | [".docx", ".md"] |
| CRISP_WEBSITE_ID | Crisp website id for support | |
| DB_ENGINE | Engine to use for database connections | django.db.backends.postgresql_psycopg2 |
| DB_CONN_MAX_AGE | Maximum lifetime of a database connection in seconds. Use 0 to close connections at the end of each request (default). When using the psycopg pool, set to 0 so connections are returned to the pool after each request. | 0 |
| DB_ENGINE | Engine to use for database connections | django.db.backends.postgresql |
| DB_HOST | Host of the database | localhost |
| DB_NAME | Name of the database | impress |
| DB_PASSWORD | Password to authenticate with | pass |

View file

@ -30,6 +30,20 @@ def test_invalid_settings_oidc_email_configuration():
)
def test_settings_conn_max_age_default():
"""
Test that DB_CONN_MAX_AGE defaults to 0 (close connections at the end of each request).
CONN_MAX_AGE is defined in the DATABASES class body and resolved by django-configurations
at class setup time, so no post_setup() call is required here.
"""
class TestSettings(Base):
"""Fake test settings."""
assert TestSettings.DATABASES["default"]["CONN_MAX_AGE"] == 0
def test_settings_psycopg_pool_not_enabled():
"""
Test that not changing DB_PSYCOPG_POOL_ENABLED should not configure psycopg in the DATABASES

View file

@ -99,6 +99,15 @@ class Base(Configuration):
"localhost", environ_name="DB_HOST", environ_prefix=None
),
"PORT": values.Value(5432, environ_name="DB_PORT", environ_prefix=None),
# Maximum lifetime of a database connection in seconds.
# Use 0 to close connections at the end of each request.
# Use None for unlimited persistent connections.
# When using the psycopg pool (DB_PSYCOPG_POOL_ENABLED), set this to 0
# so that connections are returned to the pool after each request.
"CONN_MAX_AGE": values.IntegerValue(
0, environ_name="DB_CONN_MAX_AGE", environ_prefix=None
),
"OPTIONS": {},
# Psycopg pool can be configured in the post_setup method
}
}
@ -1113,30 +1122,24 @@ class Base(Configuration):
)
if psycopg_pool_enabled:
cls.DATABASES["default"].update(
{
"OPTIONS": {
# https://www.psycopg.org/psycopg3/docs/api/pool.html#psycopg_pool.ConnectionPool
"pool": {
"min_size": values.IntegerValue(
4,
environ_name="DB_PSYCOPG_POOL_MIN_SIZE",
environ_prefix=None,
),
"max_size": values.IntegerValue(
None,
environ_name="DB_PSYCOPG_POOL_MAX_SIZE",
environ_prefix=None,
),
"timeout": values.IntegerValue(
3,
environ_name="DB_PSYCOPG_POOL_TIMEOUT",
environ_prefix=None,
),
}
},
}
)
# https://www.psycopg.org/psycopg3/docs/api/pool.html#psycopg_pool.ConnectionPool
cls.DATABASES["default"].setdefault("OPTIONS", {})["pool"] = {
"min_size": values.IntegerValue(
4,
environ_name="DB_PSYCOPG_POOL_MIN_SIZE",
environ_prefix=None,
),
"max_size": values.IntegerValue(
None,
environ_name="DB_PSYCOPG_POOL_MAX_SIZE",
environ_prefix=None,
),
"timeout": values.IntegerValue(
3,
environ_name="DB_PSYCOPG_POOL_TIMEOUT",
environ_prefix=None,
),
}
class Build(Base):