-
Notifications
You must be signed in to change notification settings - Fork 8
Description
Problem
The auction orchestrator's three timeout enforcement paths are untestable in unit tests:
- Deadline check in
select()loop — drops remaining requests whenauction_start.elapsed() >= deadline - Mediator skip — skips mediator when
remaining_ms == 0after bidding phase - Provider skip — skips provider launch when
effective_timeout == 0
The root cause is tight coupling to Fastly's concrete PendingRequest and select():
PendingRequest::new()ispub(super)— cannot be constructed outside the fastly crateselect()is a free function backed by Wasm host ABI calls- The
AuctionProvidertrait'srequest_bids()returnsPendingRequestdirectly
This means the orchestrator's select loop can only run on Fastly Compute (or Viceroy), never in a plain cargo test.
Suggested approach
Introduce a trait that abstracts over "a set of in-flight requests you can wait on":
/// Result from waiting on a set of pending provider requests.
pub struct ProviderResult {
pub backend_name: String,
pub result: Result<fastly::Response, fastly::http::request::SendError>,
}
/// Abstracts over the mechanism for waiting on concurrent provider requests.
///
/// Production uses Fastly's `select()`; tests inject a mock.
pub trait PendingRequestSet {
/// True when there are no more requests to wait on.
fn is_empty(&self) -> bool;
/// Block until the next request completes and return it.
fn select_next(&mut self) -> ProviderResult;
}The orchestrator's select loop changes from:
while !remaining.is_empty() {
let (result, rest) = select(remaining);
remaining = rest;
// ...
}to:
while !pending.is_empty() {
let result = pending.select_next();
// ...
}A production implementation wraps Vec<PendingRequest> and delegates to fastly::http::request::select(). A test implementation can return pre-canned responses with configurable delays (using std::thread::sleep or instant completion).
This unlocks tests like:
- Provider skip: set
timeout_ms: 0on context, verify no requests are launched - Deadline enforcement: mock 3 slow providers, verify the loop breaks after the deadline
- Mediator skip: inject provider responses that consume the full budget, verify mediator is skipped
Scope
- No behavior change — pure structural refactor
- Affected files:
orchestrator.rs,provider.rs(trait may need adjustment), new test mock - The
AuctionProvider::request_bids()return type may also need abstracting, or the trait boundary can be drawn at the select loop level only (simpler)
Context
Flagged during review of #469 (auction timeout enforcement). See the TODO at crates/common/src/auction/orchestrator.rs:711.