Listen then send with Coroutines

I have a question around coroutines specifically dealing with needing to listen for a response then send the request. I think an example might be easier then me trying to explain. I am going to use my specific use case, sending and receiving XMPP messages but try to remove some of the extra stuff that doesn’t really matter to the question. Super old way would be to just use listeners and set one up before I send. Its not great but it works.

xmppClient.addPacketListener { packet -> doStuff() } // listen for response
xmppClient.send(Packet()) // send request

With Rx, I usually solve this problem with a merge. I merge two observables, the listener and the deferred send. The deferred send never returns a value so it doesn’t matter what type it is. The merge is just there for ordering events.

val sendPacket = Observable.defer { xmppClient.send(Packet()) }
merge(xmppClient.packets(), sendPacket)
    .subscribe { packet ->
        doStuff()
    }

With coroutines I really don’t know what I am supposed to do to guarantee, no matter what, that I am listening before I send. Right now I have something like

val packetDefered = async { xmppClient.packets() }
yield()
xmppClient.send(Packet())
val packet = packetDefered.await()

The yield was to try and force this coroutine to give up execution so that the async was listening before I sent the packet. Otherwise I might miss the response to my packet. The only other thing I was thinking was that I could try to do something like the merge via awaitAll

val packet = awaitAll(
    async {
        xmppClient.packets()
    },
    async {
        xmppClient.send(Packet())
        null
    }
).firstNotNull()

Does anyone have any guidance on what to do here? This is a use case we have all the time. I don’t want to write it some way only to figure out we messed it up in a billion places.

Are you considered to start the async UNDISPATCHED?

@fvasco I actually didn’t know about that. I will experiment with that some.

EDIT:
After messing with that for a bit it does seem to do what I want.The only thing I am trying to do now is make it so that I don’t have to store the deferred and instead just get the response value back. That is a slightly different problem though.

1 Like

I do have the exact same issue! Could you post the code that actually worked for you.