I am trying to perform multiple concurrent GET requests using the reqwest library, while using a shared reference to the Client
object. The idea is this will be a long-lived client, and as suggested in the docs, I would like to take advantage of the keep-alive connection pooling (otherwise I could just construct a new client for every loop iteration):
use std::error::Error;
use futures::future::join_all;
use tokio::task::JoinHandle;
#[tokio::main]
async fn main() -> Result<(), Box<dyn Error>> {
let urls = vec![
"https://www.rust-lang.org/tools/install",
"https://www.rust-lang.org/learn",
"https://play.rust-lang.org/"
];
let client = reqwest::Client::builder().build()?;
let mut tasks: Vec<JoinHandle<reqwest::Result<String>>>= vec![];
for url in urls {
tasks.push(tokio::spawn(async move {
perform_fetch(&client, url).await
}));
}
join_all(tasks).await;
Ok(())
}
async fn perform_fetch(client: &reqwest::Client, url: &str) -> reqwest::Result<String> {
client.get(url)
.send()
.await?
.text()
.await
}
However, I am getting a compiler error:
error[E0382]: use of moved value: `client`
--> src\main.rs:17:44
|
13 | let client = reqwest::Client::builder().build()?;
| ------ move occurs because `client` has type `reqwest::Client`, which does not implement the `Copy` trait
...
17 | tasks.push(tokio::spawn(async move {
| ____________________________________________^
18 | | perform_fetch(&client, url).await
| | ------ use occurs due to use in generator
19 | | }));
| |_________^ value moved here, in previous iteration of loop
I tried removing the move
here:
tasks.push(tokio::spawn(async move {
But then I get another error:
error[E0373]: async block may outlive the current function, but it borrows `client`, which is owned by the current function
--> src\main.rs:17:39
|
17 | tasks.push(tokio::spawn(async {
| _______________________________________^
18 | | perform_fetch(&client, url).await
| | ------ `client` is borrowed here
19 | | }));
| |_________^ may outlive borrowed value `client`
|
= note: async blocks are not executed immediately and must either take a reference or ownership of outside variables they use
help: to force the async block to take ownership of `client` (and any other referenced variables), use the `move` keyword
|
17 | tasks.push(tokio::spawn(async move {
| ++++
Is there a way the client
reference can be shared between loop iterations without moving the value?
Here is the Cargo.toml
for this example:
[package]
name = "concurrent-requests"
version = "0.1.0"
edition = "2021"
[dependencies]
tokio = { version = "1.21.2", features = ["full"] }
futures = "0.3"
reqwest = "0.11.12"
And the playground link:
https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=90758d69aa61523ff1ca4c18abd44b7f