aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKoni Marti <koni.marti@gmail.com>2022-02-12 23:08:18 +0100
committerRobin Jarry <robin@jarry.cc>2022-02-19 15:24:55 +0100
commit11a4d5b71c12ff358916f1e0d0aed2cc26f9ea98 (patch)
treedfc0a4916ddd4bccf7c7e26f33f715388c2e329f
parentbb0f1801402e98266d2554a5f002dc8ce0419808 (diff)
downloadaerc-11a4d5b71c12ff358916f1e0d0aed2cc26f9ea98.tar.gz
aerc-11a4d5b71c12ff358916f1e0d0aed2cc26f9ea98.zip
imap: reconnect with exponential backoff
waits an increasing amount of time before attempting a reconnect. Wait is capped at 16s. Prevents many reconnect attemps in a short time period. Fixes commit 05ad96a30cb8 ("imap: improve reconnect stability") that improved the reliability of the reconnect mechanism but did not implement controls to prevent the triggering of too many reconnects within a short period of time. Fixes: 05ad96a30cb8 ("imap: improve reconnect stability") Signed-off-by: Koni Marti <koni.marti@gmail.com>
-rw-r--r--worker/imap/worker.go32
1 files changed, 28 insertions, 4 deletions
diff --git a/worker/imap/worker.go b/worker/imap/worker.go
index a1d55b9e..be04787f 100644
--- a/worker/imap/worker.go
+++ b/worker/imap/worker.go
@@ -3,6 +3,7 @@ package imap
import (
"crypto/tls"
"fmt"
+ "math"
"net"
"net/url"
"strconv"
@@ -12,6 +13,7 @@ import (
"github.com/emersion/go-imap"
sortthread "github.com/emersion/go-imap-sortthread"
"github.com/emersion/go-imap/client"
+ "github.com/pkg/errors"
"golang.org/x/oauth2"
"git.sr.ht/~rjarry/aerc/lib"
@@ -58,6 +60,7 @@ type IMAPWorker struct {
seqMap []uint32
done chan struct{}
autoReconnect bool
+ retries int
}
func NewIMAPWorker(worker *types.Worker) (types.Backend, error) {
@@ -85,7 +88,8 @@ func (w *IMAPWorker) handleMessage(msg types.WorkerMessage) error {
}
}()
- checkConn := func() {
+ checkConn := func(wait time.Duration) {
+ time.Sleep(wait)
w.stopConnectionObserver()
w.startConnectionObserver()
}
@@ -178,7 +182,7 @@ func (w *IMAPWorker) handleMessage(msg types.WorkerMessage) error {
if w.client != nil && w.client.State() == imap.SelectedState {
if !w.autoReconnect {
w.autoReconnect = true
- checkConn()
+ checkConn(0)
}
reterr = fmt.Errorf("Already connected")
break
@@ -206,8 +210,10 @@ func (w *IMAPWorker) handleMessage(msg types.WorkerMessage) error {
}
c, err := w.connect()
if err != nil {
- checkConn()
- reterr = err
+ wait, msg := w.exponentialBackoff()
+ go checkConn(wait)
+ w.retries++
+ reterr = errors.Wrap(err, msg)
break
}
@@ -312,6 +318,22 @@ func (w *IMAPWorker) handleImapUpdate(update client.Update) {
}
}
+func (w *IMAPWorker) exponentialBackoff() (time.Duration, string) {
+ maxWait := 16
+ if w.retries > 0 {
+ backoff := int(math.Pow(2.0, float64(w.retries)))
+ if backoff > maxWait {
+ backoff = maxWait
+ }
+ waitStr := fmt.Sprintf("%ds", backoff)
+ wait, err := time.ParseDuration(waitStr)
+ if err == nil {
+ return wait, fmt.Sprintf("wait %s before reconnect", waitStr)
+ }
+ }
+ return 0 * time.Second, ""
+}
+
func (w *IMAPWorker) startConnectionObserver() {
go func() {
select {
@@ -413,6 +435,8 @@ func (w *IMAPWorker) connect() (*client.Client, error) {
return nil, err
}
+ w.retries = 0
+
return c, nil
}