FAQ
While implementing heartbeats for a long living HTTP connection on the
server,
I encountered a panic raised from the http package itself.
There isn't anything fancy in the implementation except for the fact that
the response writer
is passed to another goroutine. The code can be found
in http://play.golang.org/p/ElC4PpU-6S .
It doesn't run directly on the website, but I made sure it ran locally, and
the panic runtime
error is pretty reproducible and predictable.

These two threads suggested that writers not be passed to other goroutines,
but I'm not
convinced, since these panics don't occur if
* We don't write on line 14 `w.Write([]byte("hello"))`
* or if we don't provide the extra 100ms margin for the Sleep interval on
line 22 `time.Sleep(interval + 100 * time.Millisecond)`
https://groups.google.com/forum/#!searchin/golang-nuts/http$20flush/golang-nuts/vzVgBwJ1q2c/jCS_twDIScAJ
https://groups.google.com/forum/#!searchin/golang-nuts/http$20flush/golang-nuts/FLX9Ok5IepE/ePp3-nrcWFwJ

The output of `go version` is "go version go1.1.2 darwin/amd64", and I'm on
the latest
Mavericks OS.
Below is a copy of the reproducible code:
```
package main

import (
   "fmt"
   "net/http"
   "time"
)

func handler(w http.ResponseWriter, r *http.Request) {
   interval := 1 * time.Second
   ticker := time.NewTicker(interval)
   go func() {
     for _ = range ticker.C {
       w.Write([]byte("hello"))
       if f, ok := w.(http.Flusher); ok {
         fmt.Println("flush")
         f.Flush()
       }
     }
   }()

   time.Sleep(interval + 100 * time.Millisecond)
}

func startServer() {
   http.HandleFunc("/", handler)
   go func() {
     http.ListenAndServe(":8080", nil)
   }()
}

func main() {
   startServer()
   http.Get("http://localhost:8080/")
   time.Sleep(1 * time.Minute)
}
```

Here's the stack trace:
```

panic: runtime error: invalid memory address or nil pointer dereference

[signal 0xb code=0x1 addr=0x20 pc=0x5391c]


goroutine 10 [running]:

net/http.(*switchWriter).Write(0xc200078790, 0xc2000e9800, 0x5, 0x800, 0x0,
...)

/usr/local/go/src/pkg/net/http/chunked.go:0 +0x5c

bufio.(*Writer).Flush(0xc200095b80, 0xc20009c420, 0xc200000008)

/usr/local/go/src/pkg/bufio/bufio.go:465 +0x14a

net/http.(*response).Flush(0xc2000b3700)

/usr/local/go/src/pkg/net/http/server.go:952 +0x4a

main.func·001()

/tmp/ab.go:17 +0x1e2

created by main.handler

/tmp/ab.go:20 +0xac
```

--
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+unsubscribe@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.

Search Discussions

  • Minux at Nov 1, 2013 at 6:03 pm

    On Nov 1, 2013 1:47 PM, "Fumin Wang" wrote:
    While implementing heartbeats for a long living HTTP connection on the server,
    I encountered a panic raised from the http package itself.
    There isn't anything fancy in the implementation except for the fact that
    the response writer
    is passed to another goroutine. The code can be found in
    http://play.golang.org/p/ElC4PpU-6S .
    It doesn't run directly on the website, but I made sure it ran locally,
    and the panic runtime
    error is pretty reproducible and predictable.

    These two threads suggested that writers not be passed to other
    goroutines, but I'm not
    convinced, since these panics don't occur if
    * We don't write on line 14 `w.Write([]byte("hello"))`
    * or if we don't provide the extra 100ms margin for the Sleep interval on
    line 22 `time.Sleep(interval + 100 * time.Millisecond)`
    >
    https://groups.google.com/forum/#!searchin/golang-nuts/http$20flush/golang-nuts/vzVgBwJ1q2c/jCS_twDIScAJ
    >
    https://groups.google.com/forum/#!searchin/golang-nuts/http$20flush/golang-nuts/FLX9Ok5IepE/ePp3-nrcWFwJ
    The output of `go version` is "go version go1.1.2 darwin/amd64", and I'm
    on the latest
    Mavericks OS.
    Below is a copy of the reproducible code:
    ```
    package main

    import (
    "fmt"
    "net/http"
    "time"
    )

    func handler(w http.ResponseWriter, r *http.Request) {
    interval := 1 * time.Second
    ticker := time.NewTicker(interval)
    go func() {
    for _ = range ticker.C {
    w.Write([]byte("hello"))
    if f, ok := w.(http.Flusher); ok {
    fmt.Println("flush")
    f.Flush()
    }
    }
    }()

    time.Sleep(interval + 100 * time.Millisecond)
    }
    when the handler returned, the goroutine shouldn't do any operation on it
    anymore.
    func startServer() {
    http.HandleFunc("/", handler)
    go func() {
    http.ListenAndServe(":8080", nil)
    }()
    }

    func main() {
    startServer()
    http.Get("http://localhost:8080/")
    time.Sleep(1 * time.Minute)
    }
    ```

    Here's the stack trace:
    ```

    panic: runtime error: invalid memory address or nil pointer dereference

    [signal 0xb code=0x1 addr=0x20 pc=0x5391c]


    goroutine 10 [running]:

    net/http.(*switchWriter).Write(0xc200078790, 0xc2000e9800, 0x5, 0x800, 0x0, ...)
    /usr/local/go/src/pkg/net/http/chunked.go:0 +0x5c

    bufio.(*Writer).Flush(0xc200095b80, 0xc20009c420, 0xc200000008)

    /usr/local/go/src/pkg/bufio/bufio.go:465 +0x14a

    net/http.(*response).Flush(0xc2000b3700)

    /usr/local/go/src/pkg/net/http/server.go:952 +0x4a

    main.func·001()

    /tmp/ab.go:17 +0x1e2

    created by main.handler

    /tmp/ab.go:20 +0xac
    --
    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+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/groups/opt_out.
  • DisposaBoy at Nov 1, 2013 at 6:07 pm
    TL;DR you're returning from the handler... and then writing to the responsewriter. sorry I don't know how else to explain it .

    --
    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+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/groups/opt_out.
  • Fumin Wang at Nov 1, 2013 at 6:13 pm
    Right, thanks for your observations, that resonates with what's being said
    in https://groups.google.com/forum/#!searchin/golang-nuts/http$20flush/golang-nuts/vzVgBwJ1q2c/jCS_twDIScAJ

    I wonder are you able to answer these further questions?
    * Why abruptly panic with a runtime error instead of an error return value
    which is the standard way of reporting errors?
    * Why isn't the error raised in the earlier Write `w.Write([]byte("hello"))`
    but only in the Flush?
    On Saturday, 2 November 2013 02:07:15 UTC+8, DisposaBoy wrote:

    TL;DR you're returning from the handler... and then writing to the
    responsewriter. sorry I don't know how else to explain it .
    --
    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+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/groups/opt_out.
  • Minux at Nov 1, 2013 at 6:16 pm

    On Nov 1, 2013 2:13 PM, "Fumin Wang" wrote:
    Right, thanks for your observations, that resonates with what's being
    said in
    https://groups.google.com/forum/#!searchin/golang-nuts/http$20flush/golang-nuts/vzVgBwJ1q2c/jCS_twDIScAJ
    I wonder are you able to answer these further questions?
    * Why abruptly panic with a runtime error instead of an error return
    value which is the standard way of reporting errors?
    checking that every method call on responsewriter is valid will slow
    everything down.

    besides panic for programmer error is also an idiom for Go.
    * Why isn't the error raised in the earlier Write
    `w.Write([]byte("hello"))` but only in the Flush?
    i'd say this is implementation detail so you'd better read the source code
    to find it out yourself.

    --
    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+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/groups/opt_out.

Related Discussions

Discussion Navigation
viewthread | post
Discussion Overview
groupgolang-nuts @
categoriesgo
postedNov 1, '13 at 5:47p
activeNov 1, '13 at 6:16p
posts5
users3
websitegolang.org

3 users in discussion

Minux: 2 posts Fumin Wang: 2 posts DisposaBoy: 1 post

People

Translate

site design / logo © 2022 Grokbase