Streaming HTTP client get its context cancelled

60 views
Skip to first unread message

Sylvain Vasseur

unread,
Apr 8, 2018, 3:17:49 PM4/8/18
to Go kit
Hello,

I have been using go-kit for building some microservices, one of them should be streaming some data like huge files. Another one is a gateway to the services, so the traffic will go through it too.
Basically I have the following configuration: user <--> gateway <--> service <--> huge file. And I would like to stream the file to the user, without the need to read the whole thing somewhere in any of my services since it could be gigabytes of data.

My gateway connects to the streaming service using the go-kit HTTP client, using BufferedStream(true). I copy the service response body to my gateway response, which is a reader and try to read  from it later when replying to the user.

Here is an example of my server response process that streams a file over the HTTP response

// server response
func encodeResponse(ctx context.Context, w http.ResponseWriter, r interface{}) error {
    w.WriteHeader(http.StatusOK)
    f, err := os.Open("/tmp/10gb-test")
    if err != nil {
        fmt.Println("file not found")
        return err
    }
    defer f.Close()
    _, err := io.Copy(w, f)
    if err != nil {
        fmt.Println("server copy error:", err)
        return err
    }
    return nil
}

And my gateway that get this stream, to streams it too:

type out struct {
    io.ReadCloser
}

// decodeResponse received the respones from the server
func decodeResponse(ctx context.Context, r *http.Response) (interface{}, error) {
    o := out{ReadCloser: r.Body}
    return o, nil
}

// encodeResponse replies to the user
func encodeResponse(ctx context.Context, w http.ResponseWriter, r interface{}) error {
    resp := r.(out)
    defer resp.Close()
    _, err := io.Copy(w, resp)
    if err != nil {
        fmt.Println("gateway copy error:", err)
        return err
    }
    return nil
}

Unfortunately I get an error when running this test and at the end I am not able to get the whole data. Only a small part of the begining.
When digging a bit, I've found that the server get its context cancelled at the end of the gateway Endpoint() process, due to the explicit call to the context cancellation: https://github.com/go-kit/kit/blob/master/transport/http/client.go#L113

I would say that the context should not be cancelled at the end of the endpoint if bufferedStream is true. What do you think of this kind of fix? Would it be wrong? And if yes, what could be an elegant solution to avoid closing the HTTP process before I am able to read the whole response ?

Regards
Sylvain




Reply all
Reply to author
Forward
0 new messages