risk: define and implement kill-switch refresh retry policy (#377) #389

Merged
jihoson merged 2 commits from feature/issue-377-kill-switch-refresh-retry into feature/v3-session-policy-stream 2026-03-02 09:47:56 +09:00
3 changed files with 33 additions and 3 deletions
Showing only changes of commit b34937ea9d - Show all commits

View File

@@ -73,7 +73,7 @@ class KillSwitchOrchestrator:
if result is False: if result is False:
raise RuntimeError("step returned False") raise RuntimeError("step returned False")
return return
except Exception as exc: # pragma: no cover - intentionally resilient except Exception as exc:
last_exc = exc last_exc = exc
if attempt >= attempts: if attempt >= attempts:
break break

View File

@@ -1375,7 +1375,10 @@ async def _cancel_pending_orders_for_kill_switch(
) )
if failures: if failures:
raise RuntimeError("; ".join(failures[:3])) summary = "; ".join(failures[:3])
if len(failures) > 3:
summary = f"{summary} (+{len(failures) - 3} more)"
raise RuntimeError(summary)
async def _refresh_order_state_for_kill_switch( async def _refresh_order_state_for_kill_switch(
@@ -1402,7 +1405,10 @@ async def _refresh_order_state_for_kill_switch(
) )
failures.append(f"{market.code}/{market.exchange_code}: {exc}") failures.append(f"{market.code}/{market.exchange_code}: {exc}")
if failures: if failures:
raise RuntimeError("; ".join(failures[:3])) summary = "; ".join(failures[:3])
if len(failures) > 3:
summary = f"{summary} (+{len(failures) - 3} more)"
raise RuntimeError(summary)
def _reduce_risk_for_kill_switch() -> None: def _reduce_risk_for_kill_switch() -> None:

View File

@@ -7154,3 +7154,27 @@ async def test_trigger_emergency_kill_switch_records_cancel_failure() -> None:
) )
assert any(err.startswith("cancel_pending_orders:") for err in report.errors) assert any(err.startswith("cancel_pending_orders:") for err in report.errors)
@pytest.mark.asyncio
async def test_refresh_order_state_failure_summary_includes_more_count() -> None:
broker = MagicMock()
broker.get_balance = AsyncMock(side_effect=RuntimeError("domestic down"))
overseas_broker = MagicMock()
overseas_broker.get_overseas_balance = AsyncMock(side_effect=RuntimeError("overseas down"))
markets = []
for code, exchange in [("KR", "KRX"), ("US_PRE", "NASD"), ("US_DAY", "NYSE"), ("JP", "TKSE")]:
market = MagicMock()
market.code = code
market.exchange_code = exchange
market.is_domestic = code == "KR"
markets.append(market)
with pytest.raises(RuntimeError, match=r"\(\+1 more\)$") as exc_info:
await main_module._refresh_order_state_for_kill_switch(
broker=broker,
overseas_broker=overseas_broker,
markets=markets,
)
assert "KR/KRX" in str(exc_info.value)