aboutsummaryrefslogtreecommitdiff
path: root/worker/imap/worker.go
diff options
context:
space:
mode:
Diffstat (limited to 'worker/imap/worker.go')
-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
}