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
+11
View File
@@ -49,6 +49,17 @@ impl Client {
/// How many uploads run at once. Lowering it does not interrupt transfers
/// already in flight; the queue simply refills more slowly.
/// Queued-upload states recorded since the last call, for a caller that
/// samples [`Client::uploads`] and would otherwise miss a peer that queued
/// and was served between two samples.
#[must_use]
pub fn take_upload_events(&self) -> Vec<crate::types::UploadInfo> {
self.context
.write_safe()
.map(|mut ctx| ctx.take_upload_events())
.unwrap_or_default()
}
pub fn set_upload_slots(&self, slots: usize) {
if let Ok(mut ctx) = self.context.write_safe() {
ctx.upload_slots = slots.max(1);