From 8c0bb22de37db9b7c470c8bbd3c17165f7d8c075 Mon Sep 17 00:00:00 2001 From: Jakub Date: Fri, 3 Mar 2023 17:20:49 +0100 Subject: [PATCH] feat(GODT-2442): handle bad event resync resolution. --- internal/bridge/user_events.go | 34 ++++++++++++++++++++++++++++++---- internal/user/events.go | 16 +++++++++++++--- internal/user/user.go | 11 +++++++++++ 3 files changed, 54 insertions(+), 7 deletions(-) diff --git a/internal/bridge/user_events.go b/internal/bridge/user_events.go index a05f4731..31dd32db 100644 --- a/internal/bridge/user_events.go +++ b/internal/bridge/user_events.go @@ -142,21 +142,47 @@ func (bridge *Bridge) handleUserDeauth(ctx context.Context, user *user.User) { func (bridge *Bridge) handleUserBadEvent(ctx context.Context, user *user.User, event events.UserBadEvent) { safe.Lock(func() { - if rerr := bridge.reporter.ReportMessageWithContext("Failed to handle event", reporter.Context{ + reportContext := reporter.Context{ "user_id": user.ID(), "old_event_id": event.OldEventID, "new_event_id": event.NewEventID, "event_info": event.EventInfo, "error": event.Error, "error_type": fmt.Sprintf("%T", internal.ErrCause(event.Error)), - }); rerr != nil { - logrus.WithError(rerr).Error("Failed to report failed event handling") } - bridge.logoutUser(ctx, user, true, false) + // blockEventsIMAPandSMTP() + + if doResyc, err := bridge.getBadEventUserFeedback(); err != nil || !doResyc { + if rerr := bridge.reporter.ReportMessageWithContext("Failed to handle event: logout", reportContext); rerr != nil { + logrus.WithError(rerr).Error("Failed to report failed event handling") + } + + bridge.logoutUser(ctx, user, true, false) + return + } + + if rerr := bridge.reporter.ReportMessageWithContext("Failed to handle event: repair", reportContext); rerr != nil { + logrus.WithError(rerr).Error("Failed to report event handling failure") + } + + if syncErr := user.SyncEvent(ctx); syncErr != nil { + reportContext["error"] = syncErr + reportContext["error_type"] = fmt.Sprintf("%T", internal.ErrCause(syncErr)) + if rerr := bridge.reporter.ReportMessageWithContext("Failed to handle event: repair failed: logging out", reportContext); rerr != nil { + logrus.WithError(rerr).Error("Failed to report repair failure") + } + + bridge.logoutUser(ctx, user, true, false) + return + } }, bridge.usersLock) } +func (bridge *Bridge) getBadEventUserFeedback() (doResyc bool, err error) { + return true, nil +} + func (bridge *Bridge) handleUncategorizedErrorEvent(event events.UncategorizedEventError) { if rerr := bridge.reporter.ReportMessageWithContext("Failed to handle due to uncategorized error", reporter.Context{ "error_type": fmt.Sprintf("%T", internal.ErrCause(event.Error)), diff --git a/internal/user/events.go b/internal/user/events.go index 8e8470b9..df1da8f6 100644 --- a/internal/user/events.go +++ b/internal/user/events.go @@ -86,12 +86,22 @@ func (user *User) handleRefreshEvent(ctx context.Context, refresh proton.Refresh l.WithError(err).Error("Failed to report refresh to sentry") } - // Cancel the event stream once this refresh is done. - defer user.pollAbort.Abort() + return user.SyncEvent(ctx) +} - // Resync after the refresh. +func (user *User) SyncEvent(ctx context.Context) error { + // Cancel the event stream + user.pollAbort.Abort() // ??? There was a defer here. But I think it's best to do this immediately, there is no reason to continue with polls while having re-sync. + + // Re-sync messages after the user, address and label refresh. defer user.goSync() + // stop IMAP and SMTP + + if err := user.vault.SetEventID(""); err != nil { + return fmt.Errorf("failed to clean latest event ID: %w", err) + } + return safe.LockRet(func() error { // Fetch latest user info. apiUser, err := user.client.GetUser(ctx) diff --git a/internal/user/user.go b/internal/user/user.go index 8035f0a4..4e54526e 100644 --- a/internal/user/user.go +++ b/internal/user/user.go @@ -626,6 +626,17 @@ func (user *User) doEventPoll(ctx context.Context) error { user.eventLock.Lock() defer user.eventLock.Unlock() + eventID := user.vault.EventID() + if eventID == "" { + err := errors.New("current eventID is empty") + user.eventCh.Enqueue(events.UncategorizedEventError{ // this might be bad event.. I hope sync is ongoing + UserID: user.ID(), + Error: err, + }) + + return err + } + event, err := user.client.GetEvent(ctx, user.vault.EventID()) if err != nil { return fmt.Errorf("failed to get event (caused by %T): %w", internal.ErrCause(err), err)