Arc<RwLock<>> doesn't live long enough

I’m writing a function as follows. req.get::<State<SomeService>>().unwrap() gets me a Arc<RwLock<SomeService>>. When I try to do a read access on that and access functions in it, I get these errors -

`service_reader` does not live long enough
`service_state` does not live long enough
    pub fn collect_stats(&self, req: &mut Request) -> Vec<ServiceStatus> {
        let mut statuses = Vec::new();

        for service in self.services.iter() {
            match *service {
                ServiceEnum::RM => {
                    let service_state = req.get::<State<SomeService>>().unwrap();
                    let service_reader = service_state.read().unwrap();
                    println!("{}", service_reader.service_name());
                    statuses.push(ServiceStatus {
                        name: service_reader.service_name(),
                        data: service_reader.data(),
                    });
                }
                _ => doNothing(),
            }
        }

        return statuses;
    }

Can you please post the entire error message? Also, what’s the full return type of req.get()? And what’s the definition of ServiceStatus?

My guess is service_reader.service_name() and/or service_reader.data() is returning a reference tied to service_reader. That data is only accessible while the rwlock is held, which is limited to the body of that match arm. However, the code is attempting to add this to a Vec that outlives this block.

But as @jethrogb said, we need more info to say for sure.

Full error msg:

error[E0597]: `service_state` does not live long enough
   --> src/service/mod.rs:139:30
    |
139 |         let service_reader = service_state.read().unwrap();
    |                              ^^^^^^^^^^^^^ does not live long enough
...
161 |     }
    |     - borrowed value only lives until here
    |
note: borrowed value must be valid for the anonymous lifetime #1 defined on the method body at 131:5...
   --> src/service/mod.rs:131:5
    |
131 | /     pub fn collect_stats( &self, req: &mut Request ) -> Vec<ServiceStatus> {
132 | |
133 | |        let mut statuses = Vec::new();
134 | |        /* let service_state = req.get::<State<SomeService>>().unwrap();
...   |
160 | |         return statuses;
161 | |     }
    | |_____^

‘req’ is an iron request. ServiceStatus is just a struct of ‘name’ and ‘data’ fields

I guess you are right, so how do I add to a Vec inside the match arm and use that outside ?

Can you paste the definition of ServiceStatus and of the service_name() and data() methods?

@vitalyd

#[derive(Serialize)]
pub struct ServiceStatus<'a> {
    service_name: &'static str,
    service_data: &'a Value,
}

impl Status for SomeService {
    fn service_name(&self) -> &'static str {
        "SomeService"
    }

    fn service_data(&self) -> &Value {
        &self.config
    }
}

pub trait Status: Send + Sync {
    fn service_name(&self) -> &'static str;
    fn service_data(&self) -> &Value;
}

This is the problem:

Can you clone the Value? Is that (relatively) cheap? That would be the simplest fix: clone the value and store it in ServiceStatus, which in turn is added to the Vec that you return.

I tried cloning and adding a reference. I still get the error -

borrowed value does not live long enough
   --> src/service/mod.rs:142:150
    |
142 |                    statuses.push(ServiceStatus{ service_name: service_reader.service_name(), is_healthy: service_reader.is_healthy(), service_data: &service_reader.service_data().clone()});
    |                                                                                                                                                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^  - temporary value only lives until here
    |                                                                                                                                                      |
    |                                                                                                                                                      does not live long enough
    |
note: borrowed value must be valid for the anonymous lifetime #1 defined on the method body at 131:5...

ServiceStatus would own a Value itself, not have a reference (which is what you’re trying to do above, to a temporary nonetheless). So it would look like:

// no more lifetime parameter 'a
struct ServiceStatus {   
    service_name: &'static str,
    is_healthy: bool, // ??
    service_data: Value, <== holding a value here, not a reference
}

statuses.push(ServiceStatus { 
     service_name: service_reader.service_name(), 
     is_healthy: service_reader.is_healthy(), 
     service_data: service_reader.service_data().clone(),
   });

I’m going to assume is_healthy is just a bool or some other Copy type.

Got it. That solves the lifetime problem. Thank you!