Can you write your own ContextReader that checks ctx.Done in its Read method?
On Mon, 6 Jul 2020, at 2:40 PM, Brian Candler wrote: > I am looking for the safe way to do a clean shutdown when blocked on I/O. > Here is a basic example: > > package main > > import ( > "encoding/json" > "fmt" > "io" > "os" > "os/signal" > "syscall" > ) > > func main() { > rx := json.NewDecoder(os.Stdin) > > chanTERM := make(chan os.Signal, 1) > signal.Notify(chanTERM, syscall.SIGTERM) > > for { > select { > case <-chanTERM: > fmt.Println("Shutdown requested via signal") > os.Exit(0) > default: > } > > var msg interface{} > > err := rx.Decode(&msg) > if err != nil { > if err == io.EOF { > os.Exit(0) > } > fmt.Printf("Error: %v\n", err) > os.Exit(1) > } > fmt.Printf("Message: %v\n", msg) > } > } > > This sort-of works, except that once the code is blocked in rx.Decode(&msg), > the termination signal is not handled until another message arrives. > (Actually I'm using sockets - os.Stdin is just for example here). I'd like it > to shutdown immediately if it's not in the middle of doing something. > > The question is then how to unblock this reader. > > 1. Is there a way to link an io.Reader to a context, so I can just send the > ctx.Done() signal? If so, I couldn't find it. > > (I found this post > <https://pace.dev/blog/2020/02/03/context-aware-ioreader-for-golang-by-mat-ryer.html>, > but the library > <https://github.com/dolmen-go/contextio/blob/68fc5150bcd5/io.go#L66> has the > same issue: the context is checked before the read, but a cancel won't > unblock the read) > > 2. I can just close the input stream from another goroutine. This seems > fairly brutal. Also, to distinguish this condition from an actual error, it > seems I need to parse the error message and look for the text "use of closed > network connection" (github: #4373 <https://github.com/golang/go/issues/4373>) > > 3. I can move the rx.Decode(&msg) into a goroutine which passes a message > over a channel, and just let it lock up if there's no data coming in. This > isn't a problem here where I want to exit the entire program. If this was a > network server with many connections and I wanted to disconnect just one, > then I think I'd end up having to close the channel anyway to disconnect the > client. > > Is there another option I should be looking at? > > Thanks, > > Brian. > > -- > 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/3f3b6f98-ff9c-4829-844b-a0d0abc5d753o%40googlegroups.com > > <https://groups.google.com/d/msgid/golang-nuts/3f3b6f98-ff9c-4829-844b-a0d0abc5d753o%40googlegroups.com?utm_medium=email&utm_source=footer>. -- 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/d1c9f0d0-dbb3-4730-997d-2e13155509b6%40www.fastmail.com.