From 3394456e4451dbcca5c5c9317857f1c7e0c4070b Mon Sep 17 00:00:00 2001 From: Florian Date: Tue, 7 Apr 2026 00:38:25 +0200 Subject: [PATCH] [Operating] allow to identify DB connection "owner" When having several different services running as part of a CRCon setup, and trying to identify what component/service is using a particular amount/number of DB connections is hard, apart from telling the total number of open connections. This commit aims to solve this issue by providing a proper identification for a DB connection. It is composed out of the name of the component that initiated the connection (e.g. gunicorn for the API backend, auto_settings for the autosettings component, etc) together with the server number. The name is inferred from the application start commands to keep the API for using the DB layer in the CRCon stable and to not bother callers to provide any identification. If a component name cannot be inferred, a generic "CRCon Generic" name is used. The connection name will show up as the "application_name" in the pg_stat_activity table of postgres, which can be quried with: select * from pg_stat_activity; --- rcon/models.py | 29 +++++++++++++++++++++++++++-- rconweb/rconweb/settings.py | 3 +++ 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/rcon/models.py b/rcon/models.py index 165529fde..43bf5e264 100644 --- a/rcon/models.py +++ b/rcon/models.py @@ -1,10 +1,11 @@ import logging import os import re +import sys from collections import defaultdict from contextlib import contextmanager from datetime import datetime, timezone -from typing import Any, Generator, List, Literal, Optional, Sequence, overload, TypedDict +from typing import Any, Generator, List, Literal, Optional, Sequence, overload import pydantic from sqlalchemy import TIMESTAMP, Enum, ForeignKey, String, create_engine, select, text, JSON @@ -73,6 +74,30 @@ _ENGINE = None +def _connection_name() -> str: + """ + Identify what application component is using the SQLAlchemy session. This can be helpful when inspecting the connections + in Postgres to identify the purpose of a connection. The connection name will be used as the application_name connection + property and show up in the pg_stat_activity table: + select * from pg_stat_activity; + + :return: str + """ + args = sys.argv + name = 'CRCon Generic' + if "manage.py" not in args[0]: + # stuff like daphne, gunicorn (backend) etc + name = args[0] + elif len(args) > 1 and args[1] != "": + # Take whatever argument we passed to manage.py (for Supervisor services, such as log_loop, etc) + name = args[1] + + name = (os.getenv("SERVER_NUMBER") or "") + name + # in the standard build (which we use in teh default docker setup) the name cannot exceed 63 chars (less than 64), + # see https://www.postgresql.org/docs/current/runtime-config-logging.html#GUC-APPLICATION-NAME + return name[:63] + + def get_engine(): global _ENGINE @@ -84,7 +109,7 @@ def get_engine(): logger.error(msg) raise ValueError(msg) - _ENGINE = create_engine(url, echo=False) + _ENGINE = create_engine(url, echo=False, connect_args={"application_name":_connection_name()}) return _ENGINE diff --git a/rconweb/rconweb/settings.py b/rconweb/rconweb/settings.py index e90afb597..71383c816 100644 --- a/rconweb/rconweb/settings.py +++ b/rconweb/rconweb/settings.py @@ -253,6 +253,9 @@ "HOST": db_info["HOST"], "PORT": db_info["PORT"], "NAME": db_info["NAME"], + "OPTIONS": { + "application_name": (os.getenv("SERVER_NUMBER") or "") + "Django", + } } }