2
0
mirror of https://github.com/inventree/InvenTree.git synced 2026-06-06 08:54:24 +00:00

[db] Postgresql setup (#12051)

* Adjust default postgres connection settings

* Support tcp_user_timeout

* Set application name based on running context

* Add CONN_MAX_AGE and CONN_HEALTH_CHECKS

* Add connection timeout option for mysql
This commit is contained in:
Oliver
2026-05-31 10:09:17 +10:00
committed by GitHub
parent 1e190f112f
commit 5d6d9f37cc
2 changed files with 52 additions and 13 deletions
+8 -3
View File
@@ -256,6 +256,9 @@ The following database options can be configured:
{{ configsetting("INVENTREE_DB_PASSWORD") }} Database password (if required) | {{ configsetting("INVENTREE_DB_PASSWORD") }} Database password (if required) |
{{ configsetting("INVENTREE_DB_HOST") }} Database host address (if required) | {{ configsetting("INVENTREE_DB_HOST") }} Database host address (if required) |
{{ configsetting("INVENTREE_DB_PORT") }} Database host port (if required) | {{ configsetting("INVENTREE_DB_PORT") }} Database host port (if required) |
{{ configsetting("INVENTREE_DB_CONN_MAX_AGE") }} Database connection max age (s) |
{{ configsetting("INVENTREE_DB_CONN_HEALTH_CHECKS") }} Enable database connection health checks |
{{ configsetting("INVENTREE_DB_OPTIONS") }} Additional database options (as a JSON object) | {{ configsetting("INVENTREE_DB_OPTIONS") }} Additional database options (as a JSON object) |
!!! tip "Database Password" !!! tip "Database Password"
@@ -266,11 +269,12 @@ The following database options can be configured:
If running with a PostgreSQL database backend, the following additional options are available: If running with a PostgreSQL database backend, the following additional options are available:
{{ configtable() }} {{ configtable() }}
{{ configsetting("INVENTREE_DB_TIMEOUT", default="2") }} Database connection timeout (s) | {{ configsetting("INVENTREE_DB_TIMEOUT", default="10") }} Database connection timeout (s) |
| `INVENTREE_DB_TCP_KEEPALIVES` | database.tcp_keepalives | 1 | TCP keepalive | | `INVENTREE_DB_TCP_KEEPALIVES` | database.tcp_keepalives | 1 | TCP keepalive |
| `INVENTREE_DB_TCP_KEEPALIVES_IDLE` | database.tcp_keepalives_idle | 1 | Idle TCP keepalive | | `INVENTREE_DB_TCP_KEEPALIVES_IDLE` | database.tcp_keepalives_idle | 5 | Idle TCP keepalive |
| `INVENTREE_DB_TCP_KEEPALIVES_INTERVAL` | database.tcp_keepalives_interval | 1| TCP keepalive interval | | `INVENTREE_DB_TCP_KEEPALIVES_INTERVAL` | database.tcp_keepalives_interval | 5 | TCP keepalive interval |
| `INVENTREE_DB_TCP_KEEPALIVES_COUNT` | database.tcp_keepalives_count | 5 | TCP keepalive count | | `INVENTREE_DB_TCP_KEEPALIVES_COUNT` | database.tcp_keepalives_count | 5 | TCP keepalive count |
| `INVENTREE_DB_TCP_USER_TIMEOUT` | database.tcp_user_timeout | 2000 | TCP user timeout (ms) |
| `INVENTREE_DB_ISOLATION_SERIALIZABLE` | database.serializable | False | Database isolation level configured to "serializable" | | `INVENTREE_DB_ISOLATION_SERIALIZABLE` | database.serializable | False | Database isolation level configured to "serializable" |
### MySQL Settings ### MySQL Settings
@@ -278,6 +282,7 @@ If running with a PostgreSQL database backend, the following additional options
If running with a MySQL database backend, the following additional options are available: If running with a MySQL database backend, the following additional options are available:
{{ configtable() }} {{ configtable() }}
{{ configsetting("INVENTREE_DB_TIMEOUT", default="10") }} Database connection timeout (s) |
| `INVENTREE_DB_ISOLATION_SERIALIZABLE` | database.serializable | False | Database isolation level configured to "serializable" | | `INVENTREE_DB_ISOLATION_SERIALIZABLE` | database.serializable | False | Database isolation level configured to "serializable" |
### SQLite Settings ### SQLite Settings
@@ -5,10 +5,23 @@ from pathlib import Path
import structlog import structlog
from InvenTree.config import get_boolean_setting, get_config_value, get_setting from InvenTree.config import get_boolean_setting, get_config_value, get_setting
from InvenTree.ready import isInWorkerThread
logger = structlog.get_logger('inventree') logger = structlog.get_logger('inventree')
def _get_conn_max_age() -> int | None:
"""Return the configured CONN_MAX_AGE value.
Accepts an integer number of seconds, or 'None' for unlimited persistence.
Defaults to 0 (close the connection after each request).
"""
value = get_setting('INVENTREE_DB_CONN_MAX_AGE', 'database.conn_max_age', 0)
if value is None or str(value).strip().lower() == 'none':
return None
return int(value)
def get_db_backend(): def get_db_backend():
"""Return the database backend configuration.""" """Return the database backend configuration."""
# For the core database configuration values, we test for UPPERCASE configuration values as a backup, # For the core database configuration values, we test for UPPERCASE configuration values as a backup,
@@ -43,6 +56,13 @@ def get_db_backend():
) )
or get_config_value('database.OPTIONS') or get_config_value('database.OPTIONS')
or {}, or {},
# Seconds to keep idle connections open across requests (0 = close after each request).
# Set to None for unlimited. Enable CONN_HEALTH_CHECKS alongside any non-zero value
# so stale connections are detected before use rather than causing request failures.
'CONN_MAX_AGE': _get_conn_max_age(),
'CONN_HEALTH_CHECKS': get_boolean_setting(
'INVENTREE_DB_CONN_HEALTH_CHECKS', 'database.conn_health_checks', False
),
} }
# Check for required keys # Check for required keys
@@ -113,9 +133,9 @@ def set_postgres_options(db_options: dict):
if 'connect_timeout' not in db_options: if 'connect_timeout' not in db_options:
# The DB server is in the same data center, it should not take very # The DB server is in the same data center, it should not take very
# long to connect to the database server # long to connect to the database server
# # seconds, 2 is minimum allowed by libpq # Note: 2 seconds is minimum allowed by libpq
db_options['connect_timeout'] = int( db_options['connect_timeout'] = max(
get_setting('INVENTREE_DB_TIMEOUT', 'database.timeout', 2) 2, int(get_setting('INVENTREE_DB_TIMEOUT', 'database.timeout', 10))
) )
# Setup TCP keepalive # Setup TCP keepalive
@@ -133,7 +153,7 @@ def set_postgres_options(db_options: dict):
if 'keepalives_idle' not in db_options: if 'keepalives_idle' not in db_options:
db_options['keepalives_idle'] = int( db_options['keepalives_idle'] = int(
get_setting( get_setting(
'INVENTREE_DB_TCP_KEEPALIVES_IDLE', 'database.tcp_keepalives_idle', 1 'INVENTREE_DB_TCP_KEEPALIVES_IDLE', 'database.tcp_keepalives_idle', 5
) )
) )
@@ -143,7 +163,7 @@ def set_postgres_options(db_options: dict):
get_setting( get_setting(
'INVENTREE_DB_TCP_KEEPALIVES_INTERVAL', 'INVENTREE_DB_TCP_KEEPALIVES_INTERVAL',
'database.tcp_keepalives_interval', 'database.tcp_keepalives_interval',
'1', '5',
) )
) )
@@ -157,10 +177,13 @@ def set_postgres_options(db_options: dict):
) )
) )
# # Milliseconds for how long pending data should remain unacked # # Milliseconds for how long pending data should remain unacked by the remote server
# by the remote server if 'tcp_user_timeout' not in db_options:
# TODO: Supported starting in PSQL 11 db_options['tcp_user_timeout'] = int(
# "tcp_user_timeout": int(os.getenv("PGTCP_USER_TIMEOUT", "1000"), get_setting(
'INVENTREE_DB_TCP_USER_TIMEOUT', 'database.tcp_user_timeout', '2000'
)
)
# Postgres's default isolation level is Read Committed which is # Postgres's default isolation level is Read Committed which is
# normally fine, but most developers think the database server is # normally fine, but most developers think the database server is
@@ -178,10 +201,21 @@ def set_postgres_options(db_options: dict):
else IsolationLevel.READ_COMMITTED else IsolationLevel.READ_COMMITTED
) )
# Specify the application name for the database connection
# This can be useful for debugging and monitoring purposes
if 'application_name' not in db_options:
db_options['application_name'] = (
'inventree-worker' if isInWorkerThread() else 'inventree-server'
)
def set_mysql_options(db_options: dict): def set_mysql_options(db_options: dict):
"""Set database options specific to mysql backend.""" """Set database options specific to mysql backend."""
# TODO TCP time outs and keepalives # Timeout values
if 'connect_timeout' not in db_options:
db_options['connect_timeout'] = int(
get_setting('INVENTREE_DB_TIMEOUT', 'database.timeout', 10)
)
# MariaDB's default isolation level is Repeatable Read which is # MariaDB's default isolation level is Repeatable Read which is
# normally fine, but most developers think the database server is # normally fine, but most developers think the database server is