github.com/xmidt-org/webpa-common@v1.11.9/xhttp/fanout/configuration.go (about)

     1  package fanout
     2  
     3  import (
     4  	"net/http"
     5  	"time"
     6  
     7  	gokithttp "github.com/go-kit/kit/transport/http"
     8  	"github.com/justinas/alice"
     9  	"github.com/xmidt-org/candlelight"
    10  	"github.com/xmidt-org/webpa-common/xhttp"
    11  	"github.com/xmidt-org/webpa-common/xhttp/xcontext"
    12  	"github.com/xmidt-org/webpa-common/xhttp/xtimeout"
    13  	"go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp"
    14  )
    15  
    16  const (
    17  	DefaultFanoutTimeout time.Duration = 45 * time.Second
    18  	DefaultClientTimeout time.Duration = 30 * time.Second
    19  	DefaultConcurrency                 = 1000
    20  )
    21  
    22  // Configuration defines the configuration structure for externally configuring a fanout.
    23  type Configuration struct {
    24  	// Endpoints are the URLs for each endpoint to fan out to.  If unset, the default is supplied
    25  	// by application code, which is normally a set of endpoints driven by service discovery.
    26  	Endpoints []string `json:"endpoints,omitempty"`
    27  
    28  	// Authorization is the Basic Auth token.  There is no default for this field.
    29  	Authorization string `json:"authorization"`
    30  
    31  	// Transport is the http.Client transport
    32  	Transport http.Transport `json:"transport"`
    33  
    34  	// FanoutTimeout is the timeout for the entire fanout operation.  If not supplied, DefaultFanoutTimeout is used.
    35  	FanoutTimeout time.Duration `json:"fanoutTimeout"`
    36  
    37  	// ClientTimeout is the http.Client Timeout.  If not set, DefaultClientTimeout is used.
    38  	ClientTimeout time.Duration `json:"clientTimeout"`
    39  
    40  	// Concurrency is the maximum number of concurrent fanouts allowed.  If this is not set, DefaultConcurrency is used.
    41  	Concurrency int `json:"concurrency"`
    42  
    43  	// MaxRedirects defines the maximum number of redirects each fanout will allow
    44  	MaxRedirects int `json:"maxRedirects"`
    45  
    46  	// RedirectExcludeHeaders are the headers that will *not* be copied on a redirect
    47  	RedirectExcludeHeaders []string `json:"redirectExcludeHeaders,omitempty"`
    48  
    49  	// Tracing contains information to setup OpenTelemetry tracing on the fanout
    50  	// HTTP client.
    51  	Tracing candlelight.Tracing
    52  }
    53  
    54  func (c *Configuration) endpoints() []string {
    55  	if c != nil {
    56  		return c.Endpoints
    57  	}
    58  
    59  	return nil
    60  }
    61  
    62  func (c *Configuration) authorization() string {
    63  	if c != nil && len(c.Authorization) > 0 {
    64  		return c.Authorization
    65  	}
    66  
    67  	return ""
    68  }
    69  
    70  func (c *Configuration) fanoutTimeout() time.Duration {
    71  	if c != nil && c.FanoutTimeout > 0 {
    72  		return c.FanoutTimeout
    73  	}
    74  
    75  	return DefaultFanoutTimeout
    76  }
    77  
    78  func (c *Configuration) clientTimeout() time.Duration {
    79  	if c != nil && c.ClientTimeout > 0 {
    80  		return c.ClientTimeout
    81  	}
    82  
    83  	return DefaultClientTimeout
    84  }
    85  
    86  func (c *Configuration) transport() http.RoundTripper {
    87  	var transport http.RoundTripper = new(http.Transport)
    88  	if c != nil {
    89  		transport = otelhttp.NewTransport(transport,
    90  			otelhttp.WithPropagators(c.Tracing.Propagator()),
    91  			otelhttp.WithTracerProvider(c.Tracing.TracerProvider()),
    92  		)
    93  	}
    94  	return transport
    95  }
    96  
    97  func (c *Configuration) concurrency() int {
    98  	if c != nil && c.Concurrency > 0 {
    99  		return c.Concurrency
   100  	}
   101  
   102  	return DefaultConcurrency
   103  }
   104  
   105  func (c *Configuration) maxRedirects() int {
   106  	if c != nil {
   107  		return c.MaxRedirects
   108  	}
   109  
   110  	return 0
   111  }
   112  
   113  func (c *Configuration) redirectExcludeHeaders() []string {
   114  	if c != nil {
   115  		return c.RedirectExcludeHeaders
   116  	}
   117  
   118  	return nil
   119  }
   120  
   121  func (c *Configuration) checkRedirect() func(*http.Request, []*http.Request) error {
   122  	return xhttp.CheckRedirect(xhttp.RedirectPolicy{
   123  		MaxRedirects:   c.maxRedirects(),
   124  		ExcludeHeaders: c.redirectExcludeHeaders(),
   125  	})
   126  }
   127  
   128  // NewTransactor constructs an HTTP client transaction function from a set of fanout options.
   129  func NewTransactor(c Configuration) func(*http.Request) (*http.Response, error) {
   130  	return (&http.Client{
   131  		Transport:     c.transport(),
   132  		CheckRedirect: c.checkRedirect(),
   133  		Timeout:       c.clientTimeout(),
   134  	}).Do
   135  }
   136  
   137  // NewChain constructs an Alice constructor Chain from a set of fanout options and zero or
   138  // more application-layer request functions.
   139  func NewChain(c Configuration, rf ...gokithttp.RequestFunc) alice.Chain {
   140  	return alice.New(
   141  		xtimeout.NewConstructor(xtimeout.Options{
   142  			Timeout: c.fanoutTimeout(),
   143  		}),
   144  		xcontext.Populate(rf...),
   145  		xhttp.Busy(c.concurrency()),
   146  	)
   147  }