21227: Don't reduce outgoing request concurrency below 4.
[arvados.git] / sdk / go / arvados / limiter.go
index f62264c636f96dfa4b55ff0d581fc8cd50b05c09..9edc5386a7655c3f1d9e31bcb0d3f55b2a999c87 100644 (file)
@@ -13,11 +13,16 @@ import (
        "time"
 )
 
-var requestLimiterQuietPeriod = time.Second
+var (
+       requestLimiterQuietPeriod        = time.Second
+       requestLimiterInitialLimit int64 = 8
+       requestLimiterMinimumLimit int64 = 4
+)
 
 type requestLimiter struct {
        current    int64
        limit      int64
+       maxlimit   int64
        lock       sync.Mutex
        cond       *sync.Cond
        quietUntil time.Time
@@ -33,6 +38,7 @@ func (rl *requestLimiter) Acquire(ctx context.Context) {
        if rl.cond == nil {
                // First use of requestLimiter. Initialize.
                rl.cond = sync.NewCond(&rl.lock)
+               rl.limit = requestLimiterInitialLimit
        }
        // Wait out the quiet period(s) immediately following a 503.
        for ctx.Err() == nil {
@@ -137,9 +143,18 @@ func (rl *requestLimiter) Report(resp *http.Response, err error) bool {
                        increase = 1
                }
                rl.limit += increase
-               if max := rl.current * 2; max > rl.limit {
+               if max := rl.current * 2; max < rl.limit {
                        rl.limit = max
                }
+               if min := requestLimiterMinimumLimit; min > rl.limit {
+                       // If limit is too low, programs like
+                       // controller and test suites can end up with
+                       // too few slots to complete a single request.
+                       rl.limit = min
+               }
+               if rl.maxlimit > 0 && rl.maxlimit < rl.limit {
+                       rl.limit = rl.maxlimit
+               }
                rl.cond.Broadcast()
        }
        return false