Repository: fatedier/frp (language: go)

Issue:
random delay before reconnecting to frps



Discussion / hints:

Fix patch:
diff --git a/client/service.go b/client/service.go
index d0dda158fcd..96ddadfd882 100644
--- a/client/service.go
+++ b/client/service.go
@@ -17,7 +17,6 @@ package client
 import (
 	"context"
 	"crypto/tls"
-	"errors"
 	"fmt"
 	"io"
 	"net"
@@ -34,6 +33,7 @@ import (
 	"github.com/fatedier/frp/pkg/transport"
 	"github.com/fatedier/frp/pkg/util/log"
 	frpNet "github.com/fatedier/frp/pkg/util/net"
+	"github.com/fatedier/frp/pkg/util/util"
 	"github.com/fatedier/frp/pkg/util/version"
 	"github.com/fatedier/frp/pkg/util/xlog"
 	libdial "github.com/fatedier/golib/net/dial"
@@ -109,7 +109,7 @@ func (svr *Service) Run() error {
 			if svr.cfg.LoginFailExit {
 				return err
 			}
-			time.Sleep(10 * time.Second)
+			util.RandomSleep(10*time.Second, 0.9, 1.1)
 		} else {
 			// login success
 			ctl := NewControl(svr.ctx, svr.runID, conn, session, svr.cfg, svr.pxyCfgs, svr.visitorCfgs, svr.serverUDPPort, svr.authSetter)
@@ -158,8 +158,11 @@ func (svr *Service) keepControllerWorking() {
 
 		// the first three retry with no delay
 		if reconnectCounts > 3 {
-			time.Sleep(reconnectDelay)
+			util.RandomSleep(reconnectDelay, 0.9, 1.1)
+			xl.Info("wait %v to reconnect", reconnectDelay)
 			reconnectDelay *= 2
+		} else {
+			util.RandomSleep(time.Second, 0, 0.5)
 		}
 		reconnectCounts++
 
@@ -175,18 +178,12 @@ func (svr *Service) keepControllerWorking() {
 			xl.Info("try to reconnect to server...")
 			conn, session, err := svr.login()
 			if err != nil {
-				xl.Warn("reconnect to server error: %v", err)
-				time.Sleep(delayTime)
-
-				opErr := &net.OpError{}
-				// quick retry for dial error
-				if errors.As(err, &opErr) && opErr.Op == "dial" {
-					delayTime = 2 * time.Second
-				} else {
-					delayTime = delayTime * 2
-					if delayTime > maxDelayTime {
-						delayTime = maxDelayTime
-					}
+				xl.Warn("reconnect to server error: %v, wait %v for another retry", err, delayTime)
+				util.RandomSleep(delayTime, 0.9, 1.1)
+
+				delayTime = delayTime * 2
+				if delayTime > maxDelayTime {
+					delayTime = maxDelayTime
 				}
 				continue
 			}
diff --git a/pkg/util/util/util.go b/pkg/util/util/util.go
index eb2ae0b27ee..032675fb761 100644
--- a/pkg/util/util/util.go
+++ b/pkg/util/util/util.go
@@ -19,9 +19,11 @@ import (
 	"crypto/rand"
 	"encoding/hex"
 	"fmt"
+	mathrand "math/rand"
 	"net"
 	"strconv"
 	"strings"
+	"time"
 )
 
 // RandID return a rand string used in frp.
@@ -109,3 +111,17 @@ func GenerateResponseErrorString(summary string, err error, detailed bool) strin
 	}
 	return summary
 }
+
+func RandomSleep(duration time.Duration, minRatio, maxRatio float64) time.Duration {
+	min := int64(minRatio * 1000.0)
+	max := int64(maxRatio * 1000.0)
+	var n int64
+	if max <= min {
+		n = min
+	} else {
+		n = mathrand.Int63n(max-min) + min
+	}
+	d := duration * time.Duration(n) / time.Duration(1000)
+	time.Sleep(d)
+	return d
+}


Test patch: