
- Uso Join para esperar la salida de todos los servicios.
use std::time::Duration;
use async_std::task;
use std::collections::{HashSet, HashMap};
use futures::join;
use futures::future::join_all;
struct Sale {
id: i32,
user_id: i32,
product_id: i32,
// other stuff
}
struct Product {
id: i32,
name: String
}
struct User {
id: i32,
email: String
}
#[derive(Debug)]
struct SaleView {
id: i32,
product: String,
user: String
}
async fn query_db() -> Vec<Sale> {
// DB is so slow!!!! 😱
task::sleep(Duration::from_secs(1)).await;
vec!(
Sale { id: 1, user_id: 1, product_id: 1 },
Sale { id: 2, user_id: 1, product_id: 2 },
Sale { id: 3, user_id: 2, product_id: 3 },
)
}
async fn find_users_by_ids(ids:HashSet<i32>) -> Vec<User> {
// "Talks" to the user service
task::sleep(Duration::from_secs(2)).await;
vec!(
User { id: 1, email: String::from("[email protected]")},
User { id: 2, email: String::from("[email protected]")},
User { id: 3, email: String::from("ignored")}
).into_iter().filter(|u| ids.contains(&u.id)).collect()
}
async fn find_products_by_ids(ids:HashSet<i32>) -> Vec<Product> {
// Those 🤬 backend guys didn't make a bulk API
let products_futures = ids.into_iter()
.map(|id| find_product_by_id(id));
join_all(products_futures).await
}
async fn find_product_by_id(id:i32) -> Product {
task::sleep(Duration::from_millis(300)).await;
Product { id, name: String::from("Product ") + id.to_string().as_str()}
}
async fn async_main() -> Vec<SaleView> {
let sales = query_db().await;
let user_ids = sales.iter().map(|u| u.user_id).collect();
let product_ids = sales.iter().map(|u| u.product_id).collect();
let users_future = find_users_by_ids(user_ids);
let products_future = find_products_by_ids(product_ids);
let (users, products) = join!(users_future, products_future);
let users_by_id: HashMap<i32, &User> = users.iter().map(|u| (u.id, u)).collect();
let products_by_id: HashMap<i32, &Product> = products.iter().map(|p| (p.id, p)).collect();
sales.iter().map(|s| {
let p = products_by_id.get(&s.product_id).unwrap();
let u = users_by_id.get(&s.user_id).unwrap();
SaleView {
id: s.id,
product: p.name.clone(),
user: u.email.clone()
}}).collect()
}
fn main() {
println!("{:?}", task::block_on(async_main()))
}