-
Notifications
You must be signed in to change notification settings - Fork 8
Auction orchestration #147
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: main
Are you sure you want to change the base?
Conversation
|
|
||
| ### Auction Flow | ||
| A named configuration that defines: | ||
| - Which providers participate |
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.
Confirming "providers" means wrappers?
| - Which providers participate | ||
| - Execution strategy (parallel, waterfall, etc.) | ||
| - Timeout settings | ||
| - Optional mediator |
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.
mediator = final ad-server?
| strategy = "parallel_mediation" | ||
| bidders = ["prebid", "aps"] | ||
| mediator = "gam" | ||
| timeout_ms = 2000 |
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.
timeout meaning the time for PBS, APS etc to come back to TS right? This does not include any GAM RT's or think time?
|
|
||
| **Flow:** | ||
| 1. Prebid and APS run in parallel | ||
| 2. Both return their bids simultaneously |
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.
Better way to say is that "Both return their bids within a time window" as they'll never be simultaneous
|
|
||
| **Flow:** | ||
| 1. All bidders run in parallel | ||
| 2. Highest bid wins |
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.
This may be addressed elsewhere, but AFAIK APS doesn't return a clear text creative bid, so we'll need to understand what the decryption of the TAM value looks like
|
|
||
| **Flow:** | ||
| 1. Try Prebid first | ||
| 2. If Prebid returns no bids, try APS |
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.
Let's discuss this on a call as it's not really a realistic scenario where PBS comes back with nothing and I don't know any pubs interested in waterfalls these days. We also need to make sure we are considering bid floors set by publishers here. Maybe I'm missing context?
aram356
left a comment
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.
Code review from senior developer perspective - adding inline comments on specific concerns.
|
🔧 Critical: Global Static Singleton Initialization Order Risk File: The static GLOBAL_ORCHESTRATOR: OnceLock<AuctionOrchestrator> = OnceLock::new();
pub fn get_orchestrator(settings: &Settings) -> &'static AuctionOrchestrator {
GLOBAL_ORCHESTRATOR.get_or_init(|| { ... })
}Suggestion: Either:
|
|
🔧 Critical: Memory Leak in Route Registration File: let static_path: &'static str = Box::leak(script_path.clone().into_boxed_str());This leaks memory. While the comment says it's "safe because config lives for app lifetime," this is still a code smell and will show up in memory profilers. Suggestion: Use a different pattern:
|
|
🔧 Important: Raw Provider Reference Storage Pattern File: pending_requests.push((
provider.provider_name(),
pending,
start_time,
provider.as_ref(), // Raw reference stored alongside owned data
));Storing Suggestion: Clone the provider pending_requests.push((
provider.clone(), // Arc<dyn AuctionProvider>
pending,
start_time,
)); |
|
🔧 Important: Hash-Based "Randomness" Behavior Undocumented File: let should_gam_win = {
let mut hasher = DefaultHasher::new();
slot_id.hash(&mut hasher);
let hash_val = hasher.finish();
(hash_val % 100) < self.config.win_rate as u64
};Using
Suggestion:
|
|
🔧 Important: Error Handling Timing Inconsistency File: match provider.parse_response(response, response_time_ms) {
Ok(auction_response) => { ... }
Err(e) => {
log::warn!("Provider '{}' failed to parse response: {:?}", provider_name, e);
responses.push(AuctionResponse::error(provider_name, response_time_ms));
}
}When a provider fails to parse a response, an error response is added with Suggestion: Track response receipt time separately from total processing time, or add metadata distinguishing network time from processing time: AuctionResponse::error(provider_name, response_time_ms)
.with_metadata("error_phase", json!("parse")) |
|
⛏️ Minor: OrchestrationResult Helper Methods Position File: The // Current structure:
impl AuctionOrchestrator { ... } // line 35-409
#[cfg(test)]
mod tests { ... } // line 412-771
impl OrchestrationResult { ... } // line 773-792 ← buried after testsSuggestion: Move |
💡 Architecture Suggestion: Builder Pattern for AuctionRequestFile: Building // Current approach - verbose
Ok(AuctionRequest {
id: Uuid::new_v4().to_string(),
slots,
publisher: PublisherInfo {
domain: settings.publisher.domain.clone(),
page_url: Some(format!("https://{}", settings.publisher.domain)),
},
user: UserInfo {
id: synthetic_id,
fresh_id,
consent: None,
},
device,
site: Some(SiteInfo { ... }),
context: HashMap::new(),
})
// With builder - cleaner
AuctionRequest::builder()
.id(Uuid::new_v4())
.slots(slots)
.publisher(&settings.publisher.domain)
.user(synthetic_id, fresh_id)
.device_from_request(&req)
.build()This would also make it easier to add optional fields in the future without changing all call sites. |
No description provided.