fix(config): emit background-ops advisory logs once per process

`_get_background_operations_enabled()` was emitting three advisory log
lines (1 INFO + 2 deprecation WARNINGs) on every call. Because
`get_settings()` is intentionally non-cached and runs on every MCP tool
invocation via `get_client()`, the "Automatically enabled background
operations for semantic search in multi-user mode" INFO line was
firing per-request — 569 entries/hour in one production tenant.

Gate the three log emissions behind a module-level
`_bg_ops_advisories_logged` flag, mirroring the existing
`_warn_missing_secret_once` precedent in
`vector/webhook_receiver.py`. The boolean-derivation path stays
unchanged, so the `Settings` value remains fresh per call.

Extends the autouse `_reload_dynaconf_after_test` fixture to reset the
new flag between tests, and adds two regression tests that call
`get_settings()` five times and assert each advisory fires exactly once.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Chris Coutinho
2026-05-16 13:07:50 +02:00
co-authored by Claude Opus 4.7
parent b6bb3218bc
commit 79ea4e9e21
3 changed files with 118 additions and 22 deletions
+36 -20
View File
@@ -819,23 +819,25 @@ def _is_multi_user_mode() -> bool:
return True
def _get_background_operations_enabled() -> bool:
"""Get background operations enabled status with auto-enablement for semantic search.
# Per-process guard for the three advisory log messages emitted by
# `_get_background_operations_enabled()`. The function runs on every
# `get_settings()` call (per ADR-024 / dynaconf design `get_settings()` is
# intentionally non-cached), so unguarded `logger.info`/`logger.warning`
# calls spam every MCP tool invocation. Mirrors the precedent at
# `nextcloud_mcp_server/vector/webhook_receiver.py:_warn_missing_secret_once`.
_bg_ops_advisories_logged: bool = False
Supports:
- ENABLE_BACKGROUND_OPERATIONS (new, preferred)
- ENABLE_OFFLINE_ACCESS (old, deprecated)
- Auto-enabled if ENABLE_SEMANTIC_SEARCH=true in multi-user modes
Returns:
True if background operations should be enabled
"""
def _log_bg_ops_advisories_once(
explicit: bool, legacy: bool, auto_enabled: bool
) -> None:
"""Emit ENABLE_BACKGROUND_OPERATIONS advisory logs at most once per process."""
global _bg_ops_advisories_logged
if _bg_ops_advisories_logged:
return
_bg_ops_advisories_logged = True
logger = logging.getLogger(__name__)
# Check new and old variable names
explicit = _dynaconf.get("ENABLE_BACKGROUND_OPERATIONS", False)
legacy = _dynaconf.get("ENABLE_OFFLINE_ACCESS", False)
if explicit and legacy:
logger.warning(
"Both ENABLE_BACKGROUND_OPERATIONS and ENABLE_OFFLINE_ACCESS are set. "
@@ -848,18 +850,32 @@ def _get_background_operations_enabled() -> bool:
"Please use ENABLE_BACKGROUND_OPERATIONS instead. "
"Support for ENABLE_OFFLINE_ACCESS will be removed in v1.0.0."
)
# Auto-enable if semantic search is enabled in multi-user mode
semantic_search_enabled = _get_semantic_search_enabled()
is_multi_user = _is_multi_user_mode()
auto_enabled = semantic_search_enabled and is_multi_user
if auto_enabled and not (explicit or legacy):
logger.info(
"Automatically enabled background operations for semantic search in multi-user mode. "
"Set ENABLE_BACKGROUND_OPERATIONS=false to disable (this will also disable semantic search)."
)
def _get_background_operations_enabled() -> bool:
"""Get background operations enabled status with auto-enablement for semantic search.
Supports:
- ENABLE_BACKGROUND_OPERATIONS (new, preferred)
- ENABLE_OFFLINE_ACCESS (old, deprecated)
- Auto-enabled if ENABLE_SEMANTIC_SEARCH=true in multi-user modes
Returns:
True if background operations should be enabled
"""
explicit = _dynaconf.get("ENABLE_BACKGROUND_OPERATIONS", False)
legacy = _dynaconf.get("ENABLE_OFFLINE_ACCESS", False)
semantic_search_enabled = _get_semantic_search_enabled()
is_multi_user = _is_multi_user_mode()
auto_enabled = semantic_search_enabled and is_multi_user
_log_bg_ops_advisories_once(explicit, legacy, auto_enabled)
return explicit or legacy or auto_enabled