Files
wehub-resource-sync 1443d3fdf9
Ruff Format Check / Ruff Format & Lint (push) Failing after 7m39s
Deploy VitePress site to Pages / build (push) Failing after 9m11s
Deploy VitePress site to Pages / Deploy (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 12:32:26 +08:00

100 lines
2.9 KiB
Python

"""运行时配置 Redis 快照同步。"""
from __future__ import annotations
import json
import threading
import time
from collections.abc import Iterator
from typing import Any
from yuxi.storage.redis import RedisConfig, sync_redis_client
from yuxi.utils.logging_config import logger
RUNTIME_CONFIG_REDIS_KEY = "yuxi:runtime_config"
RUNTIME_CONFIG_SYNC_INTERVAL_SECONDS = 5.0
_RUNTIME_CONFIG_REDIS_TIMEOUT_SECONDS = 0.2
def _runtime_config_redis_config() -> RedisConfig:
return RedisConfig.from_env(
decode_responses=True,
socket_timeout=_RUNTIME_CONFIG_REDIS_TIMEOUT_SECONDS,
socket_connect_timeout=_RUNTIME_CONFIG_REDIS_TIMEOUT_SECONDS,
)
def _runtime_fields(config: Any) -> Iterator[str]:
for field_name, field_info in type(config).model_fields.items():
if field_info.exclude:
continue
yield field_name
def _runtime_snapshot(config: Any) -> dict[str, Any]:
return {field_name: getattr(config, field_name) for field_name in _runtime_fields(config)}
def _load_snapshot() -> dict[str, Any] | None:
try:
with sync_redis_client(_runtime_config_redis_config()) as redis_client:
raw = redis_client.get(RUNTIME_CONFIG_REDIS_KEY)
except Exception as e:
logger.warning(f"Failed to load runtime config from Redis: {e}")
return None
if not raw:
return None
try:
snapshot = json.loads(raw)
except json.JSONDecodeError as e:
logger.warning(f"Failed to decode runtime config snapshot: {e}")
return None
return snapshot if isinstance(snapshot, dict) else None
def save_runtime_config(config: Any) -> None:
try:
with sync_redis_client(_runtime_config_redis_config()) as redis_client:
redis_client.set(
RUNTIME_CONFIG_REDIS_KEY,
json.dumps(_runtime_snapshot(config), ensure_ascii=False),
)
except Exception as e:
logger.warning(f"Failed to save runtime config to Redis: {e}")
def refresh_runtime_config(config: Any) -> None:
snapshot = _load_snapshot()
if snapshot is None:
return
for field_name in _runtime_fields(config):
if field_name in snapshot:
setattr(config, field_name, snapshot[field_name])
def start_runtime_sync(
config: Any,
current_thread: threading.Thread | None,
*,
interval: float = RUNTIME_CONFIG_SYNC_INTERVAL_SECONDS,
) -> threading.Thread:
if current_thread is not None:
return current_thread
def runtime_sync_loop() -> None:
while True:
time.sleep(interval)
try:
refresh_runtime_config(config)
except Exception as e:
logger.warning(f"Runtime config sync iteration failed: {e}")
thread = threading.Thread(target=runtime_sync_loop, name="config-runtime-sync", daemon=True)
thread.start()
logger.info(f"Runtime config sync thread started (interval={interval}s)")
return thread