4 ms·
For me the biggest issue with Async is the management of multiple dependent async calls. It has some weird thing going on and I am not sure which pattern to use
by datadeft 3y ago
For me the biggest issue with Async is the management of multiple dependent async calls. It has some weird thing going on and I am not sure which pattern to use exactly. Some functions expect exactly same async fn signature some not and I am not sure why and which one to use.
- duped 3y agoI'm confused what you mean here. If you have a function that "depends on" another function you call it within the other function. If it's async you .await it. Do you mean something about spawning tasks or passing callbacks around?
- datadeft 3y agoI have this function that I still struggle to write. async fn function_handler(_event: Request) -> Result<Response<Body>, Error> { let aws_clients = AwsClients { s3_client: S3_CLIENT.get().await.to_owned(), glue_client: GLUE_CLIENT.get().await.to_owned(), athena_client: ATHENA_CLIENT.get().await.to_owned(), }; println!("{}", aws_clients); let config = CONFIG.get().await; let version = VERSION.get().await; let db_eid_cache = create_db_eid_cache(aws_clients.clone(), config); let table_eid_cache = create_table_eid_cache(aws_clients.clone(), config); let job_eid_cache = create_job_eid_cache(aws_clients.clone(), config); let table_summaries_cache = create_table_summaries_cache(aws_clients.clone(), config); let job_summaries_cache = create_job_summaries_cache(aws_clients.clone(), config); let query_summaries_cache = create_query_summaries_cache(aws_clients, config); let rez = tokio::join!( db_eid_cache, table_eid_cache, job_eid_cache, table_summaries_cache, job_summaries_cache, query_summaries_cache, ); let six_pack = SixPack { db_eid_cache: rez.0, table_eid_cache: rez.1, job_eid_cache: rez.2, table_summaries_cache: rez.3, job_summaries_cache: rez.4, query_summaries_cache: rez.5, }; let lambda_response = LambdaResponse { config, result: &six_pack, version: &version, now: utc_now(), }; let response_body = serde_json::to_string(&lambda_response)?; Ok(Response::builder() .status(200) .header("content-type", "application/json") .body(response_body.into()) .map_err(Box::new)?) } Not sure how to do error handling properly or what would be the idiomatic way to implement it.
- duped 3y agoIf you want to .await multiple futures that can return an error you can use tokio::try_join, futures_utils::try_join_all, etc. For example: let ( db_eid_cache, table_eid_cache, job_eid_cache, table_summaries_cache, job_summaries_cache, query_summaries_cache, ) = try_join!( create_db_eid_cache(aws_clients.clone(), config), create_table_eid_cache(aws_clients.clone(), config), create_job_eid_cache(aws_clients.clone(), config), create_table_summaries_cache(aws_clients.clone(), config), create_job_summaries_cache(aws_clients.clone(), config), create_query_summaries_cache(aws_clients.clone(), config), )?; The code dealing with your clients looks suspect. Why do you have a global with a .get method that is async and returns a reference? It should probably be sync. On top of that it probably shouldn't be a global variable. Pass it in as context to the handler. I'm also suspicious of having this `AwsClients` struct and a bunch of free functions that take it by owner. Why aren't you adding an `impl` block with those as methods? And why are they taking ownership requiring the .clone`?
- datadeft 3y agoGreat questions. I guess because I never used any language that had the concept of ownership and I could not find any example how to handle these connections. I try to take your input and refactor the code based on your input. Thanks a million!