Drain the buffered updates channel when deleting messages to prevent a
backend freeze. Unilateral update messages from the IMAP server can fill
up the buffered channel if not handled during a large operation (more
than ~50 messages).
Link: https://lists.sr.ht/~rjarry/aerc-discuss/%3CCZCPBTWI3PIW.T8MWNCBG7FGL%40disroot.org%3E
Changelog-fixed: Prevent a freeze for large-scale deletions with IMAP.
Signed-off-by: Koni Marti <koni.marti@gmail.com>
---
Tested-by: Jeremy Baxter <jtbx@disroot.org>
Acked-by: Robin Jarry <robin@jarry.cc>
Applied, thanks.
To git@git.sr.ht:~rjarry/aerc
83c3a4051b14..d8d5fc8d31f3 master -> master
worker/imap/flags.go | 40 ++++++++++++++++++++++++++++++++++++++++
1 file changed, 40 insertions(+)
diff --git a/worker/imap/flags.go b/worker/imap/flags.go
index 06680818..60137bd3 100644
--- a/worker/imap/flags.go+++ b/worker/imap/flags.go
@@ -2,13 +2,53 @@ package imap
import (
"github.com/emersion/go-imap"
+ "github.com/emersion/go-imap/client" "git.sr.ht/~rjarry/aerc/lib/log"
"git.sr.ht/~rjarry/aerc/models"
"git.sr.ht/~rjarry/aerc/worker/types"
)
+// drainUpdates will drain the updates channel. For some operations, the imap+// server will send unilateral messages. If they arrive while another operation+// is in progress, the buffered updates channel can fill up and cause a freeze+// of the entire backend. Avoid this by draining the updates channel and only+// process the Message and Expunge updates.+//+// To stop the draining, close the returned struct.+func (imapw *IMAPWorker) drainUpdates() *drainCloser {+ done := make(chan struct{})+ go func() {+ defer log.PanicHandler()+ for {+ select {+ case update := <-imapw.updates:+ switch update.(type) {+ case *client.MessageUpdate,+ *client.ExpungeUpdate:+ imapw.handleImapUpdate(update)+ }+ case <-done:+ return+ }+ }+ }()+ return &drainCloser{done}+}++type drainCloser struct {+ done chan struct{}+}++func (d *drainCloser) Close() error {+ close(d.done)+ return nil+}+func (imapw *IMAPWorker) handleDeleteMessages(msg *types.DeleteMessages) {
+ drain := imapw.drainUpdates()+ defer drain.Close()+ item := imap.FormatFlagsOp(imap.AddFlags, true)
flags := []interface{}{imap.DeletedFlag}
uids := toSeqSet(msg.Uids)
--
2.44.0