diff options
author | Koni Marti <koni.marti@gmail.com> | 2022-02-12 23:08:18 +0100 |
---|---|---|
committer | Robin Jarry <robin@jarry.cc> | 2022-02-19 15:24:55 +0100 |
commit | 11a4d5b71c12ff358916f1e0d0aed2cc26f9ea98 (patch) | |
tree | dfc0a4916ddd4bccf7c7e26f33f715388c2e329f /worker/imap/worker.go | |
parent | bb0f1801402e98266d2554a5f002dc8ce0419808 (diff) | |
download | aerc-11a4d5b71c12ff358916f1e0d0aed2cc26f9ea98.tar.gz |
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>
Diffstat (limited to 'worker/imap/worker.go')
-rw-r--r-- | worker/imap/worker.go | 32 |
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 } |