这是一个批量整理提交,包含以下主要改动: 1. 删除多处冗余的空行和未使用的导入 2. 修复文件末尾缺少换行符的问题 3. 调整部分模块的导入顺序与代码排版 4. 修复部分配置默认值与策略逻辑 5. 新增多个功能模块与辅助工具 6. 完善异常处理与日志记录 7. 修复速率限制、消息缓存、权限校验等逻辑bug 8. 废弃部分旧有API与配置项并添加警告提示
95 lines
2.8 KiB
Python
95 lines
2.8 KiB
Python
from __future__ import annotations
|
|
|
|
import time
|
|
from enum import StrEnum
|
|
|
|
|
|
class SyncState(StrEnum):
|
|
PREPARED = "prepared"
|
|
SYNCING = "syncing"
|
|
ERROR = "error"
|
|
RECONNECTING = "reconnecting"
|
|
STOPPED = "stopped"
|
|
|
|
|
|
_SYNC_STATE_TRANSITIONS: dict[SyncState, set[SyncState]] = {
|
|
SyncState.PREPARED: {SyncState.SYNCING, SyncState.ERROR, SyncState.STOPPED},
|
|
SyncState.SYNCING: {SyncState.ERROR, SyncState.RECONNECTING, SyncState.STOPPED},
|
|
SyncState.ERROR: {SyncState.RECONNECTING, SyncState.STOPPED},
|
|
SyncState.RECONNECTING: {SyncState.SYNCING, SyncState.ERROR, SyncState.STOPPED},
|
|
SyncState.STOPPED: {SyncState.PREPARED},
|
|
}
|
|
|
|
|
|
class SyncStateMachine:
|
|
def __init__(self):
|
|
self._state = SyncState.PREPARED
|
|
self._last_error: str = ""
|
|
self._retry_count: int = 0
|
|
self._max_retries: int = 10
|
|
self._last_error_time: float = 0.0
|
|
self._auto_recovery_timeout: float = 60.0
|
|
|
|
@property
|
|
def state(self) -> SyncState:
|
|
return self._state
|
|
|
|
@property
|
|
def last_error(self) -> str:
|
|
return self._last_error
|
|
|
|
@property
|
|
def retry_count(self) -> int:
|
|
return self._retry_count
|
|
|
|
def can_transition(self, to_state: SyncState) -> bool:
|
|
allowed = _SYNC_STATE_TRANSITIONS.get(self._state, set())
|
|
return to_state in allowed
|
|
|
|
def transition(self, to_state: SyncState, error: str = "") -> bool:
|
|
if not self.can_transition(to_state):
|
|
return False
|
|
self._state = to_state
|
|
self._last_error = error
|
|
|
|
if to_state == SyncState.ERROR:
|
|
self._retry_count += 1
|
|
self._last_error_time = time.monotonic()
|
|
elif to_state == SyncState.SYNCING:
|
|
self._retry_count = 0
|
|
|
|
return True
|
|
|
|
def to_healthy(self) -> bool:
|
|
return self.transition(SyncState.SYNCING)
|
|
|
|
def to_error(self, error: str = "") -> bool:
|
|
return self.transition(SyncState.ERROR, error)
|
|
|
|
def to_reconnecting(self, error: str = "") -> bool:
|
|
return self.transition(SyncState.RECONNECTING, error)
|
|
|
|
def to_stopped(self) -> bool:
|
|
return self.transition(SyncState.STOPPED)
|
|
|
|
def to_prepared(self) -> bool:
|
|
return self.transition(SyncState.PREPARED)
|
|
|
|
@property
|
|
def is_healthy(self) -> bool:
|
|
return self._state in (SyncState.PREPARED, SyncState.SYNCING)
|
|
|
|
@property
|
|
def is_active(self) -> bool:
|
|
return self._state in (SyncState.PREPARED, SyncState.SYNCING, SyncState.RECONNECTING)
|
|
|
|
@property
|
|
def should_stop_retry(self) -> bool:
|
|
return self._retry_count >= self._max_retries
|
|
|
|
@property
|
|
def should_auto_recover(self) -> bool:
|
|
if self._state != SyncState.ERROR:
|
|
return False
|
|
return time.monotonic() - self._last_error_time > self._auto_recovery_timeout
|