feat(BRIDGE-376): catch gluon errors related to label uniqueness constrainst...

This commit is contained in:
Atanas Janeshliev
2025-06-05 08:05:17 +00:00
parent 9cb914cf13
commit d2742c81e5
8 changed files with 37 additions and 7 deletions

View File

@ -108,8 +108,6 @@ func (t *Handler) Execute(
t.log.WithError(err).Error("Sync aborted")
break
} else if err = t.run(ctx, syncReporter, labels, updateApplier, messageBuilder); err != nil {
t.log.WithError(err).Error("Failed to sync, will retry later")
if sentryErr := t.sentryReporter.ReportMessageWithContext("Failed to sync, will retry later", reporter.Context{
"err": err.Error(),
"user_id": t.userID,
@ -117,6 +115,7 @@ func (t *Handler) Execute(
t.log.WithError(sentryErr).Error("Failed to report sentry message")
}
t.log.WithError(err).Error("Failed to sync, will retry later")
sleepCtx(ctx, coolDown)
} else {
break

View File

@ -29,6 +29,8 @@ import (
"time"
"github.com/ProtonMail/gluon/async"
"github.com/ProtonMail/gluon/db"
"github.com/ProtonMail/gluon/reporter"
"github.com/ProtonMail/gluon/watcher"
"github.com/ProtonMail/go-proton-api"
"github.com/ProtonMail/proton-bridge/v3/internal"
@ -70,6 +72,8 @@ type Service struct {
eventPollWaitersLock sync.Mutex
eventSubscription events.Subscription
eventWatcher *watcher.Watcher[events.Event]
sentryReporter reporter.Reporter
}
func NewService(
@ -82,6 +86,7 @@ func NewService(
eventTimeout time.Duration,
panicHandler async.PanicHandler,
eventSubscription events.Subscription,
sentryReporter reporter.Reporter,
) *Service {
return &Service{
cpc: cpc.NewCPC(),
@ -99,6 +104,7 @@ func NewService(
panicHandler: panicHandler,
eventSubscription: eventSubscription,
eventWatcher: eventSubscription.Add(events.ConnStatusDown{}, events.ConnStatusUp{}),
sentryReporter: sentryReporter,
}
}
@ -414,6 +420,14 @@ func (s *Service) handleEventError(ctx context.Context, lastEventID string, even
return subscriberName, fmt.Errorf("failed to handle event due to server error: %w", err)
}
if db.IsUniqueLabelConstraintError(err) {
if err := s.sentryReporter.ReportMessageWithContext("Unique label constraint error occurred on event", reporter.Context{
"err": err,
}); err != nil {
s.log.WithError(err).Error("Failed to report label constraint error to sentry")
}
}
// Otherwise, the error is a client-side issue; notify bridge to handle it.
s.log.WithField("event", event).Warn("Failed to handle API event")

View File

@ -30,6 +30,7 @@ import (
"github.com/ProtonMail/go-proton-api"
"github.com/ProtonMail/proton-bridge/v3/internal/events"
"github.com/ProtonMail/proton-bridge/v3/internal/events/mocks"
"github.com/ProtonMail/proton-bridge/v3/internal/sentry"
"github.com/golang/mock/gomock"
"github.com/stretchr/testify/require"
)
@ -49,6 +50,7 @@ func TestServiceHandleEventError_SubscriberEventUnwrapping(t *testing.T) {
time.Second,
async.NoopPanicHandler{},
events.NewNullSubscription(),
sentry.NullSentryReporter{},
)
lastEventID := "PrevEvent"
@ -87,6 +89,7 @@ func TestServiceHandleEventError_BadEventPutsServiceOnPause(t *testing.T) {
time.Second,
async.NoopPanicHandler{},
events.NewNullSubscription(),
sentry.NullSentryReporter{},
)
service.Resume()
lastEventID := "PrevEvent"
@ -121,6 +124,7 @@ func TestServiceHandleEventError_BadEventFromPublishTimeout(t *testing.T) {
time.Second,
async.NoopPanicHandler{},
events.NewNullSubscription(),
sentry.NullSentryReporter{},
)
lastEventID := "PrevEvent"
event := proton.Event{EventID: "MyEvent"}
@ -152,6 +156,7 @@ func TestServiceHandleEventError_NoBadEventCheck(t *testing.T) {
time.Second,
async.NoopPanicHandler{},
events.NewNullSubscription(),
sentry.NullSentryReporter{},
)
lastEventID := "PrevEvent"
event := proton.Event{EventID: "MyEvent"}
@ -178,6 +183,7 @@ func TestServiceHandleEventError_JsonUnmarshalEventProducesUncategorizedErrorEve
time.Second,
async.NoopPanicHandler{},
events.NewNullSubscription(),
sentry.NullSentryReporter{},
)
lastEventID := "PrevEvent"
event := proton.Event{EventID: "MyEvent"}

View File

@ -28,6 +28,7 @@ import (
"github.com/ProtonMail/go-proton-api"
"github.com/ProtonMail/proton-bridge/v3/internal/events"
"github.com/ProtonMail/proton-bridge/v3/internal/events/mocks"
"github.com/ProtonMail/proton-bridge/v3/internal/sentry"
"github.com/golang/mock/gomock"
"github.com/stretchr/testify/require"
)
@ -69,6 +70,7 @@ func TestServiceHandleEvent_CheckEventCategoriesHandledInOrder(t *testing.T) {
10*time.Second,
async.NoopPanicHandler{},
events.NewNullSubscription(),
sentry.NullSentryReporter{},
)
subscription := NewCallbackSubscriber("test", EventHandler{
@ -130,6 +132,7 @@ func TestServiceHandleEvent_CheckEventFailureCausesError(t *testing.T) {
time.Second,
async.NoopPanicHandler{},
events.NewNullSubscription(),
sentry.NullSentryReporter{},
)
subscription := NewCallbackSubscriber("test", EventHandler{
@ -168,6 +171,7 @@ func TestServiceHandleEvent_CheckEventFailureCausesErrorParallel(t *testing.T) {
time.Second,
async.NoopPanicHandler{},
events.NewNullSubscription(),
sentry.NullSentryReporter{},
)
subscription := NewCallbackSubscriber("test", EventHandler{

View File

@ -27,6 +27,7 @@ import (
"github.com/ProtonMail/go-proton-api"
"github.com/ProtonMail/proton-bridge/v3/internal/events"
mocks2 "github.com/ProtonMail/proton-bridge/v3/internal/events/mocks"
"github.com/ProtonMail/proton-bridge/v3/internal/sentry"
"github.com/ProtonMail/proton-bridge/v3/internal/services/orderedtasks"
"github.com/ProtonMail/proton-bridge/v3/internal/services/userevents/mocks"
"github.com/golang/mock/gomock"
@ -76,6 +77,7 @@ func TestService_EventIDLoadStore(t *testing.T) {
time.Second,
async.NoopPanicHandler{},
events.NewNullSubscription(),
sentry.NullSentryReporter{},
)
_, err := service.Start(context.Background(), group)
@ -132,6 +134,7 @@ func TestService_RetryEventOnNonCatastrophicFailure(t *testing.T) {
time.Second,
async.NoopPanicHandler{},
events.NewNullSubscription(),
sentry.NullSentryReporter{},
)
service.Subscribe(NewCallbackSubscriber("foo", EventHandler{MessageHandler: subscriber}))
@ -182,6 +185,7 @@ func TestService_OnBadEventServiceIsPaused(t *testing.T) {
time.Second,
async.NoopPanicHandler{},
events.NewNullSubscription(),
sentry.NullSentryReporter{},
)
// Event publisher expectations.
@ -249,6 +253,7 @@ func TestService_UnsubscribeDuringEventHandlingDoesNotCauseDeadlock(t *testing.T
time.Second,
async.NoopPanicHandler{},
events.NewNullSubscription(),
sentry.NullSentryReporter{},
)
subscription := NewCallbackSubscriber("foo", EventHandler{MessageHandler: subscriber})
@ -309,6 +314,7 @@ func TestService_UnsubscribeBeforeHandlingEventIsNotConsideredError(t *testing.T
time.Second,
async.NoopPanicHandler{},
events.NewNullSubscription(),
sentry.NullSentryReporter{},
)
subscription := NewEventSubscriber("Foo")
@ -369,6 +375,7 @@ func TestService_WaitOnEventPublishAfterPause(t *testing.T) {
time.Second,
async.NoopPanicHandler{},
events.NewNullSubscription(),
sentry.NullSentryReporter{},
)
subscriber.EXPECT().HandleMessageEvents(gomock.Any(), gomock.Eq(messageEvents)).Times(1).DoAndReturn(func(_ context.Context, _ []proton.MessageEvent) error {
@ -442,6 +449,7 @@ func TestService_EventRewind(t *testing.T) {
time.Second,
async.NoopPanicHandler{},
events.NewNullSubscription(),
sentry.NullSentryReporter{},
)
_, err := service.Start(context.Background(), group)