Skip to content

Commit

Permalink
Improve query cancellation handling in tracebyidsharding (#3326)
Browse files Browse the repository at this point in the history
* Improve query cancelation handling in tracebyidsharding

* Move subCancel to only on error condition

* Collapse defer

* Drop status handling
  • Loading branch information
zalegrala authored Feb 20, 2024
1 parent 86ca897 commit 408f099
Show file tree
Hide file tree
Showing 2 changed files with 25 additions and 26 deletions.
49 changes: 24 additions & 25 deletions modules/frontend/tracebyidsharding.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,10 @@ func (s shardQuery) RoundTrip(r *http.Request) (*http.Response, error) {

// context propagation
r = r.WithContext(ctx)
reqs, err := s.buildShardedRequests(r)
subCtx, subCancel := context.WithCancel(ctx)
defer subCancel()

reqs, err := s.buildShardedRequests(subCtx, r)
if err != nil {
return nil, err
}
Expand All @@ -75,14 +78,18 @@ func (s shardQuery) RoundTrip(r *http.Request) (*http.Response, error) {
if s.cfg.ConcurrentShards > 0 {
concurrentShards = uint(s.cfg.ConcurrentShards)
}
wg := boundedwaitgroup.New(concurrentShards)
mtx := sync.Mutex{}

var overallError error
var (
overallError error

mtx = sync.Mutex{}
statusCode = http.StatusNotFound
statusMsg = "trace not found"
wg = boundedwaitgroup.New(concurrentShards)
)

combiner := trace.NewCombiner(s.o.MaxBytesPerTrace(userID))
_, _ = combiner.Consume(&tempopb.Trace{}) // The query path returns a non-nil result even if no inputs (which is different than other paths which return nil for no inputs)
statusCode := http.StatusNotFound
statusMsg := "trace not found"

for _, req := range reqs {
wg.Add(1)
Expand All @@ -97,20 +104,16 @@ func (s shardQuery) RoundTrip(r *http.Request) (*http.Response, error) {
overallError = rtErr
}

if shouldQuit(r.Context(), statusCode, overallError) {
return
}

// check http error
if rtErr != nil {
_ = level.Error(s.logger).Log("msg", "error querying proxy target", "url", innerR.RequestURI, "err", rtErr)
overallError = rtErr
// Check the context of the worker request
if shouldQuit(innerR.Context(), statusCode, overallError) {
return
}

// if the status code is anything but happy, save the error and pass it down the line
// if the status code is anything but happy, save the error and pass it
// down the line
if resp.StatusCode != http.StatusOK && resp.StatusCode != http.StatusNotFound {
// todo: if we cancel the parent context here will it shortcircuit the other queries and fail fast?
defer subCancel()

statusCode = resp.StatusCode
bytesMsg, readErr := io.ReadAll(resp.Body)
if readErr != nil {
Expand All @@ -129,7 +132,7 @@ func (s shardQuery) RoundTrip(r *http.Request) (*http.Response, error) {
}

// marshal into a trace to combine.
// todo: better define responsibilities between middleware. the parent middleware in frontend.go actually sets the header
// TODO: better define responsibilities between middleware. the parent middleware in frontend.go actually sets the header
// which forces the body here to be a proto encoded tempopb.Trace{}
traceResp := &tempopb.TraceByIDResponse{}
rtErr = proto.Unmarshal(buff, traceResp)
Expand Down Expand Up @@ -202,9 +205,8 @@ func (s shardQuery) RoundTrip(r *http.Request) (*http.Response, error) {

// buildShardedRequests returns a slice of requests sharded on the precalculated
// block boundaries
func (s *shardQuery) buildShardedRequests(parent *http.Request) ([]*http.Request, error) {
ctx := parent.Context()
userID, err := user.ExtractOrgID(ctx)
func (s *shardQuery) buildShardedRequests(ctx context.Context, parent *http.Request) ([]*http.Request, error) {
userID, err := user.ExtractOrgID(parent.Context())
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -237,6 +239,7 @@ func shouldQuit(ctx context.Context, statusCode int, err error) bool {
if err != nil {
return true
}

if ctx.Err() != nil {
return true
}
Expand All @@ -245,9 +248,5 @@ func shouldQuit(ctx context.Context, statusCode int, err error) bool {
return true
}

if statusCode/100 == 5 { // bail on any 5xx's
return true
}

return false
return statusCode/100 == 5 // bail on any 5xx's
}
2 changes: 1 addition & 1 deletion modules/frontend/tracebyidsharding_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ func TestBuildShardedRequests(t *testing.T) {
ctx := user.InjectOrgID(context.Background(), "blerg")
req := httptest.NewRequest("GET", "/", nil).WithContext(ctx)

shardedReqs, err := sharder.buildShardedRequests(req)
shardedReqs, err := sharder.buildShardedRequests(ctx, req)
require.NoError(t, err)
require.Len(t, shardedReqs, queryShards)

Expand Down

0 comments on commit 408f099

Please sign in to comment.