I want to invoke a http rpc in rust, but current context is sync. Then I tried like this to invoke the remote rpc:
let uniq_id = executor::block_on(get_snowflake_id());
and this is the get_snowflake_id
function:
use std::env;
use log::error;
use reqwest::Client;
use rust_wheel::model::response::api_response::ApiResponse;
pub async fn get_snowflake_id() -> Option<i64> {
let client = Client::new();
let infra_url = env::var("INFRA_URL").expect("INFRA_URL must be set");
let url = format!("{}{}", infra_url, "/infra-inner/util/uniqid/gen");
let resp = client
.get(format!("{}", url))
.body("{}")
.send()
.await;
if let Err(e) = resp {
error!("get id failed: {}", e);
return None;
}
let text_response = resp.unwrap().text().await;
if let Err(e) = text_response {
error!("extract text failed: {}", e);
return None;
}
let resp_str = text_response.unwrap_or_default();
let resp_result = serde_json::from_str::<ApiResponse<i64>>(&resp_str);
if let Err(pe) = resp_result {
error!("parse failed: {}, response: {}", pe, &resp_str);
return None;
}
Some(resp_result.unwrap().result)
}
but this code is blocked forever, am I doing the right way to invoke async code in sync context? I have to do like this because the context is sync, I can not change the current context invoke style to async. I have tried:
pub fn get_uniq_id() -> Option<i64> {
task::block_in_place(|| {
tokio::runtime::Handle::current().block_on(get_snowflake_id())
})
}
shows error can call blocking only when running on the multi-threaded runtime
. This is the application entry:
#[actix_web::main]
async fn main() -> std::io::Result<()> {}
I want to invoke a http rpc in rust, but current context is sync. Then I tried like this to invoke the remote rpc:
let uniq_id = executor::block_on(get_snowflake_id());
and this is the get_snowflake_id
function:
use std::env;
use log::error;
use reqwest::Client;
use rust_wheel::model::response::api_response::ApiResponse;
pub async fn get_snowflake_id() -> Option<i64> {
let client = Client::new();
let infra_url = env::var("INFRA_URL").expect("INFRA_URL must be set");
let url = format!("{}{}", infra_url, "/infra-inner/util/uniqid/gen");
let resp = client
.get(format!("{}", url))
.body("{}")
.send()
.await;
if let Err(e) = resp {
error!("get id failed: {}", e);
return None;
}
let text_response = resp.unwrap().text().await;
if let Err(e) = text_response {
error!("extract text failed: {}", e);
return None;
}
let resp_str = text_response.unwrap_or_default();
let resp_result = serde_json::from_str::<ApiResponse<i64>>(&resp_str);
if let Err(pe) = resp_result {
error!("parse failed: {}, response: {}", pe, &resp_str);
return None;
}
Some(resp_result.unwrap().result)
}
but this code is blocked forever, am I doing the right way to invoke async code in sync context? I have to do like this because the context is sync, I can not change the current context invoke style to async. I have tried:
pub fn get_uniq_id() -> Option<i64> {
task::block_in_place(|| {
tokio::runtime::Handle::current().block_on(get_snowflake_id())
})
}
shows error can call blocking only when running on the multi-threaded runtime
. This is the application entry:
#[actix_web::main]
async fn main() -> std::io::Result<()> {}
Share
Improve this question
edited Mar 23 at 9:32
Dolphin
asked Mar 23 at 7:02
DolphinDolphin
39.3k102 gold badges376 silver badges717 bronze badges
6
|
Show 1 more comment
1 Answer
Reset to default 1If your application ready uses Tokio, you should use a dedicated blocking call provided by Tokio:
use tokio::runtime::Runtime;
fn invoke_sync() -> Option<i64> {
let rt = Runtime::new().unwrap();
rt.block_on(get_snowflake_id())
}
use tokio::runtime::Runtime;
use once_cell::sync::Lazy;
static TOKIO_RT: Lazy<Runtime> = Lazy::new(|| {
Runtime::new().expect("Failed to create Tokio runtime")
});
fn invoke_sync() -> Option<i64> {
TOKIO_RT.block_on(get_snowflake_id())
}
If your application running inside a Tokio runtime, you should use Tokio's dedicated blocking mechanism:
use tokio::task;
fn invoke_sync() -> Option<i64> {
task::block_in_place(|| {
// This is safe if you're already within a Tokio runtime
tokio::runtime::Handle::current().block_on(get_snowflake_id())
})
}
Use tokio::task::block_in_place + Handle::current().block_on(...)
Outside Tokio runtime (pure sync):
Create and reuse a global runtime (tokio::runtime::Runtime)
and call .block_on(...).
FYI:Docs-Tokio
executor::block_on
since reqwest depends on some tokio stuff. – cdhowie Commented Mar 23 at 7:23