Skip to content

Commit 459bdae

Browse files
authored
fix(imap-connection): ZMS-106: fix notification locking issues (#949)
* fix notification locking issues * new notifications should not block old ones, fix notifications deadlock * remove unnecessary notification retry logic * tidy up imap-connection changes * use pending state check instead of fixed polling
1 parent 8b1ecc4 commit 459bdae

File tree

1 file changed

+23
-3
lines changed

1 file changed

+23
-3
lines changed

imap-core/lib/imap-connection.js

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -572,9 +572,10 @@ class IMAPConnection extends EventEmitter {
572572
this._listenerData = {
573573
lock: false,
574574
cleared: false,
575+
pendingUpdate: false,
575576
callback(message) {
576577
let selectedMailbox = conn.selected && conn.selected.mailbox;
577-
if (this._closing || this._closed) {
578+
if (conn._closing || conn._closed) {
578579
conn.clearNotificationListener();
579580
return;
580581
}
@@ -599,19 +600,34 @@ class IMAPConnection extends EventEmitter {
599600
return;
600601
}
601602

602-
if (conn._listenerData.lock || !selectedMailbox) {
603-
// race condition, do not allow fetching data before previous fetch is finished
603+
if (!selectedMailbox) {
604+
return;
605+
}
606+
607+
if (conn._listenerData.lock) {
608+
// Mark that we received a notification while locked, will re-check after lock is released
609+
conn._listenerData.pendingUpdate = true;
604610
return;
605611
}
606612

607613
conn._listenerData.lock = true;
614+
conn._listenerData.pendingUpdate = false;
615+
608616
conn._server.notifier.getUpdates(selectedMailbox, conn.selected.modifyIndex, (err, updates) => {
609617
if (!conn._listenerData || conn._listenerData.cleared) {
610618
// already logged out
611619
return;
612620
}
613621
conn._listenerData.lock = false;
614622

623+
// Helper to re-check if we missed notifications while locked
624+
let recheckPending = () => {
625+
if (conn._listenerData && !conn._listenerData.cleared && conn._listenerData.pendingUpdate) {
626+
conn._listenerData.pendingUpdate = false;
627+
setImmediate(() => conn._listenerData.callback());
628+
}
629+
};
630+
615631
if (err) {
616632
conn.logger.info(
617633
{
@@ -623,11 +639,13 @@ class IMAPConnection extends EventEmitter {
623639
conn.id,
624640
err.message
625641
);
642+
recheckPending();
626643
return;
627644
}
628645

629646
// check if the same mailbox is still selected
630647
if (!isSelected(selectedMailbox) || !updates || !updates.length) {
648+
recheckPending();
631649
return;
632650
}
633651

@@ -644,6 +662,8 @@ class IMAPConnection extends EventEmitter {
644662
// when idling emit notifications immediately
645663
conn.emitNotifications();
646664
}
665+
666+
recheckPending();
647667
});
648668
}
649669
};

0 commit comments

Comments
 (0)