github.com/thanos-io/thanos@v0.32.5/internal/cortex/querier/queryrange/util.go (about)

     1  // Copyright (c) The Cortex Authors.
     2  // Licensed under the Apache License 2.0.
     3  
     4  package queryrange
     5  
     6  import (
     7  	"context"
     8  	"net/http"
     9  
    10  	"github.com/weaveworks/common/httpgrpc"
    11  
    12  	"github.com/thanos-io/thanos/internal/cortex/tenant"
    13  	"github.com/thanos-io/thanos/internal/cortex/util/validation"
    14  )
    15  
    16  // RequestResponse contains a request response and the respective request that was used.
    17  type RequestResponse struct {
    18  	Request  Request
    19  	Response Response
    20  }
    21  
    22  // DoRequests executes a list of requests in parallel. The limits parameters is used to limit parallelism per single request.
    23  func DoRequests(ctx context.Context, downstream Handler, reqs []Request, limits Limits) ([]RequestResponse, error) {
    24  	tenantIDs, err := tenant.TenantIDs(ctx)
    25  	if err != nil {
    26  		return nil, httpgrpc.Errorf(http.StatusBadRequest, err.Error())
    27  	}
    28  
    29  	// If one of the requests fail, we want to be able to cancel the rest of them.
    30  	ctx, cancel := context.WithCancel(ctx)
    31  	defer cancel()
    32  
    33  	// Feed all requests to a bounded intermediate channel to limit parallelism.
    34  	intermediate := make(chan Request)
    35  	go func() {
    36  		for _, req := range reqs {
    37  			intermediate <- req
    38  		}
    39  		close(intermediate)
    40  	}()
    41  
    42  	respChan, errChan := make(chan RequestResponse), make(chan error)
    43  	parallelism := validation.SmallestPositiveIntPerTenant(tenantIDs, limits.MaxQueryParallelism)
    44  	if parallelism > len(reqs) {
    45  		parallelism = len(reqs)
    46  	}
    47  	for i := 0; i < parallelism; i++ {
    48  		go func() {
    49  			for req := range intermediate {
    50  				resp, err := downstream.Do(ctx, req)
    51  				if err != nil {
    52  					errChan <- err
    53  				} else {
    54  					respChan <- RequestResponse{req, resp}
    55  				}
    56  			}
    57  		}()
    58  	}
    59  
    60  	resps := make([]RequestResponse, 0, len(reqs))
    61  	var firstErr error
    62  	for range reqs {
    63  		select {
    64  		case resp := <-respChan:
    65  			resps = append(resps, resp)
    66  		case err := <-errChan:
    67  			if firstErr == nil {
    68  				cancel()
    69  				firstErr = err
    70  			}
    71  		}
    72  	}
    73  
    74  	return resps, firstErr
    75  }