mirror of
https://github.com/superseriousbusiness/gotosocial.git
synced 2024-11-01 06:50:00 +00:00
[performance] remove throttling timers (#1466)
* remove throttling timers, support setting retry-after, use retry-after in transport * remove unused variables * add throttling-retry-after to cmd flags * update envparsing to include new throttling-retry-after * update example config to include retry-after documentation * also support retry-after formatted as date-time, ensure max backoff time --------- Signed-off-by: kim <grufwub@gmail.com>
This commit is contained in:
parent
6ac1dda96f
commit
70739d32cc
8 changed files with 98 additions and 62 deletions
|
@ -203,10 +203,11 @@
|
||||||
|
|
||||||
// throttling
|
// throttling
|
||||||
cpuMultiplier := config.GetAdvancedThrottlingMultiplier()
|
cpuMultiplier := config.GetAdvancedThrottlingMultiplier()
|
||||||
clThrottle := middleware.Throttle(cpuMultiplier) // client api
|
retryAfter := config.GetAdvancedThrottlingRetryAfter()
|
||||||
s2sThrottle := middleware.Throttle(cpuMultiplier) // server-to-server (AP)
|
clThrottle := middleware.Throttle(cpuMultiplier, retryAfter) // client api
|
||||||
fsThrottle := middleware.Throttle(cpuMultiplier) // fileserver / web templates
|
s2sThrottle := middleware.Throttle(cpuMultiplier, retryAfter) // server-to-server (AP)
|
||||||
pkThrottle := middleware.Throttle(cpuMultiplier) // throttle public key endpoint separately
|
fsThrottle := middleware.Throttle(cpuMultiplier, retryAfter) // fileserver / web templates
|
||||||
|
pkThrottle := middleware.Throttle(cpuMultiplier, retryAfter) // throttle public key endpoint separately
|
||||||
|
|
||||||
gzip := middleware.Gzip() // applied to all except fileserver
|
gzip := middleware.Gzip() // applied to all except fileserver
|
||||||
|
|
||||||
|
|
|
@ -760,3 +760,10 @@ advanced-rate-limit-requests: 300
|
||||||
# Examples: [8, 4, 9, 0]
|
# Examples: [8, 4, 9, 0]
|
||||||
# Default: 8
|
# Default: 8
|
||||||
advanced-throttling-multiplier: 8
|
advanced-throttling-multiplier: 8
|
||||||
|
|
||||||
|
# Duration. Time period to use as the "retry-after" header value in response to throttled requests.
|
||||||
|
# Minimum resolution is 1 second.
|
||||||
|
#
|
||||||
|
# Examples: [30s, 10s, 5s, 1m]
|
||||||
|
# Default: 30s
|
||||||
|
advanced-throttling-retry-after: "30s"
|
|
@ -136,6 +136,7 @@ type Configuration struct {
|
||||||
AdvancedCookiesSamesite string `name:"advanced-cookies-samesite" usage:"'strict' or 'lax', see https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie/SameSite"`
|
AdvancedCookiesSamesite string `name:"advanced-cookies-samesite" usage:"'strict' or 'lax', see https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie/SameSite"`
|
||||||
AdvancedRateLimitRequests int `name:"advanced-rate-limit-requests" usage:"Amount of HTTP requests to permit within a 5 minute window. 0 or less turns rate limiting off."`
|
AdvancedRateLimitRequests int `name:"advanced-rate-limit-requests" usage:"Amount of HTTP requests to permit within a 5 minute window. 0 or less turns rate limiting off."`
|
||||||
AdvancedThrottlingMultiplier int `name:"advanced-throttling-multiplier" usage:"Multiplier to use per cpu for http request throttling. 0 or less turns throttling off."`
|
AdvancedThrottlingMultiplier int `name:"advanced-throttling-multiplier" usage:"Multiplier to use per cpu for http request throttling. 0 or less turns throttling off."`
|
||||||
|
AdvancedThrottlingRetryAfter time.Duration `name:"advanced-throttling-retry-after" usage:"Retry-After duration response to send for throttled requests."`
|
||||||
|
|
||||||
// Cache configuration vars.
|
// Cache configuration vars.
|
||||||
Cache CacheConfiguration `name:"cache"`
|
Cache CacheConfiguration `name:"cache"`
|
||||||
|
|
|
@ -139,6 +139,7 @@ func (s *ConfigState) AddServerFlags(cmd *cobra.Command) {
|
||||||
cmd.Flags().String(AdvancedCookiesSamesiteFlag(), cfg.AdvancedCookiesSamesite, fieldtag("AdvancedCookiesSamesite", "usage"))
|
cmd.Flags().String(AdvancedCookiesSamesiteFlag(), cfg.AdvancedCookiesSamesite, fieldtag("AdvancedCookiesSamesite", "usage"))
|
||||||
cmd.Flags().Int(AdvancedRateLimitRequestsFlag(), cfg.AdvancedRateLimitRequests, fieldtag("AdvancedRateLimitRequests", "usage"))
|
cmd.Flags().Int(AdvancedRateLimitRequestsFlag(), cfg.AdvancedRateLimitRequests, fieldtag("AdvancedRateLimitRequests", "usage"))
|
||||||
cmd.Flags().Int(AdvancedThrottlingMultiplierFlag(), cfg.AdvancedThrottlingMultiplier, fieldtag("AdvancedThrottlingMultiplier", "usage"))
|
cmd.Flags().Int(AdvancedThrottlingMultiplierFlag(), cfg.AdvancedThrottlingMultiplier, fieldtag("AdvancedThrottlingMultiplier", "usage"))
|
||||||
|
cmd.Flags().Duration(AdvancedThrottlingRetryAfterFlag(), cfg.AdvancedThrottlingRetryAfter, fieldtag("AdvancedThrottlingRetryAfter", "usage"))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1999,6 +1999,31 @@ func GetAdvancedThrottlingMultiplier() int { return global.GetAdvancedThrottling
|
||||||
// SetAdvancedThrottlingMultiplier safely sets the value for global configuration 'AdvancedThrottlingMultiplier' field
|
// SetAdvancedThrottlingMultiplier safely sets the value for global configuration 'AdvancedThrottlingMultiplier' field
|
||||||
func SetAdvancedThrottlingMultiplier(v int) { global.SetAdvancedThrottlingMultiplier(v) }
|
func SetAdvancedThrottlingMultiplier(v int) { global.SetAdvancedThrottlingMultiplier(v) }
|
||||||
|
|
||||||
|
// GetAdvancedThrottlingRetryAfter safely fetches the Configuration value for state's 'AdvancedThrottlingRetryAfter' field
|
||||||
|
func (st *ConfigState) GetAdvancedThrottlingRetryAfter() (v time.Duration) {
|
||||||
|
st.mutex.Lock()
|
||||||
|
v = st.config.AdvancedThrottlingRetryAfter
|
||||||
|
st.mutex.Unlock()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetAdvancedThrottlingRetryAfter safely sets the Configuration value for state's 'AdvancedThrottlingRetryAfter' field
|
||||||
|
func (st *ConfigState) SetAdvancedThrottlingRetryAfter(v time.Duration) {
|
||||||
|
st.mutex.Lock()
|
||||||
|
defer st.mutex.Unlock()
|
||||||
|
st.config.AdvancedThrottlingRetryAfter = v
|
||||||
|
st.reloadToViper()
|
||||||
|
}
|
||||||
|
|
||||||
|
// AdvancedThrottlingRetryAfterFlag returns the flag name for the 'AdvancedThrottlingRetryAfter' field
|
||||||
|
func AdvancedThrottlingRetryAfterFlag() string { return "advanced-throttling-retry-after" }
|
||||||
|
|
||||||
|
// GetAdvancedThrottlingRetryAfter safely fetches the value for global configuration 'AdvancedThrottlingRetryAfter' field
|
||||||
|
func GetAdvancedThrottlingRetryAfter() time.Duration { return global.GetAdvancedThrottlingRetryAfter() }
|
||||||
|
|
||||||
|
// SetAdvancedThrottlingRetryAfter safely sets the value for global configuration 'AdvancedThrottlingRetryAfter' field
|
||||||
|
func SetAdvancedThrottlingRetryAfter(v time.Duration) { global.SetAdvancedThrottlingRetryAfter(v) }
|
||||||
|
|
||||||
// GetCacheGTSAccountMaxSize safely fetches the Configuration value for state's 'Cache.GTS.AccountMaxSize' field
|
// GetCacheGTSAccountMaxSize safely fetches the Configuration value for state's 'Cache.GTS.AccountMaxSize' field
|
||||||
func (st *ConfigState) GetCacheGTSAccountMaxSize() (v int) {
|
func (st *ConfigState) GetCacheGTSAccountMaxSize() (v int) {
|
||||||
st.mutex.Lock()
|
st.mutex.Lock()
|
||||||
|
|
|
@ -29,17 +29,12 @@
|
||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
"runtime"
|
"runtime"
|
||||||
|
"strconv"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
|
||||||
errCapacityExceeded = "server capacity exceeded"
|
|
||||||
errTimedOut = "timed out while waiting for a pending request to complete"
|
|
||||||
errContextCanceled = "context canceled"
|
|
||||||
)
|
|
||||||
|
|
||||||
// token represents a request that is being processed.
|
// token represents a request that is being processed.
|
||||||
type token struct{}
|
type token struct{}
|
||||||
|
|
||||||
|
@ -73,11 +68,13 @@ type token struct{
|
||||||
//
|
//
|
||||||
// If the multiplier is <= 0, a noop middleware will be returned instead.
|
// If the multiplier is <= 0, a noop middleware will be returned instead.
|
||||||
//
|
//
|
||||||
|
// RetryAfter determines the Retry-After header value to be sent to throttled requests.
|
||||||
|
//
|
||||||
// Useful links:
|
// Useful links:
|
||||||
//
|
//
|
||||||
// - https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Retry-After
|
// - https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Retry-After
|
||||||
// - https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/503
|
// - https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/503
|
||||||
func Throttle(cpuMultiplier int) gin.HandlerFunc {
|
func Throttle(cpuMultiplier int, retryAfter time.Duration) gin.HandlerFunc {
|
||||||
if cpuMultiplier <= 0 {
|
if cpuMultiplier <= 0 {
|
||||||
// throttling is disabled, return a noop middleware
|
// throttling is disabled, return a noop middleware
|
||||||
return func(c *gin.Context) {}
|
return func(c *gin.Context) {}
|
||||||
|
@ -89,36 +86,24 @@ func Throttle(cpuMultiplier int) gin.HandlerFunc {
|
||||||
backlogChannelSize = limit + backlogLimit
|
backlogChannelSize = limit + backlogLimit
|
||||||
tokens = make(chan token, limit)
|
tokens = make(chan token, limit)
|
||||||
backlogTokens = make(chan token, backlogChannelSize)
|
backlogTokens = make(chan token, backlogChannelSize)
|
||||||
retryAfter = "30" // seconds
|
retryAfterStr = strconv.FormatUint(uint64(retryAfter/time.Second), 10)
|
||||||
backlogDuration = 30 * time.Second
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// prefill token channels
|
// prefill token channels
|
||||||
for i := 0; i < limit; i++ {
|
for i := 0; i < limit; i++ {
|
||||||
tokens <- token{}
|
tokens <- token{}
|
||||||
}
|
}
|
||||||
|
|
||||||
for i := 0; i < backlogChannelSize; i++ {
|
for i := 0; i < backlogChannelSize; i++ {
|
||||||
backlogTokens <- token{}
|
backlogTokens <- token{}
|
||||||
}
|
}
|
||||||
|
|
||||||
// bail instructs the requester to return after retryAfter seconds, returns a 503,
|
|
||||||
// and writes the given message into the "error" field of a returned json object
|
|
||||||
bail := func(c *gin.Context, msg string) {
|
|
||||||
c.Header("Retry-After", retryAfter)
|
|
||||||
c.JSON(http.StatusServiceUnavailable, gin.H{"error": msg})
|
|
||||||
c.Abort()
|
|
||||||
}
|
|
||||||
|
|
||||||
return func(c *gin.Context) {
|
return func(c *gin.Context) {
|
||||||
// inside this select, the caller tries to get a backlog token
|
// inside this select, the caller tries to get a backlog token
|
||||||
select {
|
select {
|
||||||
case <-c.Request.Context().Done():
|
case <-c.Request.Context().Done():
|
||||||
// request context has been canceled already
|
// request context has been canceled already
|
||||||
bail(c, errContextCanceled)
|
return
|
||||||
case btok := <-backlogTokens:
|
case btok := <-backlogTokens:
|
||||||
// take a backlog token and wait
|
|
||||||
timer := time.NewTimer(backlogDuration)
|
|
||||||
defer func() {
|
defer func() {
|
||||||
// when we're finished, return the backlog token to the bucket
|
// when we're finished, return the backlog token to the bucket
|
||||||
backlogTokens <- btok
|
backlogTokens <- btok
|
||||||
|
@ -127,16 +112,11 @@ func Throttle(cpuMultiplier int) gin.HandlerFunc {
|
||||||
// inside *this* select, the caller has a backlog token,
|
// inside *this* select, the caller has a backlog token,
|
||||||
// and they're waiting for their turn to be processed
|
// and they're waiting for their turn to be processed
|
||||||
select {
|
select {
|
||||||
case <-timer.C:
|
|
||||||
// waiting too long in the backlog
|
|
||||||
bail(c, errTimedOut)
|
|
||||||
case <-c.Request.Context().Done():
|
case <-c.Request.Context().Done():
|
||||||
// the request context has been canceled already
|
// the request context has been canceled already
|
||||||
timer.Stop()
|
return
|
||||||
bail(c, errContextCanceled)
|
|
||||||
case tok := <-tokens:
|
case tok := <-tokens:
|
||||||
// the caller gets a token, so their request can now be processed
|
// the caller gets a token, so their request can now be processed
|
||||||
timer.Stop()
|
|
||||||
defer func() {
|
defer func() {
|
||||||
// whatever happens to the request, put the
|
// whatever happens to the request, put the
|
||||||
// token back in the bucket when we're finished
|
// token back in the bucket when we're finished
|
||||||
|
@ -147,7 +127,9 @@ func Throttle(cpuMultiplier int) gin.HandlerFunc {
|
||||||
|
|
||||||
default:
|
default:
|
||||||
// we don't have space in the backlog queue
|
// we don't have space in the backlog queue
|
||||||
bail(c, errCapacityExceeded)
|
c.Header("Retry-After", retryAfterStr)
|
||||||
|
c.JSON(http.StatusTooManyRequests, gin.H{"error": "server capacity exceeded"})
|
||||||
|
c.Abort()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,6 +27,7 @@
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
@ -84,35 +85,36 @@ type transport struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// GET will perform given http request using transport client, retrying on certain preset errors, or if status code is among retryOn.
|
// GET will perform given http request using transport client, retrying on certain preset errors, or if status code is among retryOn.
|
||||||
func (t *transport) GET(r *http.Request, retryOn ...int) (*http.Response, error) {
|
func (t *transport) GET(r *http.Request) (*http.Response, error) {
|
||||||
if r.Method != http.MethodGet {
|
if r.Method != http.MethodGet {
|
||||||
return nil, errors.New("must be GET request")
|
return nil, errors.New("must be GET request")
|
||||||
}
|
}
|
||||||
return t.do(r, func(r *http.Request) error {
|
return t.do(r, func(r *http.Request) error {
|
||||||
return t.signGET(r)
|
return t.signGET(r)
|
||||||
}, retryOn...)
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// POST will perform given http request using transport client, retrying on certain preset errors, or if status code is among retryOn.
|
// POST will perform given http request using transport client, retrying on certain preset errors, or if status code is among retryOn.
|
||||||
func (t *transport) POST(r *http.Request, body []byte, retryOn ...int) (*http.Response, error) {
|
func (t *transport) POST(r *http.Request, body []byte) (*http.Response, error) {
|
||||||
if r.Method != http.MethodPost {
|
if r.Method != http.MethodPost {
|
||||||
return nil, errors.New("must be POST request")
|
return nil, errors.New("must be POST request")
|
||||||
}
|
}
|
||||||
return t.do(r, func(r *http.Request) error {
|
return t.do(r, func(r *http.Request) error {
|
||||||
return t.signPOST(r, body)
|
return t.signPOST(r, body)
|
||||||
}, retryOn...)
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *transport) do(r *http.Request, signer func(*http.Request) error, retryOn ...int) (*http.Response, error) {
|
func (t *transport) do(r *http.Request, signer func(*http.Request) error) (*http.Response, error) {
|
||||||
const maxRetries = 5
|
const (
|
||||||
|
// max no. attempts
|
||||||
|
maxRetries = 5
|
||||||
|
|
||||||
var (
|
// starting backoff duration.
|
||||||
// Initial backoff duration
|
baseBackoff = 2 * time.Second
|
||||||
backoff = 2 * time.Second
|
)
|
||||||
|
|
||||||
// Get request hostname
|
// Get request hostname
|
||||||
host = r.URL.Hostname()
|
host := r.URL.Hostname()
|
||||||
)
|
|
||||||
|
|
||||||
// Check if recently reached max retries for this host
|
// Check if recently reached max retries for this host
|
||||||
// so we don't need to bother reattempting it. The only
|
// so we don't need to bother reattempting it. The only
|
||||||
|
@ -137,6 +139,8 @@ func (t *transport) do(r *http.Request, signer func(*http.Request) error, retryO
|
||||||
r.Header.Set("User-Agent", t.controller.userAgent)
|
r.Header.Set("User-Agent", t.controller.userAgent)
|
||||||
|
|
||||||
for i := 0; i < maxRetries; i++ {
|
for i := 0; i < maxRetries; i++ {
|
||||||
|
var backoff time.Duration
|
||||||
|
|
||||||
// Reset signing header fields
|
// Reset signing header fields
|
||||||
now := t.controller.clock.Now().UTC()
|
now := t.controller.clock.Now().UTC()
|
||||||
r.Header.Set("Date", now.Format("Mon, 02 Jan 2006 15:04:05")+" GMT")
|
r.Header.Set("Date", now.Format("Mon, 02 Jan 2006 15:04:05")+" GMT")
|
||||||
|
@ -152,18 +156,35 @@ func (t *transport) do(r *http.Request, signer func(*http.Request) error, retryO
|
||||||
|
|
||||||
// Attempt to perform request
|
// Attempt to perform request
|
||||||
rsp, err := t.controller.client.Do(r)
|
rsp, err := t.controller.client.Do(r)
|
||||||
if err == nil { //nolint shutup linter
|
if err == nil { //nolint:gocritic
|
||||||
// TooManyRequest means we need to slow
|
// TooManyRequest means we need to slow
|
||||||
// down and retry our request. Codes over
|
// down and retry our request. Codes over
|
||||||
// 500 generally indicate temp. outages.
|
// 500 generally indicate temp. outages.
|
||||||
if code := rsp.StatusCode; code < 500 &&
|
if code := rsp.StatusCode; code < 500 &&
|
||||||
code != http.StatusTooManyRequests &&
|
code != http.StatusTooManyRequests {
|
||||||
!containsInt(retryOn, rsp.StatusCode) {
|
|
||||||
return rsp, nil
|
return rsp, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generate error from status code for logging
|
// Generate error from status code for logging
|
||||||
err = errors.New(`http response "` + rsp.Status + `"`)
|
err = errors.New(`http response "` + rsp.Status + `"`)
|
||||||
|
|
||||||
|
// Search for a provided "Retry-After" header value.
|
||||||
|
if after := rsp.Header.Get("Retry-After"); after != "" {
|
||||||
|
|
||||||
|
if u, _ := strconv.ParseUint(after, 10, 32); u != 0 {
|
||||||
|
// An integer number of backoff seconds was provided.
|
||||||
|
backoff = time.Duration(u) * time.Second
|
||||||
|
} else if at, _ := http.ParseTime(after); !at.Before(now) {
|
||||||
|
// An HTTP formatted future date-time was provided.
|
||||||
|
backoff = at.Sub(now)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Don't let their provided backoff exceed our max.
|
||||||
|
if max := baseBackoff * maxRetries; backoff > max {
|
||||||
|
backoff = max
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} else if errorsv2.Is(err,
|
} else if errorsv2.Is(err,
|
||||||
context.DeadlineExceeded,
|
context.DeadlineExceeded,
|
||||||
context.Canceled,
|
context.Canceled,
|
||||||
|
@ -179,11 +200,18 @@ func (t *transport) do(r *http.Request, signer func(*http.Request) error, retryO
|
||||||
} else if errors.As(err, &x509.UnknownAuthorityError{}) {
|
} else if errors.As(err, &x509.UnknownAuthorityError{}) {
|
||||||
// Unknown authority errors we do NOT recover from
|
// Unknown authority errors we do NOT recover from
|
||||||
return nil, err
|
return nil, err
|
||||||
} else if fastFail {
|
}
|
||||||
|
|
||||||
|
if fastFail {
|
||||||
// on fast-fail, don't bother backoff/retry
|
// on fast-fail, don't bother backoff/retry
|
||||||
return nil, fmt.Errorf("%w (fast fail)", err)
|
return nil, fmt.Errorf("%w (fast fail)", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if backoff == 0 {
|
||||||
|
// No retry-after found, set our predefined backoff.
|
||||||
|
backoff = time.Duration(i) * baseBackoff
|
||||||
|
}
|
||||||
|
|
||||||
l.Errorf("backing off for %s after http request error: %v", backoff.String(), err)
|
l.Errorf("backing off for %s after http request error: %v", backoff.String(), err)
|
||||||
|
|
||||||
select {
|
select {
|
||||||
|
@ -238,13 +266,3 @@ func (t *transport) safesign(sign func()) {
|
||||||
// Perform signing
|
// Perform signing
|
||||||
sign()
|
sign()
|
||||||
}
|
}
|
||||||
|
|
||||||
// containsInt checks if slice contains check.
|
|
||||||
func containsInt(slice []int, check int) bool {
|
|
||||||
for _, i := range slice {
|
|
||||||
if i == check {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
set -eu
|
set -eu
|
||||||
|
|
||||||
EXPECT='{"account-domain":"peepee","accounts-allow-custom-css":true,"accounts-approval-required":false,"accounts-reason-required":false,"accounts-registration-open":true,"advanced-cookies-samesite":"strict","advanced-rate-limit-requests":6969,"advanced-throttling-multiplier":-1,"application-name":"gts","bind-address":"127.0.0.1","cache":{"gts":{"account-max-size":99,"account-sweep-freq":1000000000,"account-ttl":10800000000000,"block-max-size":100,"block-sweep-freq":10000000000,"block-ttl":300000000000,"domain-block-max-size":1000,"domain-block-sweep-freq":60000000000,"domain-block-ttl":86400000000000,"emoji-category-max-size":100,"emoji-category-sweep-freq":10000000000,"emoji-category-ttl":300000000000,"emoji-max-size":500,"emoji-sweep-freq":10000000000,"emoji-ttl":300000000000,"mention-max-size":500,"mention-sweep-freq":10000000000,"mention-ttl":300000000000,"notification-max-size":500,"notification-sweep-freq":10000000000,"notification-ttl":300000000000,"report-max-size":100,"report-sweep-freq":10000000000,"report-ttl":300000000000,"status-max-size":500,"status-sweep-freq":10000000000,"status-ttl":300000000000,"tombstone-max-size":100,"tombstone-sweep-freq":10000000000,"tombstone-ttl":300000000000,"user-max-size":100,"user-sweep-freq":10000000000,"user-ttl":300000000000}},"config-path":"internal/config/testdata/test.yaml","db-address":":memory:","db-database":"gotosocial_prod","db-max-open-conns-multiplier":3,"db-password":"hunter2","db-port":6969,"db-sqlite-busy-timeout":1000000000,"db-sqlite-cache-size":0,"db-sqlite-journal-mode":"DELETE","db-sqlite-synchronous":"FULL","db-tls-ca-cert":"","db-tls-mode":"disable","db-type":"sqlite","db-user":"sex-haver","dry-run":false,"email":"","host":"example.com","instance-deliver-to-shared-inboxes":false,"instance-expose-peers":true,"instance-expose-public-timeline":true,"instance-expose-suspended":true,"instance-expose-suspended-web":true,"landing-page-user":"admin","letsencrypt-cert-dir":"/gotosocial/storage/certs","letsencrypt-email-address":"","letsencrypt-enabled":true,"letsencrypt-port":80,"log-db-queries":true,"log-level":"info","media-description-max-chars":5000,"media-description-min-chars":69,"media-emoji-local-max-size":420,"media-emoji-remote-max-size":420,"media-image-max-size":420,"media-remote-cache-days":30,"media-video-max-size":420,"oidc-client-id":"1234","oidc-client-secret":"shhhh its a secret","oidc-enabled":true,"oidc-idp-name":"sex-haver","oidc-issuer":"whoknows","oidc-link-existing":true,"oidc-scopes":["read","write"],"oidc-skip-verification":true,"password":"","path":"","port":6969,"protocol":"http","smtp-from":"queen.rip.in.piss@terfisland.org","smtp-host":"example.com","smtp-password":"hunter2","smtp-port":4269,"smtp-username":"sex-haver","software-version":"","statuses-cw-max-chars":420,"statuses-max-chars":69,"statuses-media-max-files":1,"statuses-poll-max-options":1,"statuses-poll-option-max-chars":50,"storage-backend":"local","storage-local-base-path":"/root/store","storage-s3-access-key":"minio","storage-s3-bucket":"gts","storage-s3-endpoint":"localhost:9000","storage-s3-proxy":true,"storage-s3-secret-key":"miniostorage","storage-s3-use-ssl":false,"syslog-address":"127.0.0.1:6969","syslog-enabled":true,"syslog-protocol":"udp","trusted-proxies":["127.0.0.1/32","docker.host.local"],"username":"","web-asset-base-dir":"/root","web-template-base-dir":"/root"}'
|
EXPECT='{"account-domain":"peepee","accounts-allow-custom-css":true,"accounts-approval-required":false,"accounts-reason-required":false,"accounts-registration-open":true,"advanced-cookies-samesite":"strict","advanced-rate-limit-requests":6969,"advanced-throttling-multiplier":-1,"advanced-throttling-retry-after":10000000000,"application-name":"gts","bind-address":"127.0.0.1","cache":{"gts":{"account-max-size":99,"account-sweep-freq":1000000000,"account-ttl":10800000000000,"block-max-size":100,"block-sweep-freq":10000000000,"block-ttl":300000000000,"domain-block-max-size":1000,"domain-block-sweep-freq":60000000000,"domain-block-ttl":86400000000000,"emoji-category-max-size":100,"emoji-category-sweep-freq":10000000000,"emoji-category-ttl":300000000000,"emoji-max-size":500,"emoji-sweep-freq":10000000000,"emoji-ttl":300000000000,"mention-max-size":500,"mention-sweep-freq":10000000000,"mention-ttl":300000000000,"notification-max-size":500,"notification-sweep-freq":10000000000,"notification-ttl":300000000000,"report-max-size":100,"report-sweep-freq":10000000000,"report-ttl":300000000000,"status-max-size":500,"status-sweep-freq":10000000000,"status-ttl":300000000000,"tombstone-max-size":100,"tombstone-sweep-freq":10000000000,"tombstone-ttl":300000000000,"user-max-size":100,"user-sweep-freq":10000000000,"user-ttl":300000000000}},"config-path":"internal/config/testdata/test.yaml","db-address":":memory:","db-database":"gotosocial_prod","db-max-open-conns-multiplier":3,"db-password":"hunter2","db-port":6969,"db-sqlite-busy-timeout":1000000000,"db-sqlite-cache-size":0,"db-sqlite-journal-mode":"DELETE","db-sqlite-synchronous":"FULL","db-tls-ca-cert":"","db-tls-mode":"disable","db-type":"sqlite","db-user":"sex-haver","dry-run":false,"email":"","host":"example.com","instance-deliver-to-shared-inboxes":false,"instance-expose-peers":true,"instance-expose-public-timeline":true,"instance-expose-suspended":true,"instance-expose-suspended-web":true,"landing-page-user":"admin","letsencrypt-cert-dir":"/gotosocial/storage/certs","letsencrypt-email-address":"","letsencrypt-enabled":true,"letsencrypt-port":80,"log-db-queries":true,"log-level":"info","media-description-max-chars":5000,"media-description-min-chars":69,"media-emoji-local-max-size":420,"media-emoji-remote-max-size":420,"media-image-max-size":420,"media-remote-cache-days":30,"media-video-max-size":420,"oidc-client-id":"1234","oidc-client-secret":"shhhh its a secret","oidc-enabled":true,"oidc-idp-name":"sex-haver","oidc-issuer":"whoknows","oidc-link-existing":true,"oidc-scopes":["read","write"],"oidc-skip-verification":true,"password":"","path":"","port":6969,"protocol":"http","smtp-from":"queen.rip.in.piss@terfisland.org","smtp-host":"example.com","smtp-password":"hunter2","smtp-port":4269,"smtp-username":"sex-haver","software-version":"","statuses-cw-max-chars":420,"statuses-max-chars":69,"statuses-media-max-files":1,"statuses-poll-max-options":1,"statuses-poll-option-max-chars":50,"storage-backend":"local","storage-local-base-path":"/root/store","storage-s3-access-key":"minio","storage-s3-bucket":"gts","storage-s3-endpoint":"localhost:9000","storage-s3-proxy":true,"storage-s3-secret-key":"miniostorage","storage-s3-use-ssl":false,"syslog-address":"127.0.0.1:6969","syslog-enabled":true,"syslog-protocol":"udp","trusted-proxies":["127.0.0.1/32","docker.host.local"],"username":"","web-asset-base-dir":"/root","web-template-base-dir":"/root"}'
|
||||||
|
|
||||||
# Set all the environment variables to
|
# Set all the environment variables to
|
||||||
# ensure that these are parsed without panic
|
# ensure that these are parsed without panic
|
||||||
|
@ -83,6 +83,7 @@ GTS_SYSLOG_ADDRESS='127.0.0.1:6969' \
|
||||||
GTS_ADVANCED_COOKIES_SAMESITE='strict' \
|
GTS_ADVANCED_COOKIES_SAMESITE='strict' \
|
||||||
GTS_ADVANCED_RATE_LIMIT_REQUESTS=6969 \
|
GTS_ADVANCED_RATE_LIMIT_REQUESTS=6969 \
|
||||||
GTS_ADVANCED_THROTTLING_MULTIPLIER=-1 \
|
GTS_ADVANCED_THROTTLING_MULTIPLIER=-1 \
|
||||||
|
GTS_ADVANCED_THROTTLING_RETRY_AFTER='10s' \
|
||||||
go run ./cmd/gotosocial/... --config-path internal/config/testdata/test.yaml debug config)
|
go run ./cmd/gotosocial/... --config-path internal/config/testdata/test.yaml debug config)
|
||||||
|
|
||||||
OUTPUT_OUT=$(mktemp)
|
OUTPUT_OUT=$(mktemp)
|
||||||
|
|
Loading…
Reference in a new issue