Commit c8a45af3 authored by Igor Drozdov's avatar Igor Drozdov

Deduplicate http transport creation

We use a very tweaked transport to perform http calls

Let's extract it into a helper function to deduplicate code

Changelog: changed
parent 0c9dbf79
...@@ -4,37 +4,17 @@ import ( ...@@ -4,37 +4,17 @@ import (
"context" "context"
"fmt" "fmt"
"io" "io"
"net"
"net/http" "net/http"
"time"
"gitlab.com/gitlab-org/labkit/correlation"
"gitlab.com/gitlab-org/labkit/log" "gitlab.com/gitlab-org/labkit/log"
"gitlab.com/gitlab-org/labkit/tracing"
"gitlab.com/gitlab-org/gitlab/workhorse/internal/helper" "gitlab.com/gitlab-org/gitlab/workhorse/internal/helper"
"gitlab.com/gitlab-org/gitlab/workhorse/internal/helper/httptransport"
"gitlab.com/gitlab-org/gitlab/workhorse/internal/senddata" "gitlab.com/gitlab-org/gitlab/workhorse/internal/senddata"
) )
// httpTransport defines a http.Transport with values
// that are more restrictive than for http.DefaultTransport,
// they define shorter TLS Handshake, and more aggressive connection closing
// to prevent the connection hanging and reduce FD usage
var httpTransport = tracing.NewRoundTripper(correlation.NewInstrumentedRoundTripper(&http.Transport{
Proxy: http.ProxyFromEnvironment,
DialContext: (&net.Dialer{
Timeout: 30 * time.Second,
KeepAlive: 10 * time.Second,
}).DialContext,
MaxIdleConns: 2,
IdleConnTimeout: 30 * time.Second,
TLSHandshakeTimeout: 10 * time.Second,
ExpectContinueTimeout: 10 * time.Second,
ResponseHeaderTimeout: 30 * time.Second,
}))
var httpClient = &http.Client{ var httpClient = &http.Client{
Transport: httpTransport, Transport: httptransport.New(),
} }
type Injector struct { type Injector struct {
......
package httptransport
import (
"net/http"
"time"
"gitlab.com/gitlab-org/labkit/correlation"
"gitlab.com/gitlab-org/labkit/tracing"
)
type Option func(*http.Transport)
// Defines a http.Transport with values
// that are more restrictive than for http.DefaultTransport,
// they define shorter TLS Handshake, and more aggressive connection closing
// to prevent the connection hanging and reduce FD usage
func New(options ...Option) http.RoundTripper {
t := http.DefaultTransport.(*http.Transport).Clone()
// To avoid keep around TCP connections to http servers we're done with
t.MaxIdleConns = 2
// A stricter timeout for fetching from external sources that can be slow
t.ResponseHeaderTimeout = 30 * time.Second
for _, option := range options {
option(t)
}
return tracing.NewRoundTripper(correlation.NewInstrumentedRoundTripper(t))
}
func WithDisabledCompression() Option {
return func(t *http.Transport) {
t.DisableCompression = true
}
}
...@@ -5,7 +5,6 @@ import ( ...@@ -5,7 +5,6 @@ import (
"context" "context"
"fmt" "fmt"
"io" "io"
"net"
"net/http" "net/http"
"os" "os"
"os/exec" "os/exec"
...@@ -18,11 +17,11 @@ import ( ...@@ -18,11 +17,11 @@ import (
"github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promauto" "github.com/prometheus/client_golang/prometheus/promauto"
"gitlab.com/gitlab-org/labkit/correlation"
"gitlab.com/gitlab-org/labkit/tracing" "gitlab.com/gitlab-org/labkit/tracing"
"gitlab.com/gitlab-org/gitlab/workhorse/internal/config" "gitlab.com/gitlab-org/gitlab/workhorse/internal/config"
"gitlab.com/gitlab-org/gitlab/workhorse/internal/helper" "gitlab.com/gitlab-org/gitlab/workhorse/internal/helper"
"gitlab.com/gitlab-org/gitlab/workhorse/internal/helper/httptransport"
"gitlab.com/gitlab-org/gitlab/workhorse/internal/log" "gitlab.com/gitlab-org/gitlab/workhorse/internal/log"
"gitlab.com/gitlab-org/gitlab/workhorse/internal/senddata" "gitlab.com/gitlab-org/gitlab/workhorse/internal/senddata"
) )
...@@ -69,23 +68,8 @@ const ( ...@@ -69,23 +68,8 @@ const (
var envInjector = tracing.NewEnvInjector() var envInjector = tracing.NewEnvInjector()
// Images might be located remotely in object storage, in which case we need to stream
// it via http(s)
var httpTransport = tracing.NewRoundTripper(correlation.NewInstrumentedRoundTripper(&http.Transport{
Proxy: http.ProxyFromEnvironment,
DialContext: (&net.Dialer{
Timeout: 30 * time.Second,
KeepAlive: 10 * time.Second,
}).DialContext,
MaxIdleConns: 2,
IdleConnTimeout: 30 * time.Second,
TLSHandshakeTimeout: 10 * time.Second,
ExpectContinueTimeout: 10 * time.Second,
ResponseHeaderTimeout: 30 * time.Second,
}))
var httpClient = &http.Client{ var httpClient = &http.Client{
Transport: httpTransport, Transport: httptransport.New(),
} }
const ( const (
......
...@@ -5,34 +5,15 @@ import ( ...@@ -5,34 +5,15 @@ import (
"fmt" "fmt"
"io" "io"
"io/ioutil" "io/ioutil"
"net"
"net/http" "net/http"
"time"
"gitlab.com/gitlab-org/labkit/correlation"
"gitlab.com/gitlab-org/labkit/mask" "gitlab.com/gitlab-org/labkit/mask"
"gitlab.com/gitlab-org/labkit/tracing"
)
// httpTransport defines a http.Transport with values "gitlab.com/gitlab-org/gitlab/workhorse/internal/helper/httptransport"
// that are more restrictive than for http.DefaultTransport, )
// they define shorter TLS Handshake, and more aggressive connection closing
// to prevent the connection hanging and reduce FD usage
var httpTransport = tracing.NewRoundTripper(correlation.NewInstrumentedRoundTripper(&http.Transport{
Proxy: http.ProxyFromEnvironment,
DialContext: (&net.Dialer{
Timeout: 30 * time.Second,
KeepAlive: 10 * time.Second,
}).DialContext,
MaxIdleConns: 2,
IdleConnTimeout: 30 * time.Second,
TLSHandshakeTimeout: 10 * time.Second,
ExpectContinueTimeout: 10 * time.Second,
ResponseHeaderTimeout: 30 * time.Second,
}))
var httpClient = &http.Client{ var httpClient = &http.Client{
Transport: httpTransport, Transport: httptransport.New(),
} }
// Object represents an object on a S3 compatible Object Store service. // Object represents an object on a S3 compatible Object Store service.
......
...@@ -3,18 +3,15 @@ package sendurl ...@@ -3,18 +3,15 @@ package sendurl
import ( import (
"fmt" "fmt"
"io" "io"
"net"
"net/http" "net/http"
"time"
"github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promauto" "github.com/prometheus/client_golang/prometheus/promauto"
"gitlab.com/gitlab-org/labkit/correlation"
"gitlab.com/gitlab-org/labkit/mask" "gitlab.com/gitlab-org/labkit/mask"
"gitlab.com/gitlab-org/labkit/tracing"
"gitlab.com/gitlab-org/gitlab/workhorse/internal/helper" "gitlab.com/gitlab-org/gitlab/workhorse/internal/helper"
"gitlab.com/gitlab-org/gitlab/workhorse/internal/helper/httptransport"
"gitlab.com/gitlab-org/gitlab/workhorse/internal/log" "gitlab.com/gitlab-org/gitlab/workhorse/internal/log"
"gitlab.com/gitlab-org/gitlab/workhorse/internal/senddata" "gitlab.com/gitlab-org/gitlab/workhorse/internal/senddata"
) )
...@@ -47,22 +44,7 @@ var preserveHeaderKeys = map[string]bool{ ...@@ -47,22 +44,7 @@ var preserveHeaderKeys = map[string]bool{
"Pragma": true, // Support for HTTP 1.0 proxies "Pragma": true, // Support for HTTP 1.0 proxies
} }
// httpTransport defines a http.Transport with values var httpTransport = httptransport.New()
// that are more restrictive than for http.DefaultTransport,
// they define shorter TLS Handshake, and more aggressive connection closing
// to prevent the connection hanging and reduce FD usage
var httpTransport = tracing.NewRoundTripper(correlation.NewInstrumentedRoundTripper(&http.Transport{
Proxy: http.ProxyFromEnvironment,
DialContext: (&net.Dialer{
Timeout: 30 * time.Second,
KeepAlive: 10 * time.Second,
}).DialContext,
MaxIdleConns: 2,
IdleConnTimeout: 30 * time.Second,
TLSHandshakeTimeout: 10 * time.Second,
ExpectContinueTimeout: 10 * time.Second,
ResponseHeaderTimeout: 30 * time.Second,
}))
var httpClient = &http.Client{ var httpClient = &http.Client{
Transport: httpTransport, Transport: httpTransport,
......
...@@ -32,19 +32,23 @@ func NewBackendRoundTripper(backend *url.URL, socket string, proxyHeadersTimeout ...@@ -32,19 +32,23 @@ func NewBackendRoundTripper(backend *url.URL, socket string, proxyHeadersTimeout
} }
func newBackendRoundTripper(backend *url.URL, socket string, proxyHeadersTimeout time.Duration, developmentMode bool, tlsConf *tls.Config) http.RoundTripper { func newBackendRoundTripper(backend *url.URL, socket string, proxyHeadersTimeout time.Duration, developmentMode bool, tlsConf *tls.Config) http.RoundTripper {
// Copied from the definition of http.DefaultTransport. We can't literally copy http.DefaultTransport because of its hidden internal state. transport := http.DefaultTransport.(*http.Transport).Clone()
transport, dialer := newBackendTransport()
transport.ResponseHeaderTimeout = proxyHeadersTimeout transport.ResponseHeaderTimeout = proxyHeadersTimeout
transport.TLSClientConfig = tlsConf transport.TLSClientConfig = tlsConf
// Puma does not support http/2, there's no point in reconnecting
transport.ForceAttemptHTTP2 = false
dial := transport.DialContext
if backend != nil && socket == "" { if backend != nil && socket == "" {
address := mustParseAddress(backend.Host, backend.Scheme) address := mustParseAddress(backend.Host, backend.Scheme)
transport.DialContext = func(ctx context.Context, network, addr string) (net.Conn, error) { transport.DialContext = func(ctx context.Context, network, addr string) (net.Conn, error) {
return dialer.DialContext(ctx, "tcp", address) return dial(ctx, "tcp", address)
} }
} else if socket != "" { } else if socket != "" {
transport.DialContext = func(ctx context.Context, network, addr string) (net.Conn, error) { transport.DialContext = func(ctx context.Context, network, addr string) (net.Conn, error) {
return dialer.DialContext(ctx, "unix", socket) return dial(ctx, "unix", socket)
} }
} else { } else {
panic("backend is nil and socket is empty") panic("backend is nil and socket is empty")
......
package roundtripper
import (
"net"
"net/http"
"time"
)
// newBackendTransport setups the default HTTP transport which Workhorse uses
// to communicate with the upstream
func newBackendTransport() (*http.Transport, *net.Dialer) {
dialler := &net.Dialer{
Timeout: 30 * time.Second,
KeepAlive: 30 * time.Second,
}
transport := &http.Transport{
Proxy: http.ProxyFromEnvironment,
DialContext: dialler.DialContext,
MaxIdleConns: 100,
IdleConnTimeout: 90 * time.Second,
TLSHandshakeTimeout: 10 * time.Second,
ExpectContinueTimeout: 1 * time.Second,
}
return transport, dialler
}
...@@ -5,32 +5,20 @@ import ( ...@@ -5,32 +5,20 @@ import (
"context" "context"
"fmt" "fmt"
"io" "io"
"net"
"net/http" "net/http"
"os" "os"
"strings" "strings"
"time"
"gitlab.com/gitlab-org/gitlab/workhorse/internal/helper/httptransport"
"gitlab.com/gitlab-org/gitlab/workhorse/internal/httprs" "gitlab.com/gitlab-org/gitlab/workhorse/internal/httprs"
"gitlab.com/gitlab-org/labkit/correlation"
"gitlab.com/gitlab-org/labkit/mask" "gitlab.com/gitlab-org/labkit/mask"
"gitlab.com/gitlab-org/labkit/tracing"
) )
var httpClient = &http.Client{ var httpClient = &http.Client{
Transport: tracing.NewRoundTripper(correlation.NewInstrumentedRoundTripper(&http.Transport{ Transport: httptransport.New(
Proxy: http.ProxyFromEnvironment, httptransport.WithDisabledCompression(), // To avoid bugs when serving compressed files from object storage
DialContext: (&net.Dialer{ ),
Timeout: 30 * time.Second,
KeepAlive: 10 * time.Second,
}).DialContext,
IdleConnTimeout: 30 * time.Second,
TLSHandshakeTimeout: 10 * time.Second,
ExpectContinueTimeout: 10 * time.Second,
ResponseHeaderTimeout: 30 * time.Second,
DisableCompression: true,
})),
} }
type archive struct { type archive struct {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment