Return chunked body data as soon as it is available
Implemented-By: OpenCode session (model recorded in docs/implementer-log.md)
This commit is contained in:
@@ -292,9 +292,6 @@ impl<'a> Body<'a> {
|
||||
}
|
||||
},
|
||||
ChunkPhase::Data => {
|
||||
if buf.len() - written == 0 {
|
||||
return Ok(written);
|
||||
}
|
||||
if self.buf.is_empty() {
|
||||
let k = self.stream.read(&mut tmp)?;
|
||||
if k == 0 {
|
||||
@@ -310,9 +307,8 @@ impl<'a> Body<'a> {
|
||||
self.chunk_remaining -= take;
|
||||
if self.chunk_remaining == 0 {
|
||||
self.phase = ChunkPhase::Crlf;
|
||||
} else if buf.len() - written == 0 {
|
||||
return Ok(written);
|
||||
}
|
||||
return Ok(written);
|
||||
}
|
||||
ChunkPhase::Crlf => {
|
||||
if self.buf.len() >= 2 {
|
||||
|
||||
@@ -308,3 +308,46 @@ fn a_missing_socket_is_a_connect_error() {
|
||||
let e: Box<dyn std::error::Error> = Box::new(HttpError::Timeout);
|
||||
assert!(!e.to_string().is_empty());
|
||||
}
|
||||
|
||||
/// A streamed body is read while it arrives. A `read` that already has data must not block
|
||||
/// waiting for more, or every event is delivered one buffer late and the last ones only when
|
||||
/// the stream ends.
|
||||
#[test]
|
||||
fn streamed_data_is_delivered_as_it_arrives() {
|
||||
let server = FakeServer::start();
|
||||
let reply = Reply::fixture("turn1");
|
||||
let piece = reply.offset_after_events(1);
|
||||
// About one event per piece, 300 ms apart: the whole stream takes over a second.
|
||||
server.route("/v1/chat/completions", vec![reply.trickle(piece, 300)]);
|
||||
let mut conn = Connection::open(&server.socket).unwrap();
|
||||
conn.set_read_timeout(Duration::from_secs(5)).unwrap();
|
||||
conn.send(&Request {
|
||||
method: "POST",
|
||||
path: "/v1/chat/completions",
|
||||
body: Some(b"{}"),
|
||||
})
|
||||
.unwrap();
|
||||
let head = conn.read_head().unwrap();
|
||||
let started = std::time::Instant::now();
|
||||
let mut body = conn.body(&head).unwrap();
|
||||
let mut arrivals = Vec::new();
|
||||
let mut buf = [0u8; 8192];
|
||||
loop {
|
||||
let n = std::io::Read::read(&mut body, &mut buf).unwrap();
|
||||
if n == 0 {
|
||||
break;
|
||||
}
|
||||
arrivals.push(started.elapsed());
|
||||
}
|
||||
let first = arrivals.first().copied().unwrap_or_default();
|
||||
let last = arrivals.last().copied().unwrap_or_default();
|
||||
assert!(
|
||||
first < Duration::from_millis(200),
|
||||
"the first data came only after {first:?}"
|
||||
);
|
||||
assert!(
|
||||
last - first >= Duration::from_millis(600),
|
||||
"everything arrived within {:?} of the first read: the reader is buffering the stream",
|
||||
last - first
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user