fix(serve): report a queued upload even when it is served between two polls

`serve` samples `uploads()` every 500ms and emits what changed, so an upload
state shorter than that window never reached the log. Nothing surfaced this
while every upload sat on its slot for a 500ms linger, which was exactly one
poll; with the linger gone a peer can queue and be served between two samples,
and "it had to wait" — the one thing the queue exists to record — silently
disappeared.

The pump now keeps whatever it left waiting, and `serve` drains that alongside
the snapshot, so the fact survives regardless of when the next sample lands.
The list is deduplicated per peer and file and capped, so a caller that never
drains cannot grow it without bound.

This is what made cli_e2e::serve_reports_a_queued_upload_once_the_slots_are_full
fail on CI while passing locally: the assertion was real, and it was timing that
decided whether the client could answer it.
This commit is contained in:
Michel de Graaf
2026-07-26 18:54:40 +02:00
parent 7435d48b32
commit db75a8266a
4 changed files with 97 additions and 0 deletions
+6
View File
@@ -344,6 +344,11 @@ pub struct ClientContext {
upload_seq: u64,
/// How many uploads may be in flight at once.
upload_slots: usize,
/// Queued-upload states that came and went between two polls of
/// [`Client::uploads`]. A caller sampling that snapshot would otherwise
/// never see a peer that queued and was served inside one poll interval,
/// and "it waited" is exactly the fact a transfer log must not lose.
upload_events: Vec<crate::types::UploadInfo>,
actor_system: Arc<ActorSystem>,
}
impl Default for ClientContext {
@@ -432,6 +437,7 @@ impl ClientContext {
upload_queue: Vec::new(),
upload_seq: 0,
upload_slots: DEFAULT_UPLOAD_SLOTS,
upload_events: Vec::new(),
downloads: DownloadStore::new(),
actor_system,
}