-
Notifications
You must be signed in to change notification settings - Fork 8
Migrate integration and provider HTTP types (PR 13) #626
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: feature/edgezero-pr12-handler-layer-types
Are you sure you want to change the base?
Changes from all commits
e9ec0a8
d2fa12d
442a6e2
0db7beb
5dbbfb0
94ec947
6d9d96a
4b27087
a2036eb
86bd21e
9694980
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -5,7 +5,6 @@ use std::collections::HashMap; | |
| use std::sync::Arc; | ||
| use std::time::{Duration, Instant}; | ||
|
|
||
| use crate::compat::platform_response_to_fastly; | ||
| use crate::error::TrustedServerError; | ||
| use crate::platform::{PlatformPendingRequest, RuntimeServices}; | ||
|
|
||
|
|
@@ -145,7 +144,6 @@ impl AuctionOrchestrator { | |
| let mediator_context = AuctionContext { | ||
| settings: context.settings, | ||
| request: context.request, | ||
| client_info: context.client_info, | ||
| timeout_ms: remaining_ms, | ||
| provider_responses: Some(&provider_responses), | ||
| services: context.services, | ||
|
|
@@ -154,6 +152,7 @@ impl AuctionOrchestrator { | |
| let start_time = Instant::now(); | ||
| let pending = mediator | ||
| .request_bids(request, &mediator_context) | ||
| .await | ||
| .change_context(TrustedServerError::Auction { | ||
| message: format!("Mediator {} failed to launch", mediator.provider_name()), | ||
| })?; | ||
|
|
@@ -165,18 +164,11 @@ impl AuctionOrchestrator { | |
| .change_context(TrustedServerError::Auction { | ||
| message: format!("Mediator {} request failed", mediator.provider_name()), | ||
| })?; | ||
| let backend_response = platform_response_to_fastly(platform_resp).change_context( | ||
| TrustedServerError::Auction { | ||
| message: format!( | ||
| "Mediator {} returned an unsupported response body", | ||
| mediator.provider_name() | ||
| ), | ||
| }, | ||
| )?; | ||
|
|
||
| let response_time_ms = start_time.elapsed().as_millis() as u64; | ||
| let mediator_resp = mediator | ||
| .parse_response(backend_response, response_time_ms) | ||
| .parse_response(platform_resp, response_time_ms) | ||
| .await | ||
| .change_context(TrustedServerError::Auction { | ||
| message: format!("Mediator {} parse failed", mediator.provider_name()), | ||
| })?; | ||
|
|
@@ -325,7 +317,6 @@ impl AuctionOrchestrator { | |
| let provider_context = AuctionContext { | ||
| settings: context.settings, | ||
| request: context.request, | ||
| client_info: context.client_info, | ||
| timeout_ms: effective_timeout, | ||
| provider_responses: context.provider_responses, | ||
| services: context.services, | ||
|
|
@@ -339,14 +330,25 @@ impl AuctionOrchestrator { | |
| ); | ||
|
|
||
| let start_time = Instant::now(); | ||
| match provider.request_bids(request, &provider_context) { | ||
| match provider.request_bids(request, &provider_context).await { | ||
| Ok(pending) => { | ||
| let request_backend_name = pending | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🤔 thinking — Worth a
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🤔 thinking — Worth a |
||
| .backend_name() | ||
| .map(str::to_string) | ||
| .unwrap_or_else(|| { | ||
| log::debug!( | ||
| "Provider '{}' pending request returned no backend name; \ | ||
| using predicted name '{}'", | ||
| provider.provider_name(), | ||
| backend_name, | ||
| ); | ||
| backend_name.clone() | ||
| }); | ||
| backend_to_provider.insert( | ||
| backend_name.clone(), | ||
| request_backend_name.clone(), | ||
| (provider.provider_name(), start_time, provider.as_ref()), | ||
| ); | ||
| pending_requests | ||
| .push(PlatformPendingRequest::new(pending).with_backend_name(backend_name)); | ||
| pending_requests.push(pending); | ||
| log::debug!( | ||
| "Request to '{}' launched successfully", | ||
| provider.provider_name() | ||
|
|
@@ -400,31 +402,19 @@ impl AuctionOrchestrator { | |
| { | ||
| let response_time_ms = start_time.elapsed().as_millis() as u64; | ||
|
|
||
| match platform_response_to_fastly(platform_response) { | ||
| Ok(response) => { | ||
| match provider.parse_response(response, response_time_ms) { | ||
| Ok(auction_response) => { | ||
| log::info!( | ||
| "Provider '{}' returned {} bids (status: {:?}, time: {}ms)", | ||
| auction_response.provider, | ||
| auction_response.bids.len(), | ||
| auction_response.status, | ||
| auction_response.response_time_ms | ||
| ); | ||
| responses.push(auction_response); | ||
| } | ||
| Err(e) => { | ||
| log::warn!( | ||
| "Provider '{}' failed to parse response: {:?}", | ||
| provider_name, | ||
| e | ||
| ); | ||
| responses.push(AuctionResponse::error( | ||
| provider_name, | ||
| response_time_ms, | ||
| )); | ||
| } | ||
| } | ||
| match provider | ||
| .parse_response(platform_response, response_time_ms) | ||
| .await | ||
| { | ||
| Ok(auction_response) => { | ||
| log::info!( | ||
| "Provider '{}' returned {} bids (status: {:?}, time: {}ms)", | ||
| auction_response.provider, | ||
| auction_response.bids.len(), | ||
| auction_response.status, | ||
| auction_response.response_time_ms | ||
| ); | ||
| responses.push(auction_response); | ||
| } | ||
| Err(e) => { | ||
| log::warn!( | ||
|
|
@@ -638,17 +628,8 @@ mod tests { | |
| AdFormat, AdSlot, AuctionRequest, Bid, MediaType, PublisherInfo, UserInfo, | ||
| }; | ||
|
|
||
| // All-None ClientInfo used across tests that don't need real IP/TLS data. | ||
| // Defined as a const so &EMPTY_CLIENT_INFO has 'static lifetime, avoiding | ||
| // the temporary-lifetime issue that arises with &ClientInfo::default(). | ||
| const EMPTY_CLIENT_INFO: crate::platform::ClientInfo = crate::platform::ClientInfo { | ||
| client_ip: None, | ||
| tls_protocol: None, | ||
| tls_cipher: None, | ||
| }; | ||
| use crate::platform::test_support::noop_services; | ||
| use crate::test_support::tests::crate_test_settings_str; | ||
| use fastly::Request; | ||
| use std::collections::{HashMap, HashSet}; | ||
|
|
||
| use super::AuctionOrchestrator; | ||
|
|
@@ -757,18 +738,19 @@ mod tests { | |
| } | ||
|
|
||
| // TODO: Re-enable provider integration tests after implementing mock support | ||
| // for send_async(). Mock providers can't create PendingRequest without real | ||
| // Fastly backends. | ||
| // for `PlatformHttpClient::send_async()`. Mock providers currently cannot | ||
| // create realistic pending requests for the select loop without real | ||
| // platform-backed transport handles. | ||
| // | ||
| // Untested timeout enforcement paths (require real backends): | ||
| // - Deadline check in select() loop (drops remaining requests) | ||
| // - Mediator skip when remaining_ms == 0 (bidding exhausts budget) | ||
| // - Provider skip when effective_timeout == 0 (budget exhausted before launch) | ||
| // - Provider context receives reduced timeout_ms per remaining budget | ||
| // | ||
| // Follow-up: introduce a thin abstraction over `select()` (e.g. a trait) | ||
| // Follow-up: introduce a thin abstraction over `PlatformHttpClient::select()` | ||
| // so the deadline/drop logic can be unit-tested with mock futures instead | ||
| // of requiring real Fastly backends. An `#[ignore]` integration test | ||
| // of requiring real platform backends. An `#[ignore]` integration test | ||
| // exercising the full path via Viceroy would also catch regressions. | ||
|
|
||
| #[tokio::test] | ||
|
|
@@ -786,8 +768,12 @@ mod tests { | |
|
|
||
| let request = create_test_auction_request(); | ||
| let settings = create_test_settings(); | ||
| let req = Request::get("https://test.com/test"); | ||
| let context = create_test_auction_context(&settings, &req, &EMPTY_CLIENT_INFO, 2000); | ||
| let req = http::Request::builder() | ||
| .method(http::Method::GET) | ||
| .uri("https://test.com/test") | ||
| .body(edgezero_core::body::Body::empty()) | ||
| .expect("should build request"); | ||
| let context = create_test_auction_context(&settings, &req, 2000); | ||
|
|
||
| let result = orchestrator | ||
| .run_auction(&request, &context, &noop_services()) | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍 praise — Clean elimination of the
compat::to_fastly_request/compat::from_fastly_responseround-trip for integration dispatch. The proxy registry now operates onhttp::Request<EdgeBody>end-to-end, which removes a non-trivial amount of conversion overhead per request and eliminates an entire class of header-mapping bugs.