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 commit05ad96a30c
("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:05ad96a30c
("imap: improve reconnect stability") Signed-off-by: Koni Marti <koni.marti@gmail.com>
This commit is contained in:
parent
bb0f180140
commit
11a4d5b71c
1 changed files with 28 additions and 4 deletions
|
@ -3,6 +3,7 @@ package imap
|
||||||
import (
|
import (
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"math"
|
||||||
"net"
|
"net"
|
||||||
"net/url"
|
"net/url"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
@ -12,6 +13,7 @@ import (
|
||||||
"github.com/emersion/go-imap"
|
"github.com/emersion/go-imap"
|
||||||
sortthread "github.com/emersion/go-imap-sortthread"
|
sortthread "github.com/emersion/go-imap-sortthread"
|
||||||
"github.com/emersion/go-imap/client"
|
"github.com/emersion/go-imap/client"
|
||||||
|
"github.com/pkg/errors"
|
||||||
"golang.org/x/oauth2"
|
"golang.org/x/oauth2"
|
||||||
|
|
||||||
"git.sr.ht/~rjarry/aerc/lib"
|
"git.sr.ht/~rjarry/aerc/lib"
|
||||||
|
@ -58,6 +60,7 @@ type IMAPWorker struct {
|
||||||
seqMap []uint32
|
seqMap []uint32
|
||||||
done chan struct{}
|
done chan struct{}
|
||||||
autoReconnect bool
|
autoReconnect bool
|
||||||
|
retries int
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewIMAPWorker(worker *types.Worker) (types.Backend, error) {
|
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.stopConnectionObserver()
|
||||||
w.startConnectionObserver()
|
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.client != nil && w.client.State() == imap.SelectedState {
|
||||||
if !w.autoReconnect {
|
if !w.autoReconnect {
|
||||||
w.autoReconnect = true
|
w.autoReconnect = true
|
||||||
checkConn()
|
checkConn(0)
|
||||||
}
|
}
|
||||||
reterr = fmt.Errorf("Already connected")
|
reterr = fmt.Errorf("Already connected")
|
||||||
break
|
break
|
||||||
|
@ -206,8 +210,10 @@ func (w *IMAPWorker) handleMessage(msg types.WorkerMessage) error {
|
||||||
}
|
}
|
||||||
c, err := w.connect()
|
c, err := w.connect()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
checkConn()
|
wait, msg := w.exponentialBackoff()
|
||||||
reterr = err
|
go checkConn(wait)
|
||||||
|
w.retries++
|
||||||
|
reterr = errors.Wrap(err, msg)
|
||||||
break
|
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() {
|
func (w *IMAPWorker) startConnectionObserver() {
|
||||||
go func() {
|
go func() {
|
||||||
select {
|
select {
|
||||||
|
@ -413,6 +435,8 @@ func (w *IMAPWorker) connect() (*client.Client, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
w.retries = 0
|
||||||
|
|
||||||
return c, nil
|
return c, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue