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
+12
View File
@@ -138,6 +138,18 @@ pub fn serve(
let deadline = span.map(|span| Instant::now() + span);
let mut reported: HashMap<(String, String), UploadRecord> = HashMap::new();
while deadline.is_none_or(|deadline| Instant::now() < deadline) {
// Queued states first, and from the client's own record rather than
// this snapshot: with few slots and small files a peer can queue and be
// served well inside one poll, and "it had to wait" is precisely what a
// transfer log exists to report.
for queued in session.client.take_upload_events() {
let record = upload_record(&queued);
let key = (record.user.clone(), record.path.clone());
if reported.get(&key) != Some(&record) {
ctx.out.emit(&record);
reported.insert(key, record);
}
}
for upload in session.client.uploads() {
let record = upload_record(&upload);
let key = (record.user.clone(), record.path.clone());