Build 060.28: implement Persistent Checkpoint and Startup Recovery

This commit is contained in:
2026-08-01 20:55:32 +03:00
parent 58e5a12a4d
commit 8c485e32b1
63 changed files with 12430 additions and 92 deletions

View File

@@ -15,6 +15,8 @@ _TRADE_STREAM_VARIABLES = (
"TRADE_STREAM_HEARTBEAT_TIMEOUT_SECONDS",
"TRADE_STREAM_SCHEDULER_INTERVAL_SECONDS",
"TRADE_STREAM_RECOVERY_WINDOW_MS",
"TRADE_STREAM_SUBSCRIPTION_ACK_TIMEOUT_SECONDS",
"TRADE_STREAM_STARTUP_MARKET_BUFFER_CAPACITY",
)
_MARKET_DATA_STORAGE_VARIABLES = (
@@ -69,6 +71,8 @@ def test_trade_stream_is_disabled_by_default(
assert settings.trade_stream.enabled is False
assert settings.trade_stream.websocket_url == ""
assert settings.trade_stream.symbols == ()
assert settings.trade_stream.subscription_ack_timeout_seconds == 10.0
assert settings.trade_stream.startup_market_buffer_capacity == 10_000
def test_disabled_trade_stream_ignores_dependent_values(
@@ -76,6 +80,14 @@ def test_disabled_trade_stream_ignores_dependent_values(
) -> None:
prepare_environment(monkeypatch)
monkeypatch.setenv("TRADE_STREAM_OPEN_TIMEOUT_SECONDS", "invalid")
monkeypatch.setenv(
"TRADE_STREAM_SUBSCRIPTION_ACK_TIMEOUT_SECONDS",
"invalid",
)
monkeypatch.setenv(
"TRADE_STREAM_STARTUP_MARKET_BUFFER_CAPACITY",
"invalid",
)
monkeypatch.setenv("TRADE_STREAM_SYMBOLS", ",")
settings = load_settings()
@@ -144,7 +156,7 @@ def test_enabled_trade_stream_parses_independent_settings(
enable_trade_stream(monkeypatch)
monkeypatch.setenv(
"TRADE_STREAM_SYMBOLS",
" ETH/USD_LEVERAGE, BTC/USD_LEVERAGE,ETH/USD_LEVERAGE ",
" eth/usd_leverage, BTC/USD_LEVERAGE,ETH/USD_LEVERAGE ",
)
monkeypatch.setenv("TRADE_STREAM_OPEN_TIMEOUT_SECONDS", "11.5")
monkeypatch.setenv("TRADE_STREAM_PROBE_TIMEOUT_SECONDS", "21")
@@ -152,6 +164,14 @@ def test_enabled_trade_stream_parses_independent_settings(
monkeypatch.setenv("TRADE_STREAM_HEARTBEAT_TIMEOUT_SECONDS", "31")
monkeypatch.setenv("TRADE_STREAM_SCHEDULER_INTERVAL_SECONDS", "6")
monkeypatch.setenv("TRADE_STREAM_RECOVERY_WINDOW_MS", "123456")
monkeypatch.setenv(
"TRADE_STREAM_SUBSCRIPTION_ACK_TIMEOUT_SECONDS",
"12.5",
)
monkeypatch.setenv(
"TRADE_STREAM_STARTUP_MARKET_BUFFER_CAPACITY",
"1234",
)
settings = load_settings()
trade_stream = settings.trade_stream
@@ -168,6 +188,20 @@ def test_enabled_trade_stream_parses_independent_settings(
assert trade_stream.heartbeat_timeout_seconds == 31.0
assert trade_stream.scheduler_interval_seconds == 6.0
assert trade_stream.recovery_window_ms == 123_456
assert trade_stream.subscription_ack_timeout_seconds == 12.5
assert trade_stream.startup_market_buffer_capacity == 1_234
def test_enabled_trade_stream_uses_startup_boundary_defaults(
monkeypatch: pytest.MonkeyPatch,
) -> None:
prepare_environment(monkeypatch)
enable_trade_stream(monkeypatch)
trade_stream = load_settings().trade_stream
assert trade_stream.subscription_ack_timeout_seconds == 10.0
assert trade_stream.startup_market_buffer_capacity == 10_000
@pytest.mark.parametrize(
@@ -180,6 +214,12 @@ def test_enabled_trade_stream_parses_independent_settings(
("TRADE_STREAM_SCHEDULER_INTERVAL_SECONDS", "invalid"),
("TRADE_STREAM_RECOVERY_WINDOW_MS", "1.5"),
("TRADE_STREAM_RECOVERY_WINDOW_MS", "0"),
("TRADE_STREAM_SUBSCRIPTION_ACK_TIMEOUT_SECONDS", "0"),
("TRADE_STREAM_SUBSCRIPTION_ACK_TIMEOUT_SECONDS", "nan"),
("TRADE_STREAM_SUBSCRIPTION_ACK_TIMEOUT_SECONDS", "invalid"),
("TRADE_STREAM_STARTUP_MARKET_BUFFER_CAPACITY", "0"),
("TRADE_STREAM_STARTUP_MARKET_BUFFER_CAPACITY", "-1"),
("TRADE_STREAM_STARTUP_MARKET_BUFFER_CAPACITY", "1.5"),
),
)
def test_enabled_trade_stream_rejects_invalid_numeric_settings(