"the type `impl Future<Output = [async output]>` does not fulfill the required lifetime" when spawning a new thread in rust

Hello everyone,

I am new to rust, I've been trying to spawn a new Tokio thread to insert the Redis key value but I am facing this error

error[E0759]: `self` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement
   --> src/main.rs:27:25
    |
27  |     pub async fn insert(&mut self) {
    |                         ^^^^^^^^^ this data with an anonymous lifetime `'_`...
28  |         let th = tokio::spawn(async move {
    |                  ------------ ...is used and required to live as long as `'static` here
    |
note: `'static` lifetime requirement introduced by this bound
    |
127 |         T: Future + Send + 'static,
    |                            ^^^^^^^

error[E0477]: the type `impl Future<Output = [async output]>` does not fulfill the required lifetime
   --> src/main.rs:28:18
    |
28  |         let th = tokio::spawn(async move {
    |                  ^^^^^^^^^^^^
    |
note: type must satisfy the static lifetime as required by this binding
    |
127 |         T: Future + Send + 'static,
    |                            ^^^^^^^

Code:

use std::{error::Error};
use tokio;

use redis::{
    AsyncCommands, Client,
};

#[tokio::main]
async fn main() -> Result<(), Box<dyn Error>> {
    // 1) Create Connection
    let client = Client::open("redis://127.0.0.1:6379")?;
    let mut con = client.get_tokio_connection().await?;
    let mut cache_ops = CacheOperations::new(&mut con);
    cache_ops.insert();
    Ok(())
}

struct CacheOperations<'a> {
    redis_client: &'a mut redis::aio::Connection,
}

impl<'a> CacheOperatios<'a> {
    pub fn new(redis_client: &'a mut redis::aio::Connection) -> Self {
        Self { redis_client }
    }

    pub async fn insert(&mut self) {
        let th = tokio::spawn(async move {
            let h = self
                .redis_client
                .set::<String, String, String>("ok final".to_string(), "Hello world!".to_string())
                .await;
            let result = self
                .redis_client
                .get::<String, String>("my_key".to_string())
                .await;
            println!("->> my_key: {:?}\n", result);
        });

        th.await.unwrap();
    }
}

Thanks in advance.

Why are you spawning a task? You can just do this:

pub async fn insert(&mut self) {
    let h = self
        .redis_client
        .set::<String, String, String>("ok final".to_string(), "Hello world!".to_string())
        .await;
    let result = self
        .redis_client
        .get::<String, String>("my_key".to_string())
        .await;
    println!("->> my_key: {:?}\n", result);
}

Also, why a mutable reference? I suspect you will have more success by storing it by-value.

1 Like

(I'm a noob just experimenting to find the best solution here)

I agree! But I will be making around 100k Redis inserts, It will be split into 10 batches and 10K inserts/thread.

That's the reason I am trying to experiment with a simple Redis insert with thread


It is a reference because that connection will be used in different implementations as well and rust made me to make it mutable.

If you wanted to parallelize inserts, then the tokio::spawn call would go outside the insert calls. Additionally, since your insert method takes &mut self, it's impossible to call it from several places in parallel, so you would need to create a separate connection per spawned task.

So the right solution here is to make all the inserts from the main thread right?

Well, if you want single-threaded inserts, sure.

Thanks! So there is no way to parallelize the inserts without creating a new connection for every thread ?

I don't know what the redis library supports, but if there is, such a solution requires that you can change the insert function to take &self instead of &mut self.

1 Like

I've never used this redis crate myself, but I've answered someone else's question before and came across MultiplexedConnection and ConnectionManager which claim to support "requests to be be sent concurrently on the same underlying connection". You can clone those handles to a connection (they implement Clone), so each parallel task/thread can have its own clone to call the necessary &mut self methods on concurrently. As mentioned, I've never used this stuff, or "redis" in general, so no guarantees if this will have any of the desired performance benefit you might expect from parallelizing stuff.

Thank you very much, It works!!

How did you find these methods? I did search Redis documentation but I couldn't find it.

I don't remember how I came across them at the time, possibly by looking at the module-level docs of the aio module and seeing those types listed there, then just being curious to find out what those are for. It also was fairly hard to me to find out how to construct those, until I somehow came across the Client struct's methods like "get_tokio_connection_manager" or "get_multiplexed_tokio_connection", etc.

1 Like

FYI, just looked it up, this was the thread

1 Like

This helped a lot, Thanks!