Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [13.0.0-rc.13] - 2026-07-02

### Changed

- The default streaming read timeout is now 10s (was 3s), matching the terminal's streaming socket read timeout so a client rides through the brief silence right after a full-market subscribe instead of tripping the deadline and forcing an unnecessary reconnect. Still configurable via `streaming.timeout_ms`.

### Fixed

- **Windows server archive attaches to the release.** The Windows `thetadatadx-server` archive was built, but the upload step received a path the artifact action could not resolve on Windows, so the GitHub Release carried no Windows binary. The archive is now referenced by its native workspace path and attaches correctly.
Expand Down
4 changes: 4 additions & 0 deletions docs-site/docs/changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [13.0.0-rc.13] - 2026-07-02

### Changed

- The default streaming read timeout is now 10s (was 3s), matching the terminal's streaming socket read timeout so a client rides through the brief silence right after a full-market subscribe instead of tripping the deadline and forcing an unnecessary reconnect. Still configurable via `streaming.timeout_ms`.

### Fixed

- **Windows server archive attaches to the release.** The Windows `thetadatadx-server` archive was built, but the upload step received a path the artifact action could not resolve on Windows, so the GitHub Release carried no Windows binary. The archive is now referenced by its native workspace path and attaches correctly.
Expand Down
4 changes: 2 additions & 2 deletions thetadatadx-cpp/include/config_accessors.hpp.inc

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions thetadatadx-cpp/include/thetadatadx.h
Original file line number Diff line number Diff line change
Expand Up @@ -1452,15 +1452,15 @@ int32_t thetadatadx_config_set_reconnect_callback(ThetaDataDxConfig* config, The

/**
* Set the streaming read timeout (ms): the no-frames deadline after which
* the streaming session is declared dead and reconnects. Default 3_000;
* the streaming session is declared dead and reconnects. Default 10_000;
* validated to [100, 60_000] at connect.
* @param config Config handle to mutate; no-op when NULL.
* @param v Read timeout in milliseconds.
*/
void thetadatadx_config_set_streaming_timeout_ms(ThetaDataDxConfig* config, uint64_t v);

/**
* Read the current streaming timeout_ms setting (default 3_000).
* Read the current streaming timeout_ms setting (default 10_000).
* @param config Config handle to read.
* @param out Receives the timeout in milliseconds on success.
* @return 0 on success, -1 if either pointer is null.
Expand Down
2 changes: 1 addition & 1 deletion thetadatadx-ffi/src/auth.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2189,7 +2189,7 @@ mod resilience_knob_tests {
super::thetadatadx_config_get_streaming_timeout_ms(cfg, &mut got),
0
);
assert_eq!(got, 3_000);
assert_eq!(got, 10_000);
super::thetadatadx_config_set_streaming_timeout_ms(cfg, 9_000);
assert_eq!(
super::thetadatadx_config_get_streaming_timeout_ms(cfg, &mut got),
Expand Down
4 changes: 2 additions & 2 deletions thetadatadx-ffi/src/config_accessors.rs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion thetadatadx-py/python/thetadatadx/__init__.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -264,7 +264,7 @@ class Config:
metrics_port: Optional[int]
"""Prometheus exporter port. ``None`` (the default) leaves the exporter disabled even when the metrics feature is compiled in; an ``int`` binds an HTTP listener on ``0.0.0.0:<port>``. The setter raises ``ValueError`` for values outside ``0..=65535``."""
streaming_timeout_ms: int
"""No-frames deadline, in milliseconds, for the streaming connection (default 3_000)."""
"""No-frames deadline, in milliseconds, for the streaming connection (default 10_000)."""
streaming_connect_timeout_ms: int
"""Connect timeout, in milliseconds, for opening a streaming connection."""
streaming_ping_interval_ms: int
Expand Down
4 changes: 2 additions & 2 deletions thetadatadx-py/src/_generated/config_accessors.rs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 3 additions & 3 deletions thetadatadx-py/tests/test_config_resilience.py
Original file line number Diff line number Diff line change
Expand Up @@ -97,23 +97,23 @@ def test_reconnect_callback_registration_switches_policy():
def test_streaming_transport_defaults_and_round_trip():
mod = _import_module()
cfg = mod.Config.production()
assert cfg.streaming_timeout_ms == 3_000
assert cfg.streaming_timeout_ms == 10_000
assert cfg.streaming_connect_timeout_ms == 2_000
assert cfg.streaming_ping_interval_ms == 250
assert cfg.streaming_ring_size == 131_072
assert cfg.streaming_io_read_slice_ms == 25
assert cfg.streaming_keepalive_idle_secs == 5
assert cfg.streaming_keepalive_interval_secs == 2
assert cfg.streaming_keepalive_retries == 2
cfg.streaming_timeout_ms = 10_000
cfg.streaming_timeout_ms = 15_000
cfg.streaming_connect_timeout_ms = 5_000
cfg.streaming_ping_interval_ms = 1_000
cfg.streaming_ring_size = 8_192
cfg.streaming_io_read_slice_ms = 50
cfg.streaming_keepalive_idle_secs = 10
cfg.streaming_keepalive_interval_secs = 5
cfg.streaming_keepalive_retries = 4
assert cfg.streaming_timeout_ms == 10_000
assert cfg.streaming_timeout_ms == 15_000
assert cfg.streaming_connect_timeout_ms == 5_000
assert cfg.streaming_ping_interval_ms == 1_000
assert cfg.streaming_ring_size == 8_192
Expand Down
13 changes: 8 additions & 5 deletions thetadatadx-rs/config.default.toml
Original file line number Diff line number Diff line change
Expand Up @@ -36,13 +36,16 @@ hosts = [
connect_timeout = 2000

# Read timeout — how long to wait for data before the link is considered
# dead (ms). The server heartbeats every ~100 ms on a quiet session, so this
# default is ~30 missed heartbeats: a dead link is declared quickly.
read_timeout = 3000
# dead (ms). Matches the terminal's streaming socket read timeout and rides
# through the brief silence right after a full-market subscribe while the
# server sets the subscription up. The ~100 ms cadence is the client's ping
# to the server, not an inbound heartbeat; inbound frames arrive ~250 ms.
read_timeout = 10000
Comment on lines +39 to +43

# Client heartbeat interval (ms). The server's own ~100 ms heartbeat is the
# primary liveness signal; this client ping proves write-side health at a
# Client outbound ping interval (ms). This ping proves write-side health at a
# 4 Hz cadence without adding inbound-frame pressure on a recovering upstream.
# Reverse-direction liveness is the inbound frame and ping stream (~250 ms),
# which read_timeout guards.
ping_interval = 250

# Initial reconnect wait after an involuntary disconnect (ms). The auto-
Expand Down
16 changes: 8 additions & 8 deletions thetadatadx-rs/config_surface.toml
Original file line number Diff line number Diff line change
Expand Up @@ -324,20 +324,20 @@ param = "v"
abi_type = "u64"
path = "streaming.timeout_ms"
doc = """
Set the streaming read timeout (ms): the no-frames deadline after which the streaming I/O loop declares the session dead and reconnects. Default `3_000`; validated to `[100, 60_000]` at connect.
Set the streaming read timeout (ms): the no-frames deadline after which the streaming I/O loop declares the session dead and reconnects. Default `10_000`; validated to `[100, 60_000]` at connect.
"""
cpp_doc = """
Set the streaming read timeout (ms): the no-frames deadline after
which the streaming I/O loop reconnects. Default 3_000;
which the streaming I/O loop reconnects. Default 10_000;
validated to [100, 60_000] at connect.
"""
py_doc = """
Set the streaming read timeout (ms): the no-frames deadline after
which the streaming I/O loop declares the session dead and
reconnects. Default ``3_000``; validated to ``[100, 60_000]``.
reconnects. Default ``10_000``; validated to ``[100, 60_000]``.
"""
ts_doc = """
Set the streaming read timeout (ms): the no-frames deadline after which the streaming I/O loop declares the session dead and reconnects. Default `3_000n`; validated to `[100, 60_000]` at connect.
Set the streaming read timeout (ms): the no-frames deadline after which the streaming I/O loop declares the session dead and reconnects. Default `10_000n`; validated to `[100, 60_000]` at connect.
"""
py_param = "ms"
ts_param = "ms"
Expand All @@ -349,19 +349,19 @@ param = "out"
abi_type = "u64"
path = "streaming.timeout_ms"
doc = """
Read the current streaming `timeout_ms` setting (default `3_000`).
Read the current streaming `timeout_ms` setting (default `10_000`).

Writes the configured value into `*out`. Returns `0` on success,
`-1` if either pointer is null.
"""
cpp_doc = """
Current streaming timeout_ms (default 3_000).
Current streaming timeout_ms (default 10_000).
"""
py_doc = """
Current ``streaming.timeout_ms`` value (default ``3_000``).
Current ``streaming.timeout_ms`` value (default ``10_000``).
"""
ts_doc = """
Current `streaming.timeout_ms` value (default `3_000n`).
Current `streaming.timeout_ms` value (default `10_000n`).
"""

[[accessor]]
Expand Down
35 changes: 20 additions & 15 deletions thetadatadx-rs/src/config/fpss.rs
Original file line number Diff line number Diff line change
Expand Up @@ -134,11 +134,16 @@ pub struct StreamingConfig {
/// Drives the per-connection initial socket read timeout, the framing
/// layer's mid-frame stall budget, and the I/O loop's overall
/// "no frames received" deadline that triggers
/// [`crate::RemoveReason::TimedOut`]. Default `3_000`
/// — the server heartbeats every ~100 ms on a quiet session, so
/// three seconds of total silence is ~30 missed heartbeats and a
/// dead link is declared quickly instead of after the previous
/// 10 s default. Validated to the range `[100, 60_000]` ms.
/// [`crate::RemoveReason::TimedOut`]. Default `10_000`, matching the
/// terminal's streaming socket read timeout. Right after a
/// full-market subscribe the server can fall fully silent (no
/// frames, no pings) for a few seconds while it sets the
/// subscription up; a 10 s deadline rides through that gap where a
Comment on lines +137 to +141
/// shorter one trips inside it and forces an unnecessary reconnect.
/// The ~100 ms cadence is the client's ping to the server, not an
/// inbound heartbeat; inbound frames and pings arrive roughly every
/// ~250 ms on an active session. Validated to the range
/// `[100, 60_000]` ms.
pub timeout_ms: u64,

/// Streaming event ring buffer size (slots).
Expand All @@ -154,14 +159,14 @@ pub struct StreamingConfig {

/// Streaming heartbeat ping interval in milliseconds.
///
/// The streaming server expects a heartbeat at this cadence and may
/// disconnect if it falls silent. Default `250` — the server's own
/// ~100 ms heartbeat is the primary liveness signal in the
/// reverse direction; the client ping mainly proves write-side
/// health, and a 4 Hz cadence does that without contributing to
/// inbound-frame pressure on a recovering upstream. Validated to
/// the range `[100, 300_000]` ms — sub-100 ms values are rejected
/// so a misconfiguration does not flood the upstream.
/// This is the client's outbound ping cadence to the server, and the
/// server may disconnect if it falls silent. Default `250` — the ping
/// mainly proves write-side health at a 4 Hz cadence without adding
/// inbound-frame pressure on a recovering upstream. Reverse-direction
/// liveness is the inbound frame and ping stream (~250 ms on an active
/// session), which [`Self::timeout_ms`] guards. Validated to the range
/// `[100, 300_000]` ms — sub-100 ms values are rejected so a
/// misconfiguration does not flood the upstream.
pub ping_interval_ms: u64,

/// Per-server TCP connect timeout in milliseconds. Default `2000`.
Expand Down Expand Up @@ -255,7 +260,7 @@ impl StreamingConfig {
],
host_selection: HostSelectionPolicy::Shuffled,
host_shuffle_seed: None,
timeout_ms: 3_000,
timeout_ms: 10_000,
ring_size: 131_072,
ping_interval_ms: 250,
connect_timeout_ms: 2_000,
Expand Down Expand Up @@ -301,7 +306,7 @@ mod tests {
#[test]
fn production_defaults_resilience_shape() {
let cfg = StreamingConfig::production_defaults();
assert_eq!(cfg.timeout_ms, 3_000);
assert_eq!(cfg.timeout_ms, 10_000);
assert_eq!(cfg.ping_interval_ms, 250);
assert_eq!(cfg.io_read_slice_ms, 25);
assert_eq!(cfg.keepalive_idle_secs, 5);
Expand Down
2 changes: 1 addition & 1 deletion thetadatadx-rs/src/config/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2013,7 +2013,7 @@ mod tests {
let config = DirectConfig::production_defaults();
let validated = config.validate().expect("production defaults validate");
assert_eq!(validated.historical.window_size_kb, 64);
assert_eq!(validated.streaming.timeout_ms, 3_000);
assert_eq!(validated.streaming.timeout_ms, 10_000);
assert_eq!(validated.streaming.ping_interval_ms, 250);
assert_eq!(validated.streaming.connect_timeout_ms, 2_000);
assert_eq!(validated.streaming.io_read_slice_ms, 25);
Expand Down
2 changes: 1 addition & 1 deletion thetadatadx-rs/src/fpss/connection.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
//! detection) so a peer that vanishes without a FIN/RST is detected
//! by the transport long before the platform default of 2+ hours
//! - Connect timeout: 2 seconds (configurable)
//! - Read timeout: configurable (default 3 seconds)
//! - Read timeout: configurable (default 10 seconds)
//! - Host order: fault-domain-aware per-client shuffle by default (see
//! [`order_hosts`]), `FixedOrder` escape hatch preserves declaration
//! order
Expand Down
6 changes: 3 additions & 3 deletions thetadatadx-ts/__tests__/config_resilience.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -67,17 +67,17 @@ test("reconnect callback registration switches policy", () => {

test("streaming transport defaults and round-trip", () => {
const cfg = Config.production();
assert.equal(cfg.streamingTimeoutMs, 3_000n);
assert.equal(cfg.streamingTimeoutMs, 10_000n);
assert.equal(cfg.streamingConnectTimeoutMs, 2_000n);
assert.equal(cfg.streamingPingIntervalMs, 250n);
assert.equal(cfg.streamingRingSize, 131_072n);
assert.equal(cfg.streamingIoReadSliceMs, 25n);
assert.equal(cfg.streamingKeepaliveIdleSecs, 5n);
assert.equal(cfg.streamingKeepaliveIntervalSecs, 2n);
assert.equal(cfg.streamingKeepaliveRetries, 2);
cfg.setStreamingTimeoutMs(10_000n);
cfg.setStreamingTimeoutMs(15_000n);
cfg.setStreamingKeepaliveIdleSecs(10n);
assert.equal(cfg.streamingTimeoutMs, 10_000n);
assert.equal(cfg.streamingTimeoutMs, 15_000n);
assert.equal(cfg.streamingKeepaliveIdleSecs, 10n);
});

Expand Down
4 changes: 2 additions & 2 deletions thetadatadx-ts/index.d.ts

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions thetadatadx-ts/src/_generated/config_accessors.rs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.