fix(atest): 去除 manage.py 硬编码密钥口令 + SIO 初次连接失败兜底重连

- manage.py 强制环境变量注入,删除默认 SECRET_KEY/MSYNC_SERVICE_SECRET/DB_PASSWORD
- sio_client 初次连接失败启动兜底重连线程,消除永久退化态
- 补充 RetryStep 手动重试与状态守卫回归用例(17/17 通过)
This commit is contained in:
TermiNexus committed 2026-08-10 23:29:34 +08:00
1 parent 409664d546
commit ddaadd8e57
3 files changed
+90 -6

No files matched your search

+10 -3
View File
@@ -7,9 +7,16 @@ def main():
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
os.environ['DJANGO_SETTINGS_MODULE'] = 'ATestCServer.settings'
os.environ['DB_NAME'] = 'atestc'
os.environ.setdefault('DJANGO_SECRET_KEY', 'gvsds-django-prod-k8x2m9v4n7p1q6w3j5r0t8y1u4i7o0a2s6d9f3g5h7j2k4l6z8x1c3v5b')
os.environ.setdefault('MSYNC_SERVICE_SECRET', 'atestc-msync-secret')
os.environ.setdefault('DB_PASSWORD', '1Qq@1Qq@190*')
# 安全:禁止硬编码默认密钥/口令,缺失时显式报错(settings.py 亦有
# ImproperlyConfigured 兜底)。MSYNC_SERVICE_SECRET 与 DB_PASSWORD
# 由部署环境(环境变量)提供。
required_envs = ['DJANGO_SECRET_KEY', 'MSYNC_SERVICE_SECRET', 'DB_PASSWORD']
missing = [name for name in required_envs if not os.environ.get(name)]
if missing:
raise SystemExit(
'缺少必需的环境变量: ' + ', '.join(missing)
+ '(禁止使用默认值,请通过环境变量注入)'
)
try:
from django.core.management import execute_from_command_line
except ImportError as exc:
+32 -2
View File
@@ -103,10 +103,40 @@ class MSyncSocketClient:
logger.info(f'[SIO] → connect url={url} ns=/msync')
self._sio.connect(url, namespaces=['/msync'], wait=True, wait_timeout=15)
except Exception as e:
logger.warning(f'Socket.IO 连接失败: {e},将自动重连')
self._StartHeartbeat()
logger.warning(f'Socket.IO 连接失败: {e},启动兜底重连线程')
self._StartBootstrap()
return
self._OnReady()
def _StartBootstrap(self):
"""初次连接失败的兜底:循环重连,成功后走完整注册/认证流程
python-socketio 的 reconnection 仅在"已连接后断开"时生效,
初次 connect 失败不会自动重连,需自行兜底。
"""
def bootstrap():
while self._running and not self._sio.connected:
try:
logger.info(f'[SIO] 兜底重连尝试: {self.MasterURL}')
self._sio.connect(
self.MasterURL,
namespaces=['/msync'],
wait=True,
wait_timeout=10,
)
break
except Exception as e:
logger.warning(f'[SIO] 兜底重连失败: {e}')
time.sleep(3)
if self._sio.connected:
self._OnReady()
threading.Thread(target=bootstrap, daemon=True, name='msync-bootstrap').start()
def _OnReady(self):
"""连接建立后的统一就绪流程:注册/认证/心跳/ORM 中转"""
logger.info(f'[SIO] Socket 已连接, 开始注册/认证...')
for attempt in range(1, 4):
reg_ok = self._DoRegister()
+48 -1
View File
@@ -53,7 +53,7 @@ def _Run():
from unittest import mock
import uuid
from gvsdsdk.msync.transaction import TransactionManager, StepExecutionError
from gvsdsdk.msync.transaction import TransactionManager, StepExecutionError, TransactionError
from gvsdsdk.msync.local_tx import local_tx
from gvsdsdk.msync.models import ServiceNode
@@ -164,6 +164,53 @@ def _Run():
r3 = local_tx.ExecuteStep('no_such', {}, 'K:1:1')
check('不同键不命中', r1 is not r3)
# ─── 6. RetryStep 手动重试(自动重试耗尽后仍可重试,计数分离)───
print('[6] RetryStep 手动重试')
dtx = TransactionManager.Create(
name='t6',
steps_data=[
{'name': 's1', 'ParticipantService': 'svc'},
{'name': 's2', 'ParticipantService': 'svc', 'MaxRetries': 0},
],
)
with mock.patch.object(TransactionManager, '_call_service', side_effect=[
{'ok': 1},
StepExecutionError('s2 永久失败'), # s2 自动重试耗尽
StepExecutionError('补偿 s1 也失败'), # 补偿失败 → 事务 FAILED
]):
TransactionManager.Execute(dtx.TransactionCode)
dtx.refresh_from_db()
check('自动重试耗尽后事务 Failed', dtx.TransactionStatus == 5)
# s2 MaxRetries=0 已耗尽,原逻辑(CanRetry)拒绝;现手动重试不受配额限制
with mock.patch.object(TransactionManager, '_call_service', return_value={'ok': True}):
step = TransactionManager.RetryStep(dtx.TransactionCode, 1)
check('手动重试成功 Completed', step.StepStatus == 2)
check('手动重试计数独立', step.RetryCount == 1)
# ─── 7. RetryStep 拒绝已补偿事务(事务状态守卫)───
print('[7] RetryStep 已补偿事务拒绝')
dtx = TransactionManager.Create(
name='t7',
steps_data=[
{'name': 's1', 'ParticipantService': 'svc'},
{'name': 's2', 'ParticipantService': 'svc', 'MaxRetries': 0},
],
)
with mock.patch.object(TransactionManager, '_call_service', side_effect=[
{'ok': 1},
StepExecutionError('s2 失败'),
{'ok': True}, # s1 补偿成功 → 事务 COMPENSATED
]):
TransactionManager.Execute(dtx.TransactionCode)
dtx.refresh_from_db()
check('事务已补偿', dtx.TransactionStatus == 4)
rejected = False
try:
TransactionManager.RetryStep(dtx.TransactionCode, 1) # s2 正向失败步骤
except TransactionError:
rejected = True
check('已补偿事务 RetryStep 被拒绝', rejected)
# ─── 汇总 ───
passed = sum(1 for _, ok in results if ok)
print(f'\n结果: {passed}/{len(results)} 通过')