Search code examples
rustrust-tokiorust-futures

Borrowed data escapes outside of joined task


I have two fallible async functions I want to execute in parallel. The problem is that both functions take a reference, and the parameters to my wrapper function are also references. This gives me an error when I try to use task::spawn because the reference escapes the function. I know that a borrow may not outlive a function body, but as you can see, I am actually joining these tasks, so the references would not outlive the body of this function.

async fn decode_tokens<'auth, 'id>(
    x_authorization: &'auth str,
    x_user: &'id str,
) -> Result<AuthorizedUser, AuthorizationError> {
    let decode_auth_handle = task::spawn(decode_auth_token(x_authorization)); // error[E0521]: borrowed data escapes outside of function
    let decode_id_handle = task::spawn(decode_id_token(x_user)); // error[E0521]: borrowed data escapes outside of function

    // handles are joined here
    let auth_token = decode_auth_handle.await??; 
    let id_token = decode_id_handle.await??;

    Ok(AuthorizedUser {
        id_token: id_token,
        authorization_token: auth_token,
    })
}

Is my understanding wrong, or did I get my lifetime annotations wrong?

Also, I'd like to note that the functions decode_auth_token and decode_id_token both return Owned Results

I think I'd be able to get around this by annotating the return type of this function, but since the return type is also an Owned result, I don't think I can annotate it


Solution

  • Event though it returns an awaitable handle, spawn is intended more for long-running operations in fire and forget mode, or if you want to run more operations in the current function while the spawned task is running in the background. If you simply want to start multiple futures and await them all concurently, it's usually better (and certainly easier) to use join:

    let (auth_token, id_token) = join!(
       decode_auth_token (x_authorization),
       decode_id_token (x_user));
    
    Ok(AuthorizedUser {
        id_token: id_token?,
        authorization_token: auth_token?,
    })