smol-rs/async-channel

Request/Reply pattern best practice

ufoscout opened this issue · 2 comments

Hi, what is the best way to get a reply from a message sent to a channel?
The only way I found to achive it is by creating a second temporary channel for each call and push the response into it.
For example:

pub struct ReplyRequest {
    pub message: String,
    pub responder: async_channel::Sender<String>,
}

async fn send_a_message(request_tx: async_channel::Sender<ReplyRequest>) {
        let (reply_tx, reply_rx) = async_channel::bounded(1);
        let message = "Hello world".to_owned();
        request_tx.send(ReplyRequest { message, responder: reply_tx }).await.unwrap();
        let received_response = reply_rx.recv().await.unwrap();
        println!("Replied: {}", received_response);
}

main(){
     let (request_tx, request_rx) = async_channel::bounded(1);
     your_executor::spawn(async move {
                loop {
                    match request_rx.recv().await {
                        Ok(message) => {
                             println!("Received: {}", message.message);
                            message.responder.send("A new World!".to_owned()).await.unwrap();
                        }
                        Err(err) => panic!()
                    }
        }
     })
    send_a_message(request_tx.clone()).await;
}

Is this the correct way of achieving it?

fogti commented

I have used async-oneshot for the response in the past. Example code (using macros) https://github.com/YZITE/yxd-auth/blob/3d6acb1371521b8a41874dbae727a9dc133fcb7f/crates/kdc/src/db_.rs#L8-L34

I think oneshot is a reasonable pattern here; the performance should not be that different compared to a dedicated oneshot channel because concurrent-queue optimize the single-capacity case