Rust · Batches

Batches

use ucall::Batch;use ucall::Batching;use ucall::BodyDelivery; 1.0.0-rc.1 · 60202332

A batch endpoint gathers matching requests from every event loop into one queue and hands them to its handler in batches, which suits work that is cheaper per request in bulk, like GPU inference.

use std::time::Duration;
use ucall::*;

let mut server = Server::new(&[Interface::new("127.0.0.1:0").pipelined_requests(8)])?;
let batching = Batching { min_size: 16, max_size: 64, max_latency: Duration::from_millis(2) };
let infer = server.batch("/infer", Verb::Post, batching, |batch: Batch| {
    let inputs: Vec<&[u8]> = batch.iter().map(Request::body).collect();
    let scores: Vec<String> = inputs.iter().map(|input| input.len().to_string()).collect();
    for (request, score) in batch.into_iter().zip(scores) {
        let _ = request.reply(HTTPStatus::OK, &[], score.as_bytes());
    }
})?;

std::thread::scope(|scope| {
    scope.spawn(|| server.take_calls(0));
    scope.spawn(|| infer.take_batches());
    scope.spawn(|| {
        std::thread::sleep(Duration::from_millis(100));
        println!("{:?}", infer.statistics());
        server.stop();
    });
});

Batching dispatches as soon as min_size requests wait, never more than max_size at once, and a smaller batch once its oldest request waited max_latency; zero fields mean 1, 32 and 10 milliseconds. The handler runs on the thread polling the endpoint through take_batch or take_batches, never on an event loop, so a slow batch never stalls the network. A Batch lends its requests in arrival order: get and iter borrow them, take moves one out, and iterating it by value takes them all, forwards or reversed. Requests the handler neither replies to nor keeps answer 500 once it returns, and all of them do when it panics. Taken requests may be replied to later, from any thread, while their responses still leave each connection in request order.

The queue holds as many requests as the interfaces admit at once, connections times pipelined requests, and refuses more with 503. Server::stop releases the requests still queued without a reply, and a dropped BatchEndpoint leaves its queue unanswered until the server is freed. BatchEndpoint::statistics counts batches and requests, and whether each batch was dispatched on reaching max_size, on reaching min_size, or once max_latency passed, from any thread while the endpoint is polled.

API

StructBatchThe requests of one due batch, from every event loop, lent to the handler in arrival order.5
server.rs:1310 ↗
pub struct Batch<'batch>

Each request is taken out at most once, by index or by iterating; whatever the handler leaves answers 500 once it returns.

Implements

IntoIterator
lenRequests in the batch, taken or not.
server.rs:1316 ↗
pub fn len(&self) -> usize
is_emptyWhether the batch has no requests, which a dispatched batch never is.
server.rs:1321 ↗
pub fn is_empty(&self) -> bool
getBorrows request index, unless it was taken.
server.rs:1326 ↗
pub fn get(&self, index: usize) -> Option<&Request>
takeTakes request index out of the batch, to reply to it here or on another thread.
server.rs:1331 ↗
pub fn take(&mut self, index: usize) -> Option<Request>
iterBorrows every request not yet taken, in order.
server.rs:1336 ↗
pub fn iter(&self) -> impl DoubleEndedIterator<Item = &Request>
StructBatchingWhen a batch endpoint hands its queue to the handler; zero fields take the defaults of 1 request, 32 requests, and 10 milliseconds.
server.rs:1131 ↗
pub struct Batching

Fields

min_sizeusizeDispatch as soon as this many requests wait.
max_sizeusizeNever hand the handler more than this many requests at once.
max_latencyDurationDispatch a smaller batch once its oldest request waited this long.

Implements

Clone, Copy, StructuralPartialEq, PartialEq, Eq, Debug, Default
EnumBodyDeliveryWhen an endpoint's handler runs: once the body is buffered, or at headers time, with the body pulled through DetachedRequest::body_chunk.
types.rs:868 ↗
pub enum BodyDelivery

Values

BufferedThe handler runs once the whole body arrived, read through body.
StreamedThe handler runs once the headers arrived, and the body is pulled chunk by chunk.

Implements

Clone, Copy, StructuralPartialEq, PartialEq, Eq, Debug, Hash, Default