Skip to content

Commit da23e4a

Browse files
authored
Merge pull request #55 from bookingcom/grzkv/context_cancellation_fix_concurrency_improvement
Fixed context cancellation and timeouts for both zipper and carbonapi
2 parents 4b7f5b8 + dfa25a8 commit da23e4a

File tree

2 files changed

+47
-21
lines changed

2 files changed

+47
-21
lines changed

pkg/backend/net/net.go

Lines changed: 46 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import (
2222
"go.uber.org/zap"
2323
)
2424

25+
// ErrHTTPCode is a custom error type to distinguish HTTP errors
2526
type ErrHTTPCode int
2627

2728
func (e ErrHTTPCode) Error() string {
@@ -145,7 +146,7 @@ func (b Backend) enter(ctx context.Context) error {
145146

146147
select {
147148
case <-ctx.Done():
148-
b.logger.Error("Request context cancelled",
149+
b.logger.Warn("Request context cancelled",
149150
zap.String("host", b.address),
150151
zap.String("uuid", util.GetUUID(ctx)),
151152
zap.Error(ctx.Err()),
@@ -196,33 +197,57 @@ func (b Backend) request(ctx context.Context, u *url.URL, body io.Reader) (*http
196197
return req, nil
197198
}
198199

200+
type requestRes struct {
201+
resp *http.Response
202+
err error
203+
}
204+
199205
func (b Backend) do(ctx context.Context, trace types.Trace, req *http.Request) (string, []byte, error) {
200206
t0 := time.Now()
201-
resp, err := b.client.Do(req)
202-
trace.AddHTTPCall(t0)
203207

204-
var body []byte
205-
var bodyErr error
206-
if resp != nil && resp.Body != nil {
207-
t1 := time.Now()
208-
body, bodyErr = ioutil.ReadAll(resp.Body)
209-
resp.Body.Close()
210-
trace.AddReadBody(t1)
211-
}
208+
ch := make(chan requestRes)
212209

213-
if err != nil {
214-
return "", nil, err
215-
}
210+
go func() {
211+
resp, err := b.client.Do(req)
212+
ch <- requestRes{resp: resp, err: err}
213+
}()
216214

217-
if bodyErr != nil {
218-
return "", nil, bodyErr
219-
}
215+
select {
216+
case res := <-ch:
217+
trace.AddHTTPCall(t0)
218+
219+
var body []byte
220+
var bodyErr error
221+
if res.resp != nil && res.resp.Body != nil {
222+
t1 := time.Now()
223+
body, bodyErr = ioutil.ReadAll(res.resp.Body)
224+
res.resp.Body.Close()
225+
trace.AddReadBody(t1)
226+
}
220227

221-
if resp.StatusCode != http.StatusOK {
222-
return "", body, ErrHTTPCode(resp.StatusCode)
223-
}
228+
// TODO (grzkv): we should not try to interpret the body if there is an error
229+
if res.err != nil {
230+
return "", nil, res.err
231+
}
224232

225-
return resp.Header.Get("Content-Type"), body, nil
233+
if bodyErr != nil {
234+
return "", nil, bodyErr
235+
}
236+
237+
if res.resp.StatusCode != http.StatusOK {
238+
return "", body, ErrHTTPCode(res.resp.StatusCode)
239+
}
240+
241+
return res.resp.Header.Get("Content-Type"), body, nil
242+
243+
case <-ctx.Done():
244+
b.logger.Warn("Request context cancelled",
245+
zap.String("host", b.address),
246+
zap.String("uuid", util.GetUUID(ctx)),
247+
zap.Error(ctx.Err()),
248+
)
249+
return "", nil, ctx.Err()
250+
}
226251
}
227252

228253
// Call makes a call to a backend.

pkg/backend/rpc.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ func Renders(ctx context.Context, backends []Backend, request types.RenderReques
7575
}
7676
}
7777

78+
// TODO (grzkv): This is based on an *assumption* about loggers. Replace by a logger passed from above
7879
if err := checkErrs(ctx, errs, len(backends), backends[0].Logger()); err != nil {
7980
return nil, err
8081
}

0 commit comments

Comments
 (0)