slawlor / ractor

Rust actor framework
MIT License
1.38k stars 69 forks source link

`CallResult` should return errors that occured handling the message #180

Closed tqwewe closed 10 months ago

tqwewe commented 11 months ago

Is your feature request related to a problem? Please describe. If a message handler fails when calling .call on an actor, CallResult::SenderError is returned with no error information.

Describe the solution you'd like CallResult::Failed(err) should be added to the CallResult enum containing if an error occured when handling the message.

Ideally, I'd be able to write the following code:

#[async_trait::async_trait]
impl Actor for TestActor {
    async fn handle(...) -> Result<(), ActorProcessingErr> {
        Err(anyhow!("command failed"))
    }
}

let result = call!(actor, MessageFormat::TestRpc, "Something".to_string());
match result {
    Ok(value) => { println!("{value}"); }
    Err(CallError::Failed(err)) => // Handle the error returned in the handle function
    Err(CallError::Timeout) => // Call timed out
    Err(CallError::SenderError) => // Is this still needed if we add Failed?
}

Describe alternatives you've considered Using a RpcReplyPort<Result<T, E>> to send the error back. However this makes it difficult to work with, as I cannot use the ? operator to simply return the error.

slawlor commented 10 months ago

I think this is something that can't and won't be fixed. If an actor's handler returns an error, it's going to kill (terminate) the actor. This is signifying some abnormal processing for the actor. If there's a pending RPC going on, then the sender will be dropped with the cleanup of the actor, which is why you get a SenderError response (since the async awaiter is no longer valid).

There's no underlying monitoring framework, outside of supervision, saying something like "This actor is dying with some error, reply to any pending RPC with this specific error". That would require some support for things like reflection probably to be able to (a) identify that there's a pending RPC and (b) propagate that information from the actor's task/thread to the caller's task/thread.

tqwewe commented 10 months ago

Thanks for the response!