diff --git a/internal/bridge/user.go b/internal/bridge/user.go index 59baaa4e..5242ef70 100644 --- a/internal/bridge/user.go +++ b/internal/bridge/user.go @@ -326,12 +326,12 @@ func (bridge *Bridge) SendBadEventUserFeedback(_ context.Context, userID string, logrus.WithError(rerr).Error("Failed to report feedback failure") } - user.BadEventFeedbackResync(ctx) - if err := bridge.addIMAPUser(ctx, user); err != nil { return fmt.Errorf("failed to add IMAP user: %w", err) } + user.BadEventFeedbackResync(ctx) + return nil } diff --git a/internal/bridge/user_events.go b/internal/bridge/user_events.go index ddf78f95..267080a4 100644 --- a/internal/bridge/user_events.go +++ b/internal/bridge/user_events.go @@ -48,7 +48,7 @@ func (bridge *Bridge) handleUserEvent(ctx context.Context, user *user.User, even } case events.UserRefreshed: - if err := bridge.handleUserRefreshed(ctx, user); err != nil { + if err := bridge.handleUserRefreshed(ctx, user, event); err != nil { return fmt.Errorf("failed to handle user refreshed event: %w", err) } @@ -120,8 +120,12 @@ func (bridge *Bridge) handleUserAddressDeleted(ctx context.Context, user *user.U return nil } -func (bridge *Bridge) handleUserRefreshed(ctx context.Context, user *user.User) error { +func (bridge *Bridge) handleUserRefreshed(ctx context.Context, user *user.User, event events.UserRefreshed) error { return safe.RLockRet(func() error { + if event.CancelEventPool { + user.CancelSyncAndEventPoll() + } + if err := bridge.removeIMAPUser(ctx, user, true); err != nil { return fmt.Errorf("failed to remove IMAP user: %w", err) } @@ -153,7 +157,7 @@ func (bridge *Bridge) handleUserBadEvent(_ context.Context, user *user.User, eve logrus.WithError(rerr).Error("Failed to report failed event handling") } - user.BadEventAbort() + user.CancelSyncAndEventPoll() // Disable IMAP user if err := bridge.removeIMAPUser(context.Background(), user, false); err != nil { diff --git a/internal/events/user.go b/internal/events/user.go index 9b80d820..172bd55b 100644 --- a/internal/events/user.go +++ b/internal/events/user.go @@ -148,7 +148,8 @@ func (event UserChanged) String() string { type UserRefreshed struct { eventBase - UserID string + UserID string + CancelEventPool bool } func (event UserRefreshed) String() string { diff --git a/internal/user/events.go b/internal/user/events.go index a7aa2c23..d5a4fec1 100644 --- a/internal/user/events.go +++ b/internal/user/events.go @@ -93,10 +93,10 @@ func (user *User) handleRefreshEvent(ctx context.Context, refresh proton.Refresh // Re-sync messages after the user, address and label refresh. defer user.goSync() - return user.syncUserAddressesLabelsAndClearSync(ctx) + return user.syncUserAddressesLabelsAndClearSync(ctx, false) } -func (user *User) syncUserAddressesLabelsAndClearSync(ctx context.Context) error { +func (user *User) syncUserAddressesLabelsAndClearSync(ctx context.Context, cancelEventPool bool) error { return safe.LockRet(func() error { // Fetch latest user info. apiUser, err := user.client.GetUser(ctx) @@ -128,7 +128,8 @@ func (user *User) syncUserAddressesLabelsAndClearSync(ctx context.Context) error // The user was refreshed. user.eventCh.Enqueue(events.UserRefreshed{ - UserID: user.apiUser.ID, + UserID: user.apiUser.ID, + CancelEventPool: cancelEventPool, }) return nil diff --git a/internal/user/user.go b/internal/user/user.go index b3769920..465307be 100644 --- a/internal/user/user.go +++ b/internal/user/user.go @@ -299,15 +299,19 @@ func (user *User) SetAddressMode(_ context.Context, mode vault.AddressMode) erro }, user.eventLock, user.apiAddrsLock, user.updateChLock) } -// BadEventAbort stops user to communicate. The resolution is either logout or resync. -func (user *User) BadEventAbort() { +// CancelSyncAndEventPoll stops the sync or event poll go-routine. +func (user *User) CancelSyncAndEventPoll() { user.syncAbort.Abort() user.pollAbort.Abort() } // BadEventFeedbackResync sends user feedback whether should do message re-sync. func (user *User) BadEventFeedbackResync(ctx context.Context) { - if err := user.syncUserAddressesLabelsAndClearSync(ctx); err != nil { + user.CancelSyncAndEventPoll() + + // We need to cancel the event poll later again as it is not guaranteed, due to timing, that we have a + // task to cancel. + if err := user.syncUserAddressesLabelsAndClearSync(ctx, true); err != nil { user.log.WithError(err).Error("Bad event resync failed") } }