fix(notification): keep config save independent from cache sync

This commit is contained in:
InfinityPacer
2026-08-31 07:33:40 +08:00
parent a66cdb04e0
commit 655a4fb204
2 changed files with 74 additions and 9 deletions

View File

@@ -6,6 +6,7 @@ from app.api.dependencies.auth import get_current_active_superuser
from app.api.response import ResponseAPIRouter
from app.application.configuration import get_configured_system_config
from app.chain.notification import NotificationChain
from app.modules.wechatclawbot.wechatclawbot import WechatClawBot
from app.schemas.common import ManageRequest as _SchemaManageRequest
from app.schemas.response import Response as _SchemaResponse
from app.schemas.system import NotificationConf
@@ -54,17 +55,24 @@ async def save_config(
legacy["id"] = f"legacy-{legacy.get('type') or 'notification'}-{legacy.get('name') or 'unnamed'}"
previous_models.append(NotificationConf(**legacy))
previous_data = _normalize_configs(previous_models)
result = NotificationChain().manage_channel(
channel="WechatClawBot",
action="reconcile_config",
previous=previous_data,
current=current,
)
if not result.get("success"):
return _SchemaResponse(success=False, message=result.get("message"))
saved = await get_configured_system_config().async_set(SystemConfigKey.Notifications, current)
if saved is False:
return _SchemaResponse(success=False, message="通知配置保存失败")
try:
# 配置写入成功后再同步 ClawBot 缓存,避免持久化失败留下半完成的登录状态。
result = WechatClawBot.reconcile_cached_states(previous_data, current)
except Exception as error:
return _SchemaResponse(
success=False,
message=f"通知配置已保存,但缓存同步失败,请重试:{error}",
data={"value": current},
)
if not result.get("success"):
return _SchemaResponse(
success=False,
message=f"通知配置已保存,但缓存同步失败,请重试:{result.get('message')}",
data={"value": current},
)
return _SchemaResponse(success=True, message="通知配置保存成功", data={"value": current})
except ValueError as error:
return _SchemaResponse(success=False, message=str(error))

View File

@@ -2,7 +2,7 @@
import pytest
from app.api.endpoints.notification import _normalize_configs
from app.api.endpoints.notification import _normalize_configs, save_config
from app.modules.wechatclawbot.wechatclawbot import WechatClawBot
from app.schemas.system import NotificationConf
@@ -61,3 +61,60 @@ def test_reconcile_cached_states_migrates_renamed_identity_and_cleans_removed(mo
@pytest.mark.parametrize("identity", ["stable-id", "display-name"])
def test_cache_key_is_stable_for_same_identity(identity):
assert WechatClawBot._build_cache_key(identity) == WechatClawBot._build_cache_key(identity)
@pytest.mark.asyncio
async def test_save_config_does_not_touch_cache_when_persistence_fails(monkeypatch):
calls = {"reconcile": 0}
class FakeConfig:
def get(self, _key):
return []
async def async_set(self, _key, _value):
return False
monkeypatch.setattr(
"app.api.endpoints.notification.get_configured_system_config",
lambda: FakeConfig(),
)
def fail_if_reconciled(_previous, _current):
calls["reconcile"] += 1
return {"success": True}
monkeypatch.setattr(WechatClawBot, "reconcile_cached_states", fail_if_reconciled)
response = await save_config([NotificationConf(name="Alpha", type="telegram")], None)
assert response.success is False
assert response.message == "通知配置保存失败"
assert calls["reconcile"] == 0
@pytest.mark.asyncio
async def test_save_config_saves_channels_without_loaded_clawbot_module(monkeypatch):
calls = []
class FakeConfig:
def get(self, _key):
return []
async def async_set(self, _key, value):
calls.append(value)
return True
monkeypatch.setattr(
"app.api.endpoints.notification.get_configured_system_config",
lambda: FakeConfig(),
)
monkeypatch.setattr(
WechatClawBot,
"reconcile_cached_states",
lambda _previous, _current: {"success": True},
)
response = await save_config([NotificationConf(name="TG", type="telegram")], None)
assert response.success is True
assert response.data["value"][0]["name"] == "TG"
assert len(calls) == 1