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#L113I 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