From dcf694588ce877831858eb3dd6f33b5ff9def5aa Mon Sep 17 00:00:00 2001 From: Leander Beernaert Date: Wed, 22 Feb 2023 13:30:45 +0100 Subject: [PATCH] fix(GODT-2390): Add reports for uncaught json and net.opErr Report to sentry if we see some uncaught network err, but don't force the user logout. If we catch an uncaught json parser error we report the error to sentry and let the user be logged out later. Finally this patch also prints the error type in UserBadEvent sentry report to further help diagnose issues. --- internal/bridge/user_events.go | 15 ++++++++++++++- internal/events/user.go | 11 +++++++++++ internal/user/user.go | 22 ++++++++++++++++++---- 3 files changed, 43 insertions(+), 5 deletions(-) diff --git a/internal/bridge/user_events.go b/internal/bridge/user_events.go index c0ee71bd..923bd8e5 100644 --- a/internal/bridge/user_events.go +++ b/internal/bridge/user_events.go @@ -56,6 +56,9 @@ func (bridge *Bridge) handleUserEvent(ctx context.Context, user *user.User, even case events.UserBadEvent: bridge.handleUserBadEvent(ctx, user, event.Error) + + case events.UncategorizedEventError: + bridge.handleUncategorizedErrorEvent(event) } return nil @@ -139,7 +142,8 @@ func (bridge *Bridge) handleUserDeauth(ctx context.Context, user *user.User) { func (bridge *Bridge) handleUserBadEvent(ctx context.Context, user *user.User, err error) { safe.Lock(func() { if rerr := bridge.reporter.ReportMessageWithContext("Failed to handle event", reporter.Context{ - "error": err, + "error_type": fmt.Sprintf("%T", err), + "error": err, }); rerr != nil { logrus.WithError(rerr).Error("Failed to report failed event handling") } @@ -147,3 +151,12 @@ func (bridge *Bridge) handleUserBadEvent(ctx context.Context, user *user.User, e bridge.logoutUser(ctx, user, true, false) }, bridge.usersLock) } + +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", event.Error), + "error": event.Error, + }); rerr != nil { + logrus.WithError(rerr).Error("Failed to report failed event handling") + } +} diff --git a/internal/events/user.go b/internal/events/user.go index 216069f6..7b9771a5 100644 --- a/internal/events/user.go +++ b/internal/events/user.go @@ -156,3 +156,14 @@ type AddressModeChanged struct { func (event AddressModeChanged) String() string { return fmt.Sprintf("AddressModeChanged: UserID: %s, AddressMode: %s", event.UserID, event.AddressMode) } + +type UncategorizedEventError struct { + eventBase + + UserID string + Error error +} + +func (event UncategorizedEventError) String() string { + return fmt.Sprintf("UncategorizedEventError: UserID: %s, Source:%T, Error: %s", event.UserID, event.Error, event.Error) +} diff --git a/internal/user/user.go b/internal/user/user.go index 7cd96d55..f993f5e9 100644 --- a/internal/user/user.go +++ b/internal/user/user.go @@ -20,10 +20,11 @@ package user import ( "context" "crypto/subtle" + "encoding/json" "errors" "fmt" "io" - "net/url" + "net" "strings" "sync/atomic" "time" @@ -647,9 +648,22 @@ func (user *User) doEventPoll(ctx context.Context) error { return fmt.Errorf("failed to handle event due to network issue: %w", err) } - // If the error is a url.Error, return error to retry later. - if urlErr := new(url.Error); errors.As(err, &urlErr) { - return fmt.Errorf("failed to handle event due to URL issue: %w", err) + // Catch all for uncategorized net errors that may slip through. + if netErr := new(net.OpError); errors.As(err, &netErr) { + user.eventCh.Enqueue(events.UncategorizedEventError{ + UserID: user.ID(), + Error: err, + }) + + return fmt.Errorf("failed to handle event due to network issues (uncategorized): %w", err) + } + + // In case a json decode error slips through. + if jsonErr := new(json.UnmarshalTypeError); errors.As(err, &jsonErr) { + user.eventCh.Enqueue(events.UncategorizedEventError{ + UserID: user.ID(), + Error: err, + }) } // If the error is a server-side issue, return error to retry later.