How to impl a loop in the lifetime of a variable?

pub async fn run(&self, socket_addr: SocketAddr) -> Result<(), Box<dyn Error>> {
        let listener = TcpListener::bind(socket_addr).await?;
        tokio::spawn(self.start_health_checking());
        while let Ok((inbound, _)) = listener.accept().await {
            if let Some(server) = self.random_server() {
                let transfer = LoadBalancer::transfer(inbound, server.socket_addr).map(|r| {
                    if let Err(e) = r {
                        println!("Failed to transfer; error={}", e);
                    }
                });
                tokio::spawn(transfer);
            }
        }
        Ok(())
    }
    pub async fn start_health_checking(&self) {
        loop {
            match self.health_check_status {
                HealthCheckStatus::On => {
                    let mut servers = self.servers.lock().unwrap();
                    servers
                        .retain(|server| std::net::TcpStream::connect(server.socket_addr).is_ok());
                }
                _ => break,
            }
            sleep(self.health_check_duration).await;
        }
    }

it keeps reminding me that I need to impl 'static for self in run function, but I don't want a static, I just want a loop when the variable is avaliable, not after it's dropped, can somebody help me with it? thanks

Similar to the std::thread::spawn(), a task created by the tokio::spawn() cannot have a reference from the outside as it may outlive any other tasks. So you need ownership of the every arguments including the self, but it should also be shared. It mean you need to wrap it with Arc.

Replace &self with self: Arc<Self> so each method call requires its own copy of the Arc-ed self. You can call it as Arc::clone(&self).start_health_checking() as it consumes the receiver.

Hi I tried your advice:

start_health_checking(self: Arc<&Self>)
tokio::spawn(LoadBalancer::start_health_checking(Arc::clone(&Arc::new(self))));

but it still reminds me static lifetime requirement

Arc<Self>

oh yes, but I met another problem with Arc, it can't be dropped since the reference it's in a loop

Can you share the current state of the code? It seems there're some &self still remaining.

pub async fn run(self, socket_addr: SocketAddr) -> Result<(), Box<dyn Error>> {
        let listener = TcpListener::bind(socket_addr).await?;
        let lb = Arc::new(self);
        tokio::spawn(LoadBalancer::start_health_checking(Arc::clone(&lb)));
        while let Ok((inbound, _)) = listener.accept().await {
            if let Some(server) = lb.random_server() {
                let transfer = LoadBalancer::transfer(inbound, server.socket_addr).map(|r| {
                    if let Err(e) = r {
                        println!("Failed to transfer; error={}", e);
                    }
                });
                tokio::spawn(transfer);
            }
        }
        Ok(())
    }

pub async fn start_health_checking(self: Arc<Self>) {
        loop {
            match self.health_check_status {
                HealthCheckStatus::On => {
                    let mut servers = self.servers.lock().unwrap();
                    servers
                        .retain(|server| std::net::TcpStream::connect(server.socket_addr).is_ok());
                }
                _ => break,
            }
            sleep(self.health_check_duration).await;
        }
    }

this is my current code

I think it's because of the arc in the loop stopped dropping

And what's the full error message printed on the cargo build?

Hi there's no error on build, it's just the logic not correct, I want a master task and a loop task running on the same time, but when master task finished, I want loop task finished too, but I don't know how to write such kind of code

I recommend checking out this stackoverflow question: How to remotely shut down running tasks with Tokio. In this case I would use abortable or JoinHandle::abort by calling abort from the master task when it exits.

You might want to put the call to abort in a destructor of a custom type to ensure it happens even if the task exits abnormally through e.g. a panic.

Thanks, I've used a AtomicBool to solve this