The current Sender.Send() blocks for the remote disposition. This is fine for many applications, but it does not allow sending at full network throughput because it forces the sender t idle for at least 2x the network latency between each send.
The doc mentions using goroutines, but this is not really workable - you lose control of message ordering. What you really want is an ordered stream of messages going out and an independent ordered stream of dispositions coming in.
One solution is to send the dispositions back on a channel, like https://github.com/apache/qpid-proton/blob/go1/electron/sender.go#L61
However I am currently leaning towards a design like this:
Sender { AsyncSend(Message) Result }
Result { Wait() error }
For the sync case this is almost as easy to use as blocking Send():
err := AsyncSend(Message).Wait()
and it supports the the channel solution for async:
type myResult struct { r: Result; extra: ...}
myResults := make(chan myResult, n)
go func() { ... ; myResults <- myResult{r: s.AsyncSend(m), extra: ...} ...}()
go func() { for r := range(myResults) { if err := r.r.Wait() {boom()} else { proces(r.extra)}})()
I'd like to hear comments on the design before I submit a PR.