Skip to content

Recovery Policy EN

b23r0 edited this page Oct 12, 2026 · 2 revisions

English · 简体中文

Recovery policy

Introduced in 1.2.0, available in published 1.4.0. These APIs are absent from 1.1.0. Recovery changes scheduling, not RakNet packet formats or reliability guarantees. It is independent of send-policy, and both compile features are off by default.

Enable and apply

[dependencies]
rust-raknet = { version = "1.4.0", features = ["recovery-policy"] }

For local development, use a task-specific source copy and a path dependency.

use rust_raknet::{RaknetSocket, RecoveryOptions};
use std::time::Duration;

async fn configure(socket: &RaknetSocket) -> rust_raknet::error::Result<()> {
    socket.set_recovery_options(RecoveryOptions {
        tail_probe_min_delay: Some(Duration::from_millis(10)),
        ..RecoveryOptions::default()
    }).await?;
    Ok(())
}

Call after connect or accept, before starting send tasks. This is a per-connection socket setting, not a listener builder. Configure each accepted socket. For a proxy, frontend and upstream are independent connections; configure each sending leg that needs the policy. Configuring one endpoint does not negotiate options with its peer. Inspect the requested settings with socket.recovery_options().await. Applying to a closed socket returns ConnectionClosed.

Every recovery option

Field Default Effect Trade-off
deadline_driven: bool false Wake maintenance for the earliest reliable retry deadline, reducing the wait for a periodic tick after expiry More precise scheduling can change throughput and latency under load; it does not lower the base RTO
tail_probe_min_delay: Option<Duration> None Permit one early replay of a complete eligible tail datagram; also enables deadline-driven maintenance Reduces some isolated loss waits; does not guarantee a throughput or congestion improvement
reset_backoff_on_progress: bool false On a fresh, unambiguous RTT sample, cap existing retry counts at one and recompute their deadlines May shorten prolonged recovery, but can increase retransmission pressure; retransmitted ACKs cannot trigger the reset

Default means all three are off. To evaluate only expiry scheduling:

socket.set_recovery_options(RecoveryOptions {
    deadline_driven: true,
    ..RecoveryOptions::default()
}).await?;

To evaluate progress backoff independently, set reset_backoff_on_progress: true and leave the other fields at their defaults. To preserve the current configuration when changing a field, read recovery_options(), edit that field, and apply it again. Configure before traffic where possible: reconfiguration resets the probe progress epoch while preserving an active probe's normal fallback deadline.

Probe conditions and timing

A probe requires valid RTT feedback after enabling the policy, an empty pending send queue and exactly one outstanding datagram that has never been retransmitted. A packed datagram may contain up to eight frames; all its members must remain outstanding and are replayed together under one new datagram sequence. With a send policy, pending unreliable work prevents probing, and the group must fit the flush budget. A full flight window is not probed wholesale.

The minimum wait is max(1 ms, configured minimum, ceil(1.5 × smoothed RTT)), measured from ACK progress or the start of a new flight. Zero and submillisecond values use the 1 ms floor; duration precision is milliseconds. One probe is allowed without further progress, and its transmission history prevents repeated probing of that datagram. A 10 ms setting is a floor, not a delivery deadline, and a slow path can require much longer.

The probe retains the original absolute RTO fallback deadline. If original and probe are both lost, ordinary timeout recovery still runs at that deadline. A probe does not increment the ordinary timeout-backoff count. ACKs for retransmitted/probed data do not update RTT (Karn's rule). Already-due ordinary retries take precedence; actual NACK/timeout recovery still disables future small-message coalescing as before.

Timestamp correction and unchanged estimator

Compiling recovery-policy also refreshes subsequent send timestamps after obtaining the queue lock and processing feedback. Lock contention therefore cannot backdate newly flushed data. This applies even with every option off. ACK RTT samples still use the input feedback timestamp.

The base estimator is unchanged: SRTT = (4 × old SRTT + sample) / 5, integer milliseconds; RTO = clamp(1.5 × SRTT, 50 ms, 12,000 ms). Ordinary retry backoff remains a 1.5 multiplier, bounded at 12,000 ms. Progress backoff only changes existing retry levels when its option is enabled. There is no adaptive congestion window, bandwidth estimator or rate pacer in this feature.

Disable

socket.set_recovery_options(RecoveryOptions::default()).await?;

This disables new probes, deadline-driven maintenance and progress backoff. An already-issued probe retains its normal fallback until retired. The timing correction remains compiled; build without recovery-policy to retain the original feedback/timing path. Unlike send policy, recovery has a default-settings reset API.

What the measurements showed

October 4, 2026, three controlled-link repeats. The following historical recovery experiment is separate from the October 12 cross-protocol benchmark, which does not enable recovery-policy.

Controlled scenario 1.1.0 Deadline only 10 ms minimum probe
One lost tail datagram 81.91 ms 55.86 ms 14.94 ms
One lost ACK 83.00 ms 55.86 ms 14.54 ms
Two lost target transmissions 168.72 ms 132.15 ms 55.06 ms
Bandwidth / RTT / queue step 4,819.20 ms 5,095.62 ms 5,097.49 ms

Tail/ACK cases used 100 Mbps / 2 ms RTT and reliable flush. The step switched from 100 Mbps / 30 ms RTT to 2 Mbps / 800 ms RTT with 32 KiB queues per direction, then validated 192 ordered 800 B echoes. Step completion measures the last echo. These are different workloads; the 15 ms results do not apply to the 800 ms RTT path.

Sustained throughput can fall: with 1,024 connections, 64 B, no injected loss and batch sends, this round's default build measured 140.68 MiB/s versus 118.74 MiB/s with probes. For 800 B the corresponding values were 466.86 and 393.23 MiB/s. Loaded latency had mixed results too. These are three-repeat medians, not universal guarantees or significance tests. Keep the default build for throughput-first workloads; evaluate recovery per connection for sparse messages and tail-loss-sensitive requests.

All configuration parameters · Send policy · Benchmark methodology

Clone this wiki locally