Railscale Connection Lifecycle

Deep-dive into Pipeline::do_connection() in train_track (train_track/src/core/service.rs).

Phase 1: Parse Until Routing Key

Client bytes -> FrameParser::parse() -> Stream<ParsedData>

Reads frames sequentially, buffering into pre_route_buf:

  • ParsedData::Passthrough(bytes) — raw bytes, buffered as-is
  • ParsedData::Parsed(frame) — processed through FramePipeline::process(), then into_bytes()

Breaks out of the loop when a frame returns Some from routing_key().

NoRoutingFrame

If the stream ends without producing a routing frame, returns RailscaleError::NoRoutingFrame.

Phase 2: Concurrent Route + Parse

let (dest_result, post_route_buf) = tokio::join!(
    router.route(&routing_key),
    async { /* continue parsing remaining frames */ }
);

Two things happen simultaneously:

  1. DestinationRouter::route() resolves the routing key to a connected upstream (e.g., TCP connect)
  2. Remaining frames continue parsing into post_route_buf

This overlaps upstream connection latency with continued request parsing.

Phase 3: Forward + Relay

pre_route_buf  -> dest.write() (sequential)
post_route_buf -> dest.write() (sequential)
                  dest.relay_response(&mut write_half) -> client

Flushes both buffers to the destination, then relays the upstream response back to the client’s write half.

Timing Breakdown

MetricWhat it measures
forward_durationPhase 1 + 2 + 3 (write) — total request forwarding
connect_durationPhase 2 — routing/upstream connect time
relay_durationPhase 3 (relay) — response piping time
total_durationFull connection lifetime

OTel Metrics

MetricTypeWhen
connections_totalCounterconn_start
connections_activeUpDownCounterconn_start / conn_end
connection_errorsCounteron error
connection_duration_secondsHistogramconn_end
request_forward_duration_secondsHistogramforward_done
upstream_connect_duration_secondsHistogramupstream_connected
response_relay_duration_secondsHistogramrelay_done
response_bytesHistogramrelay_done
frames_parsedCounterforward_done
bytes_passthroughCounterforward_done