Typically, a network communication system, like gRPC for example, will
accept contexts for network calls and turn context done-ness into an error.
The typical signature of an RPC-backed function is
func(context.Context, req *Request) (*Response, error)
If the context times out or is cancelled, a good RPC library will return
from this call immediately with a non-nil error. So context done-ness
checking is just part of ordinary error checking.
I'm not sure how you're mapping the RPCs to channels. If you're doing
res, err := RPC(ctx, req)
if err != nil { return ... }
ch <- res
then you indeed have a problem: you'll need another check whenever you
receive from the channel. But if you're doing
res, err := RPC(ctx, req)
ch <- rpcResult{res, err}
then receivers don't have to check ctx.Done, but of course they do have to
check the error:
result <- ch
if result.err != nil { ...}
// use result.res
Channels are a bit awkward either way, so for the Google Cloud client
libraries we use an iterator pattern (
https://github.com/googleapis/google-cloud-go/wiki/Iterator-Guidelines).
On Tuesday, June 9, 2020 at 8:04:21 AM UTC-4, Yegor Roganov wrote:
>
> Thanks Ian, it's nice to know that we're using Go correctly.
>
> I agree that more code doesn't really matter, and I think I'd be
> completely fine with this situation had there been a vet check that ensured
> that no selects are forgotten.
> Let's see if generics change something in this area.
>
> On Monday, June 8, 2020 at 10:46:05 PM UTC+3, Ian Lance Taylor wrote:
>>
>> On Mon, Jun 8, 2020 at 9:59 AM Yegor Roganov <[email protected]> wrote:
>> >
>> > My team is developing a cloud-based data processing application, and a
>> large bulk of the application's job is doing network calls to other
>> services.
>> > Go's goroutines and channel-based communication are an excellent fit,
>> but in order for the application to be able to properly shut down,
>> > simple construct of sending to a channel `myChan <- value` needs to
>> actually be something like:
>> >
>> > ```
>> >
>> > select {
>> > case myChan <- value:
>> > case <-ctx.Done():
>> > return ctx.Err()
>> > }
>> >
>> > ```
>> >
>> > As you see, a simple one line construct needs to be replaced with a
>> select on context.Done EVERYWHERE.
>> > My two gripes with this situation are:
>> >
>> > 1) It's more code and "clutter" which makes code less clear
>> > 2) It's easy to forget to do a select on context.Done, and then an
>> application is unable to shut down.
>> >
>> > Am I doing something wrong? Does someone relate with me?
>>
>> You are not doing anything wrong, and, you're right: it's more code.
>>
>> In general, Go prefers code to be explicit rather than implicit, so I
>> don't really agree that this makes the code less clear. I think that
>> this code is clear to anybody who knows Go, and with more experience
>> it becomes fairly idiomatic.
>>
>> But you're absolutely right that it's easy to forget to do a select.
>>
>> Personally I think that this is an area where generics can help. For
>> example, from the design draft published last year, see
>>
>> https://go.googlesource.com/proposal/+/refs/heads/master/design/go2draft-contracts.md#channels
>>
>> . I think the right step here is going to be see how generics can
>> help with these common patterns before trying other approaches. I
>> acknowledge that that is a slow process.
>>
>> Ian
>>
>
--
You received this message because you are subscribed to the Google Groups
"golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
To view this discussion on the web visit
https://groups.google.com/d/msgid/golang-nuts/de39eb18-2188-4236-ac33-6ec9109ce68fo%40googlegroups.com.