mirror of
https://github.com/ProtonMail/proton-bridge.git
synced 2025-12-10 04:36:43 +00:00
feat(BRIDGE-376): catch gluon errors related to label uniqueness constrainst...
This commit is contained in:
2
go.mod
2
go.mod
@ -7,7 +7,7 @@ toolchain go1.24.2
|
||||
require (
|
||||
github.com/0xAX/notificator v0.0.0-20220220101646-ee9b8921e557
|
||||
github.com/Masterminds/semver/v3 v3.2.0
|
||||
github.com/ProtonMail/gluon v0.17.1-0.20250603132151-341ea279ce81
|
||||
github.com/ProtonMail/gluon v0.17.1-0.20250604083016-c6e17f8461b1
|
||||
github.com/ProtonMail/go-autostart v0.0.0-20210130080809-00ed301c8e9a
|
||||
github.com/ProtonMail/go-proton-api v0.4.1-0.20250417134000-e624a080f7ba
|
||||
github.com/ProtonMail/gopenpgp/v2 v2.8.2-proton
|
||||
|
||||
6
go.sum
6
go.sum
@ -36,10 +36,8 @@ github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAE
|
||||
github.com/ProtonMail/bcrypt v0.0.0-20210511135022-227b4adcab57/go.mod h1:HecWFHognK8GfRDGnFQbW/LiV7A3MX3gZVs45vk5h8I=
|
||||
github.com/ProtonMail/bcrypt v0.0.0-20211005172633-e235017c1baf h1:yc9daCCYUefEs69zUkSzubzjBbL+cmOXgnmt9Fyd9ug=
|
||||
github.com/ProtonMail/bcrypt v0.0.0-20211005172633-e235017c1baf/go.mod h1:o0ESU9p83twszAU8LBeJKFAAMX14tISa0yk4Oo5TOqo=
|
||||
github.com/ProtonMail/gluon v0.17.1-0.20250528125353-9b611f58b753 h1:Zym7WHKLOu1RAUc9b8vkhwEaEU2Gi6MkaurCm7zpK6E=
|
||||
github.com/ProtonMail/gluon v0.17.1-0.20250528125353-9b611f58b753/go.mod h1:0/c03TzZPNiSgY5UDJK1iRDkjlDPwWugxTT6et2qDu8=
|
||||
github.com/ProtonMail/gluon v0.17.1-0.20250603132151-341ea279ce81 h1:p3X/izcQ3VtYI7qF0pmejByXPTRisFkkS+xCxXgeCxs=
|
||||
github.com/ProtonMail/gluon v0.17.1-0.20250603132151-341ea279ce81/go.mod h1:0/c03TzZPNiSgY5UDJK1iRDkjlDPwWugxTT6et2qDu8=
|
||||
github.com/ProtonMail/gluon v0.17.1-0.20250604083016-c6e17f8461b1 h1:FvkPBZF/M5GpZTy+hzhaheyi+Z5XWeZOL5GKVKqj85Y=
|
||||
github.com/ProtonMail/gluon v0.17.1-0.20250604083016-c6e17f8461b1/go.mod h1:0/c03TzZPNiSgY5UDJK1iRDkjlDPwWugxTT6et2qDu8=
|
||||
github.com/ProtonMail/go-crypto v0.0.0-20230321155629-9a39f2531310/go.mod h1:8TI4H3IbrackdNgv+92dI+rhpCaLqM0IfpgCgenFvRE=
|
||||
github.com/ProtonMail/go-crypto v1.1.4-proton h1:KIo9uNlk3vzlwI7o5VjhiEjI4Ld1TDixOMnoNZyfpFE=
|
||||
github.com/ProtonMail/go-crypto v1.1.4-proton/go.mod h1:zNoyBJW3p/yVWiHNZgfTF9VsjwqYof5YY0M9kt2QaX0=
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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")
|
||||
|
||||
|
||||
@ -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"}
|
||||
|
||||
@ -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{
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -241,6 +241,7 @@ func newImpl(
|
||||
5*time.Minute,
|
||||
crashHandler,
|
||||
eventSubscription,
|
||||
reporter,
|
||||
)
|
||||
|
||||
addressMode := usertypes.VaultToAddressMode(encVault.AddressMode())
|
||||
|
||||
Reference in New Issue
Block a user