refactor(notification): use new queue package (#9360)

# Which Problems Are Solved

The recently introduced notification queue have potential race conditions.

# How the Problems Are Solved

Current code is refactored to use the queue package, which is safe in
regards of concurrency.

# Additional Changes

- the queue is included in startup
- improved code quality of queue

# Additional Context

- closes https://github.com/zitadel/zitadel/issues/9278
This commit is contained in:
Silvan
2025-02-27 11:49:12 +01:00
committed by GitHub
parent 83614562a2
commit 444f682e25
45 changed files with 1936 additions and 2818 deletions

View File

@@ -3,7 +3,7 @@ package channels
import "github.com/zitadel/zitadel/internal/eventstore"
type Message interface {
GetTriggeringEvent() eventstore.Event
GetTriggeringEventType() eventstore.EventType
GetContent() (string, error)
}

View File

@@ -13,7 +13,7 @@ func logMessages(ctx context.Context, channel channels.NotificationChannel) chan
return channels.HandleMessageFunc(func(message channels.Message) error {
logEntry := logging.WithFields(
"instance", authz.GetInstance(ctx).InstanceID(),
"triggering_event_type", message.GetTriggeringEvent().Type(),
"triggering_event_type", message.GetTriggeringEventType(),
)
logEntry.Debug("sending notification")
err := channel.HandleMessage(message)

View File

@@ -24,7 +24,7 @@ func countMessages(ctx context.Context, channel channels.NotificationChannel, su
func addCount(ctx context.Context, metricName string, message channels.Message) {
labels := map[string]attribute.Value{
"triggering_event_type": attribute.StringValue(string(message.GetTriggeringEvent().Type())),
"triggering_event_type": attribute.StringValue(string(message.GetTriggeringEventType())),
}
addCountErr := metrics.AddCount(ctx, metricName, 1, labels)
logging.WithFields("name", metricName, "labels", labels).OnError(addCountErr).Error("incrementing counter metric failed")

View File

@@ -9,7 +9,6 @@ import (
verify "github.com/twilio/twilio-go/rest/verify/v2"
"github.com/zitadel/logging"
"github.com/zitadel/zitadel/internal/eventstore"
"github.com/zitadel/zitadel/internal/notification/channels"
"github.com/zitadel/zitadel/internal/notification/messages"
"github.com/zitadel/zitadel/internal/zerrors"
@@ -39,15 +38,14 @@ func InitChannel(config Config) channels.NotificationChannel {
// as it would be a waste of resources and could potentially result in a rate limit.
var twilioErr *twilioClient.TwilioRestError
if errors.As(err, &twilioErr) && twilioErr.Status >= 400 && twilioErr.Status < 500 {
userID, notificationID := userAndNotificationIDsFromEvent(twilioMsg.TriggeringEvent)
logging.WithFields(
"error", twilioErr.Message,
"status", twilioErr.Status,
"code", twilioErr.Code,
"instanceID", twilioMsg.TriggeringEvent.Aggregate().InstanceID,
"userID", userID,
"notificationID", notificationID).
Warn("twilio create verification error")
"instanceID", twilioMsg.InstanceID,
"jobID", twilioMsg.JobID,
"userID", twilioMsg.UserID,
).Warn("twilio create verification error")
return channels.NewCancelError(twilioErr)
}
@@ -76,24 +74,3 @@ func InitChannel(config Config) channels.NotificationChannel {
return nil
})
}
func userAndNotificationIDsFromEvent(event eventstore.Event) (userID, notificationID string) {
aggID := event.Aggregate().ID
// we cannot cast to the actual event type because of circular dependencies
// so we just check the type...
if event.Aggregate().Type != aggregateTypeNotification {
// in case it's not a notification event, we can directly return the aggregate ID (as it's a user event)
return aggID, ""
}
// ...and unmarshal the event data from the notification event into a struct that contains the fields we need
var data struct {
Request struct {
UserID string `json:"userID"`
} `json:"request"`
}
if err := event.Unmarshal(&data); err != nil {
return "", aggID
}
return data.Request.UserID, aggID
}