Make HTTP timeout configurable

This commit is contained in:
Till Faelligen 2023-09-19 11:48:49 +02:00
parent 3a451cb22f
commit a397b72c30
No known key found for this signature in database
GPG Key ID: ACCDC9606D472758
3 changed files with 71 additions and 46 deletions

View File

@ -42,19 +42,21 @@ const (
EnvSecret = "SYNCV3_SECRET"
// Optional fields
EnvBindAddr = "SYNCV3_BINDADDR"
EnvTLSCert = "SYNCV3_TLS_CERT"
EnvTLSKey = "SYNCV3_TLS_KEY"
EnvPPROF = "SYNCV3_PPROF"
EnvPrometheus = "SYNCV3_PROM"
EnvDebug = "SYNCV3_DEBUG"
EnvOTLP = "SYNCV3_OTLP_URL"
EnvOTLPUsername = "SYNCV3_OTLP_USERNAME"
EnvOTLPPassword = "SYNCV3_OTLP_PASSWORD"
EnvSentryDsn = "SYNCV3_SENTRY_DSN"
EnvLogLevel = "SYNCV3_LOG_LEVEL"
EnvMaxConns = "SYNCV3_MAX_DB_CONN"
EnvIdleTimeoutSecs = "SYNCV3_DB_IDLE_TIMEOUT_SECS"
EnvBindAddr = "SYNCV3_BINDADDR"
EnvTLSCert = "SYNCV3_TLS_CERT"
EnvTLSKey = "SYNCV3_TLS_KEY"
EnvPPROF = "SYNCV3_PPROF"
EnvPrometheus = "SYNCV3_PROM"
EnvDebug = "SYNCV3_DEBUG"
EnvOTLP = "SYNCV3_OTLP_URL"
EnvOTLPUsername = "SYNCV3_OTLP_USERNAME"
EnvOTLPPassword = "SYNCV3_OTLP_PASSWORD"
EnvSentryDsn = "SYNCV3_SENTRY_DSN"
EnvLogLevel = "SYNCV3_LOG_LEVEL"
EnvMaxConns = "SYNCV3_MAX_DB_CONN"
EnvIdleTimeoutSecs = "SYNCV3_DB_IDLE_TIMEOUT_SECS"
EnvHTTPTimeoutSecs = "SYNCV3_HTTP_TIMEOUT_SECS"
EnvHTTPInitialTimeoutSecs = "SYNCV3_HTTP_INITIAL_TIMEOUT_SECS"
)
var helpMsg = fmt.Sprintf(`
@ -74,8 +76,10 @@ Environment var
%s Default: info. The level of verbosity for messages logged. Available values are trace, debug, info, warn, error and fatal
%s Default: unset. Max database connections to use when communicating with postgres. Unset or 0 means no limit.
%s Default: 3600. The maximum amount of time a database connection may be idle, in seconds. 0 means no limit.
%s Default: 300. The timeout in seconds for normal HTTP requests.
%s Default: 1800. The timeout in seconds for initial sync requests.
`, EnvServer, EnvDB, EnvSecret, EnvBindAddr, EnvTLSCert, EnvTLSKey, EnvPPROF, EnvPrometheus, EnvOTLP, EnvOTLPUsername, EnvOTLPPassword,
EnvSentryDsn, EnvLogLevel, EnvMaxConns, EnvIdleTimeoutSecs)
EnvSentryDsn, EnvLogLevel, EnvMaxConns, EnvIdleTimeoutSecs, EnvHTTPTimeoutSecs, EnvHTTPInitialTimeoutSecs)
func defaulting(in, dft string) string {
if in == "" {
@ -96,22 +100,24 @@ func main() {
}
args := map[string]string{
EnvServer: os.Getenv(EnvServer),
EnvDB: os.Getenv(EnvDB),
EnvSecret: os.Getenv(EnvSecret),
EnvBindAddr: defaulting(os.Getenv(EnvBindAddr), "0.0.0.0:8008"),
EnvTLSCert: os.Getenv(EnvTLSCert),
EnvTLSKey: os.Getenv(EnvTLSKey),
EnvPPROF: os.Getenv(EnvPPROF),
EnvPrometheus: os.Getenv(EnvPrometheus),
EnvDebug: os.Getenv(EnvDebug),
EnvOTLP: os.Getenv(EnvOTLP),
EnvOTLPUsername: os.Getenv(EnvOTLPUsername),
EnvOTLPPassword: os.Getenv(EnvOTLPPassword),
EnvSentryDsn: os.Getenv(EnvSentryDsn),
EnvLogLevel: os.Getenv(EnvLogLevel),
EnvMaxConns: defaulting(os.Getenv(EnvMaxConns), "0"),
EnvIdleTimeoutSecs: defaulting(os.Getenv(EnvIdleTimeoutSecs), "3600"),
EnvServer: os.Getenv(EnvServer),
EnvDB: os.Getenv(EnvDB),
EnvSecret: os.Getenv(EnvSecret),
EnvBindAddr: defaulting(os.Getenv(EnvBindAddr), "0.0.0.0:8008"),
EnvTLSCert: os.Getenv(EnvTLSCert),
EnvTLSKey: os.Getenv(EnvTLSKey),
EnvPPROF: os.Getenv(EnvPPROF),
EnvPrometheus: os.Getenv(EnvPrometheus),
EnvDebug: os.Getenv(EnvDebug),
EnvOTLP: os.Getenv(EnvOTLP),
EnvOTLPUsername: os.Getenv(EnvOTLPUsername),
EnvOTLPPassword: os.Getenv(EnvOTLPPassword),
EnvSentryDsn: os.Getenv(EnvSentryDsn),
EnvLogLevel: os.Getenv(EnvLogLevel),
EnvMaxConns: defaulting(os.Getenv(EnvMaxConns), "0"),
EnvIdleTimeoutSecs: defaulting(os.Getenv(EnvIdleTimeoutSecs), "3600"),
EnvHTTPTimeoutSecs: defaulting(os.Getenv(EnvIdleTimeoutSecs), "300"),
EnvHTTPInitialTimeoutSecs: defaulting(os.Getenv(EnvHTTPInitialTimeoutSecs), "1800"),
}
requiredEnvVars := []string{EnvServer, EnvDB, EnvSecret, EnvBindAddr}
for _, requiredEnvVar := range requiredEnvVars {
@ -203,11 +209,21 @@ func main() {
if err != nil {
panic("invalid value for " + EnvIdleTimeoutSecs + ": " + args[EnvIdleTimeoutSecs])
}
httpTimeoutSecs, err := strconv.Atoi(args[EnvHTTPTimeoutSecs])
if err != nil {
panic("invalid value for " + EnvHTTPTimeoutSecs + ": " + args[EnvHTTPTimeoutSecs])
}
httpLongTimeoutSecs, err := strconv.Atoi(args[EnvHTTPInitialTimeoutSecs])
if err != nil {
panic("invalid value for " + EnvHTTPInitialTimeoutSecs + ": " + args[EnvHTTPInitialTimeoutSecs])
}
h2, h3 := syncv3.Setup(args[EnvServer], args[EnvDB], args[EnvSecret], syncv3.Opts{
AddPrometheusMetrics: args[EnvPrometheus] != "",
DBMaxConns: maxConnsInt,
DBConnMaxIdleTime: time.Duration(idleTimeSecs) * time.Second,
MaxTransactionIDDelay: time.Second,
HTTPTimeout: time.Duration(httpTimeoutSecs) * time.Second,
HTTPLongTimeout: time.Duration(httpLongTimeoutSecs) * time.Second,
})
go h2.StartV2Pollers()

View File

@ -4,12 +4,13 @@ import (
"context"
"encoding/json"
"fmt"
"go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp"
"io/ioutil"
"net/http"
"net/url"
"time"
"go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp"
"github.com/tidwall/gjson"
)
@ -30,9 +31,24 @@ type Client interface {
// One client can be shared among many users.
type HTTPClient struct {
Client *http.Client
LongTimeoutClient *http.Client
DestinationServer string
}
func NewHTTPClient(shortTimeout, longTimeout time.Duration, destHomeServer string) *HTTPClient {
return &HTTPClient{
LongTimeoutClient: &http.Client{
Timeout: longTimeout,
Transport: otelhttp.NewTransport(http.DefaultTransport),
},
Client: &http.Client{
Timeout: shortTimeout,
Transport: otelhttp.NewTransport(http.DefaultTransport),
},
DestinationServer: destHomeServer,
}
}
// Return sync2.HTTP401 if this request returns 401
func (v *HTTPClient) WhoAmI(ctx context.Context, accessToken string) (string, string, error) {
req, err := http.NewRequestWithContext(ctx, "GET", v.DestinationServer+"/_matrix/client/r0/account/whoami", nil)
@ -72,11 +88,7 @@ func (v *HTTPClient) DoSyncV2(ctx context.Context, accessToken, since string, is
}
var res *http.Response
if isFirst {
longTimeoutClient := &http.Client{
Timeout: 30 * time.Minute,
Transport: otelhttp.NewTransport(http.DefaultTransport),
}
res, err = longTimeoutClient.Do(req)
res, err = v.LongTimeoutClient.Do(req)
} else {
res, err = v.Client.Do(req)
}

17
v3.go
View File

@ -15,15 +15,13 @@ import (
"github.com/matrix-org/sliding-sync/internal"
"github.com/matrix-org/sliding-sync/pubsub"
"github.com/matrix-org/sliding-sync/state"
_ "github.com/matrix-org/sliding-sync/state/migrations"
"github.com/matrix-org/sliding-sync/sync2"
"github.com/matrix-org/sliding-sync/sync2/handler2"
"github.com/matrix-org/sliding-sync/sync3/handler"
"github.com/pressly/goose/v3"
"github.com/rs/zerolog"
"github.com/rs/zerolog/hlog"
"go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp"
_ "github.com/matrix-org/sliding-sync/state/migrations"
)
//go:embed state/migrations/*
@ -51,6 +49,11 @@ type Opts struct {
DBMaxConns int
DBConnMaxIdleTime time.Duration
// HTTPTimeout is used for "normal" HTTP requests
HTTPTimeout time.Duration
// HTTPLongTimeout is used for initial sync requests
HTTPLongTimeout time.Duration
}
type server struct {
@ -82,13 +85,7 @@ func allowCORS(next http.Handler) http.HandlerFunc {
// Setup the proxy
func Setup(destHomeserver, postgresURI, secret string, opts Opts) (*handler2.Handler, http.Handler) {
// Setup shared DB and HTTP client
v2Client := &sync2.HTTPClient{
Client: &http.Client{
Timeout: 5 * time.Minute,
Transport: otelhttp.NewTransport(http.DefaultTransport),
},
DestinationServer: destHomeserver,
}
v2Client := sync2.NewHTTPClient(opts.HTTPTimeout, opts.HTTPLongTimeout, destHomeserver)
db, err := sqlx.Open("postgres", postgresURI)
if err != nil {
sentry.CaptureException(err)