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 <yego...@gmail.com> 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 golang-nuts+unsubscr...@googlegroups.com. To view this discussion on the web visit https://groups.google.com/d/msgid/golang-nuts/de39eb18-2188-4236-ac33-6ec9109ce68fo%40googlegroups.com.