tidaldb/tidal-server/src
jordan 897c6086f5 fix(cluster): size the read fan-out budget for the transport it crosses
Restoring the three-node cluster for a first production consumer surfaced this
immediately: EVERY cross-shard read came back

  {"items":[...],"scatter_gather":{"degraded":true,
    "unavailable_shards":["tidaldb-0","tidaldb-2"],"shards_queried":1,
    "elapsed_ms":50,"shard_deadline_ms":45}}

HTTP 200, one shard of three, partial results. Replication itself was healthy -
/cluster/status showed all three regions reachable, lag_events 0, 13.3M events
applied each - so nothing in the quorum, election, or ship metrics moved.

Measured on the live cluster: a COLD peer fetch (TCP + TLS handshake + remote
1536-D search) takes ~50ms; a warm one takes ~1ms. DEFAULT_DEADLINE_MS is 50
(spec §7.4) and NETWORK_OVERHEAD_MS is 5, leaving a 45ms per-shard budget -
just under the cold cost. Proven by parameter sweep against one pod:

  deadline_ms=50   -> degraded, 1/3 shards, 0 items
  deadline_ms=250  -> healthy,  3/3 shards, elapsed 51ms
  deadline_ms=1000 -> healthy,  3/3 shards, elapsed 1ms (warm)

The 50ms spec figure budgets a shard READ, not establishing a connection to
another pod. m11p7 put TLS on that hop and the default never followed, so the
first query after any rollout, idle period, or pod restart answered from a third
of the corpus. Fixed with a transport-aware default: 50ms in-process,
TLS_DEFAULT_DEADLINE_MS (250ms) once inter-node TLS is configured. An explicit
`?deadline_ms=` still wins in both directions, and MAX_DEADLINE_MS is unchanged.

The worse half was silence. A degraded fan-out is the one cluster failure that
answers 200 OK: the caller gets a ranked list assembled from a subset of the
corpus with `degraded: true` buried in response metadata. Nothing incremented,
so no alert could exist - a feed quietly ranking over one third of its
candidates looked identical to a healthy one. Added
tidaldb_cluster_scatter_degraded_total and
tidaldb_cluster_scatter_shard_unavailable_total, emitted from both HTTP fan-out
paths, so partial answers are now a countable correctness signal.

Also sizes the cluster StatefulSet for a consumer instead of the endurance gate:
requests 2 cores -> 300m per voter (limit 2 cores). The 2-core reservation was
the 200 rps soak envelope and needed 6,000m plus 2,000m free on each of three
PV-pinned nodes; the fleet is 82-91% committed, so that contract could not be
placed and the cluster stayed parked for a gate nobody is waiting on. 300m is
what the tightest pinned node can reserve, with the quorum/write-pool alerts as
the detector if real load outgrows it.

Tests: default_read_budget_covers_a_cold_inter_node_tls_hop pins the budget
against the measured cold hop and the explicit-override path; the cluster-metrics
render test covers both new counters.
2026-08-17 20:28:21 -06:00
..
cluster fleet remediation: make the workspace gate runnable, then fix what it caught 2026-08-16 12:38:14 -06:00
cluster_config.rs feat(m9/m10/p1): community policy engine, signal revocation, agent capability boundaries, feedback loop, metrics instrumentation 2026-03-16 05:59:42 -06:00
config.rs feat(m12): multi-vector user preference modeling + ANN candidate-gen 2026-06-23 09:52:36 -06:00
dto.rs feat(m12p4): sharded ingestion — scatter-gather pool + cross-shard unified reads (L4) 2026-06-14 15:17:35 -06:00
error.rs docs: withdraw the pre-release "not ready for production" disclaimer 2026-07-30 19:03:34 -06:00
health.rs fix: M0-M10 third-pass remediation — durability, replication, and CLI hardening 2026-06-08 10:28:34 -06:00
lib.rs feat(m11): membership, snapshot install, and reseed (m11p5) 2026-06-12 19:55:54 -06:00
main.rs docs: withdraw the pre-release "not ready for production" disclaimer 2026-07-30 19:03:34 -06:00
offload.rs fix(m12-rc13): read-SLA collapse + WAL_RETENTION_SEGMENTS 16 + tidalctl S3 DR 2026-06-17 15:47:37 -06:00
openapi.rs docs: withdraw the pre-release "not ready for production" disclaimer 2026-07-30 19:03:34 -06:00
router.rs feat(m12p4): sharded ingestion — scatter-gather pool + cross-shard unified reads (L4) 2026-06-14 15:17:35 -06:00
scatter_gather.rs fix(cluster): size the read fan-out budget for the transport it crosses 2026-08-17 20:28:21 -06:00
self_exit.rs feat(m11): membership, snapshot install, and reseed (m11p5) 2026-06-12 19:55:54 -06:00
state.rs feat(m12): vector retrieval G1/G2 — recall harness, ANN in RETRIEVE, index tuning 2026-06-14 11:07:09 -06:00