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.

Reply via email to