feat: add audit events and runtime state snapshots to database
- Introduced new tables for audit events and runtime state snapshots in the database schema. - Created data classes for AuditRecord and RuntimeStateRecord to represent the new entities. - Implemented AuditRepository and RuntimeStateRepository for inserting and retrieving records. - Enhanced the dashboard to include an audit trail section, displaying recent audit events. - Added tests for the new audit repository and runtime lifecycle functionalities. - Updated settings validation to ensure proper configuration for alerting features. - Integrated alert notifications across various components, including execution sequencer and loss limits.
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import asyncio
|
||||
from dataclasses import dataclass
|
||||
from datetime import UTC, datetime
|
||||
from types import SimpleNamespace
|
||||
@@ -83,6 +84,31 @@ class _FakeFailingExecutor:
|
||||
raise RuntimeError("executor failure")
|
||||
|
||||
|
||||
class _FakeAlertNotifier:
|
||||
def __init__(self) -> None:
|
||||
self.events: list[dict[str, str]] = []
|
||||
|
||||
async def notify(
|
||||
self,
|
||||
*,
|
||||
category: str,
|
||||
severity: str,
|
||||
title: str,
|
||||
message: str,
|
||||
details: dict[str, str] | None = None,
|
||||
) -> bool:
|
||||
self.events.append(
|
||||
{
|
||||
"category": category,
|
||||
"severity": severity,
|
||||
"title": title,
|
||||
"message": message,
|
||||
**(details or {}),
|
||||
}
|
||||
)
|
||||
return True
|
||||
|
||||
|
||||
@dataclass(slots=True)
|
||||
class _FakeWsClientTwoMessages:
|
||||
delta: BookDelta
|
||||
@@ -430,3 +456,29 @@ async def test_market_data_feed_halts_on_repeated_execution_failures() -> None:
|
||||
assert stop_guard.halted_reason == "consecutive_failures_limit_breached"
|
||||
assert kill_switch.is_active
|
||||
assert kill_switch.reason == "consecutive_failures_limit_breached"
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_market_data_feed_emits_critical_alert_on_executor_exception() -> None:
|
||||
event = _sample_event(allocated_capital=75.0)
|
||||
detector = _FakeDetector(event)
|
||||
executor = _FakeFailingExecutor()
|
||||
notifier = _FakeAlertNotifier()
|
||||
feed = MarketDataFeed(
|
||||
ws_client=_FakeWsClient(_sample_delta()),
|
||||
snapshot_writer=_FakeSnapshotWriter(),
|
||||
detector=detector,
|
||||
opportunity_writer=_FakeOpportunityWriter(),
|
||||
paper_trading_mode=False,
|
||||
opportunity_executor=executor.execute,
|
||||
alert_notifier=notifier,
|
||||
)
|
||||
|
||||
await feed.run()
|
||||
await asyncio.sleep(0)
|
||||
|
||||
assert executor.calls == 1
|
||||
assert len(notifier.events) == 1
|
||||
assert notifier.events[0]["category"] == "system"
|
||||
assert notifier.events[0]["severity"] == "critical"
|
||||
assert notifier.events[0]["title"] == "Critical execution exception"
|
||||
|
||||
Reference in New Issue
Block a user