I suggest using errgroup <https://godoc.org/golang.org/x/sync/errgroup> (and/or context.Context <https://godoc.org/context#WithCancel> in general) instead of rolling your own cancellation and timeout logic. It should make it pretty much trivial to kick off all the queries and cancel the context once you got the first result. It will also allow you to propagate that cancellation seamlessly through the ecosystem (e.g. cancellation traverses network boundaries when used with grpc and it will kill child processes if they are spawned with a context <https://godoc.org/os/exec#CommandContext>). The errgroup documentation has specific examples for how to do this kind of thing.
I would, in any case, encourage you to use cancellation and not simply let the goroutines run, because that's just wasteful and might be incorrect. In particular, if they are writing to a channel, make sure that they don't block because there is no reader, which would leak resources. You should either wait for them, or make *sure* that they'll *eventually* die. On Tue, Oct 25, 2016 at 4:08 PM, Nick Patavalis <nick.patava...@gmail.com> wrote: > Hi, > > You don't *need* to wait for the goroutines to exit, per se, but, as far > as I can tell, your code will panic when it "return"s and one of the > still-running resolver goroutines try to send to the closed channel. > > One solution would be *not to close the channel upon return*. The channel > will be collected when the last goroutine exits. You must, though, make > sure that the resolver goroutines will *not block* sending on recvChann. > Use something like this: > > select { > case: recvChan <- r > default: > } > > > This would work, but it feels a bit dirty: you leave goroutines running > while you no longer need them. It would be better if you could make your > resolver goroutines cancel-able: > > > recvChan := make(chan *dnsRecord, 1) > quitChan := make(chan struct{}) > defer close(quitChan) > > for _, server := range DnsServers { > go doResolve(server, req, recvChan, quitChan) // query ip > address > } > > select { > case r := <-recvChan: // receive address > responseRecord(w, req, r) // response to client > case <-time.After(2 * time.Second): // timeout > } > > // chanQuit will be closed > return > > > Then you must make your resolvers quit when quitChannel is closed; > depending on what your resolvers do, it may be complicated. It is arguable > whether this extra complication is worth the gain. > > (you could also wait for the resolvers to stop after canceling them, but I > see no practical advantage in doing so...) > > > -- > 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. > For more options, visit https://groups.google.com/d/optout. > -- 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. For more options, visit https://groups.google.com/d/optout.