Guard geo_service.init_geoip against repeated initialization

This commit is contained in:
2026-04-18 19:54:05 +02:00
parent 99731a9919
commit 52e08e17a4
3 changed files with 40 additions and 1 deletions

View File

@@ -109,6 +109,11 @@ _dirty: set[str] = set()
#: Optional MaxMind GeoLite2 reader initialised by :func:`init_geoip`.
_geoip_reader: geoip2.database.Reader | None = None
#: Indicates whether :func:`init_geoip` has already been called.
#: This function is startup-only and must not be invoked again while the
#: process is handling requests.
_geoip_initialized: bool = False
#: Lock protecting mutations to the in-memory geo caches.
_cache_lock: asyncio.Lock = asyncio.Lock()
@@ -230,13 +235,19 @@ async def re_resolve_all(
def init_geoip(mmdb_path: str | None) -> None:
"""Initialise the MaxMind GeoLite2-Country database reader.
This function is startup-only and must be called before request handling
begins. A second initialization attempt is considered a programming error
and raises ``RuntimeError``.
If *mmdb_path* is ``None``, empty, or the file does not exist the
fallback is silently disabled — ip-api.com remains the sole resolver.
Args:
mmdb_path: Absolute path to a ``GeoLite2-Country.mmdb`` file.
"""
global _geoip_reader # noqa: PLW0603
global _geoip_reader, _geoip_initialized # noqa: PLW0603
if _geoip_initialized:
raise RuntimeError("GeoIP reader already initialised")
if not mmdb_path:
return
from pathlib import Path # noqa: PLC0415
@@ -247,6 +258,7 @@ def init_geoip(mmdb_path: str | None) -> None:
log.warning("geoip_mmdb_not_found", path=mmdb_path)
return
_geoip_reader = geoip2.database.Reader(mmdb_path)
_geoip_initialized = True
log.info("geoip_mmdb_loaded", path=mmdb_path)