Documentation
¶
Index ¶
Constants ¶
const ( LabelMethod = "method" LabelTemplateID = "notification_template_id" LabelResult = "result" ResultSuccess = "success" ResultTempFail = "temp_fail" ResultPermFail = "perm_fail" )
Variables ¶
var ( ErrCannotEnqueueDisabledNotification = xerrors.New("notification is not enabled") ErrDuplicate = xerrors.New("duplicate notification") )
var ( TemplateWorkspaceCreated = uuid.MustParse("281fdf73-c6d6-4cbb-8ff5-888baf8a2fff") TemplateWorkspaceManuallyUpdated = uuid.MustParse("d089fe7b-d5c5-4c0c-aaf5-689859f7d392") TemplateWorkspaceDeleted = uuid.MustParse("f517da0b-cdc9-410f-ab89-a86107c420ed") TemplateWorkspaceAutobuildFailed = uuid.MustParse("381df2a9-c0c0-4749-420f-80a9280c66f9") TemplateWorkspaceDormant = uuid.MustParse("0ea69165-ec14-4314-91f1-69566ac3c5a0") TemplateWorkspaceAutoUpdated = uuid.MustParse("c34a0c09-0704-4cac-bd1c-0c0146811c2b") TemplateWorkspaceMarkedForDeletion = uuid.MustParse("51ce2fdf-c9ca-4be1-8d70-628674f9bc42") TemplateWorkspaceManualBuildFailed = uuid.MustParse("2faeee0f-26cb-4e96-821c-85ccb9f71513") TemplateWorkspaceOutOfMemory = uuid.MustParse("a9d027b4-ac49-4fb1-9f6d-45af15f64e7a") TemplateWorkspaceOutOfDisk = uuid.MustParse("f047f6a3-5713-40f7-85aa-0394cce9fa3a") )
Workspace-related events.
var ( TemplateUserAccountCreated = uuid.MustParse("4e19c0ac-94e1-4532-9515-d1801aa283b2") TemplateUserAccountDeleted = uuid.MustParse("f44d9314-ad03-4bc8-95d0-5cad491da6b6") TemplateUserAccountSuspended = uuid.MustParse("b02ddd82-4733-4d02-a2d7-c36f3598997d") TemplateUserAccountActivated = uuid.MustParse("9f5af851-8408-4e73-a7a1-c6502ba46689") TemplateYourAccountSuspended = uuid.MustParse("6a2f0609-9b69-4d36-a989-9f5925b6cbff") TemplateYourAccountActivated = uuid.MustParse("1a6a6bea-ee0a-43e2-9e7c-eabdb53730e4") TemplateUserRequestedOneTimePasscode = uuid.MustParse("62f86a30-2330-4b61-a26d-311ff3b608cf") )
Account-related events.
var ( TemplateTemplateDeleted = uuid.MustParse("29a09665-2a4c-403f-9648-54301670e7be") TemplateTemplateDeprecated = uuid.MustParse("f40fae84-55a2-42cd-99fa-b41c1ca64894") TemplateWorkspaceBuildsFailedReport = uuid.MustParse("34a20db2-e9cc-4a93-b0e4-8569699d7a00") )
Template-related events.
var ErrInvalidDispatchTimeout = xerrors.New("dispatch timeout must be less than lease period")
var (
TemplateTestNotification = uuid.MustParse("c425f63e-716a-4bf4-ae24-78348f706c3f")
)
Notification-related events.
Functions ¶
This section is empty.
Types ¶
type Enqueuer ¶
type Enqueuer interface { Enqueue(ctx context.Context, userID, templateID uuid.UUID, labels map[string]string, createdBy string, targets ...uuid.UUID) ([]uuid.UUID, error) EnqueueWithData(ctx context.Context, userID, templateID uuid.UUID, labels map[string]string, data map[string]any, createdBy string, targets ...uuid.UUID) ([]uuid.UUID, error) }
Enqueuer enqueues a new notification message in the store and returns its ID, should it enqueue without failure.
type Handler ¶
type Handler interface { // Dispatcher constructs a DeliveryFunc to be used for delivering a notification via the chosen method. Dispatcher(payload types.MessagePayload, title, body string, helpers template.FuncMap) (dispatch.DeliveryFunc, error) }
Handler is responsible for preparing and delivering a notification by a given method.
type InvalidDefaultNotificationMethodError ¶ added in v2.21.0
type InvalidDefaultNotificationMethodError struct {
Method string
}
func (InvalidDefaultNotificationMethodError) Error ¶ added in v2.21.0
func (e InvalidDefaultNotificationMethodError) Error() string
type Manager ¶
type Manager struct {
// contains filtered or unexported fields
}
Manager manages all notifications being enqueued and dispatched.
Manager maintains a notifier: this consumes the queue of notification messages in the store.
The notifier dequeues messages from the store _CODER_NOTIFICATIONS_LEASE_COUNT_ at a time and concurrently "dispatches" these messages, meaning they are sent by their respective methods (email, webhook, etc).
To reduce load on the store, successful and failed dispatches are accumulated in two separate buffers (success/failure) of size CODER_NOTIFICATIONS_STORE_SYNC_INTERVAL in the Manager, and updates are sent to the store about which messages succeeded or failed every CODER_NOTIFICATIONS_STORE_SYNC_INTERVAL seconds. These buffers are limited in size, and naturally introduce some backpressure; if there are hundreds of messages to be sent but they start failing too quickly, the buffers (receive channels) will fill up and block senders, which will slow down the dispatch rate.
NOTE: The above backpressure mechanism only works within the same process, which may not be true forever, such as if we split notifiers out into separate targets for greater processing throughput; in this case we will need an alternative mechanism for handling backpressure.
func NewManager ¶
func NewManager(cfg codersdk.NotificationsConfig, store Store, ps pubsub.Pubsub, helpers template.FuncMap, metrics *Metrics, log slog.Logger, opts ...ManagerOption) (*Manager, error)
NewManager instantiates a new Manager instance which coordinates notification enqueuing and delivery.
helpers is a map of template helpers which are used to customize notification messages to use global settings like access URL etc.
func (*Manager) BufferedUpdatesCount ¶
BufferedUpdatesCount returns the number of buffered updates which are currently waiting to be flushed to the store. The returned values are for success & failure, respectively.
func (*Manager) Run ¶
Run initiates the control loop in the background, which spawns a given number of notifier goroutines. Manager requires system-level permissions to interact with the store. Run is only intended to be run once.
func (*Manager) WithHandlers ¶
func (m *Manager) WithHandlers(reg map[database.NotificationMethod]Handler)
WithHandlers allows for tests to inject their own handlers to verify functionality.
type ManagerOption ¶ added in v2.16.0
type ManagerOption func(*Manager)
func WithTestClock ¶ added in v2.16.0
func WithTestClock(clock quartz.Clock) ManagerOption
WithTestClock is used in testing to set the quartz clock on the manager
type Metrics ¶
type Metrics struct { DispatchAttempts *prometheus.CounterVec RetryCount *prometheus.CounterVec QueuedSeconds *prometheus.HistogramVec InflightDispatches *prometheus.GaugeVec DispatcherSendSeconds *prometheus.HistogramVec PendingUpdates prometheus.Gauge SyncedUpdates prometheus.Counter }
func NewMetrics ¶
func NewMetrics(reg prometheus.Registerer) *Metrics
type NoopEnqueuer ¶
type NoopEnqueuer struct{}
NoopEnqueuer implements the Enqueuer interface but performs a noop.
func NewNoopEnqueuer ¶
func NewNoopEnqueuer() *NoopEnqueuer
NewNoopEnqueuer builds a NoopEnqueuer which is used to fulfill the contract for enqueuing notifications, if ExperimentNotifications is not set.
type Store ¶
type Store interface { AcquireNotificationMessages(ctx context.Context, params database.AcquireNotificationMessagesParams) ([]database.AcquireNotificationMessagesRow, error) BulkMarkNotificationMessagesSent(ctx context.Context, arg database.BulkMarkNotificationMessagesSentParams) (int64, error) BulkMarkNotificationMessagesFailed(ctx context.Context, arg database.BulkMarkNotificationMessagesFailedParams) (int64, error) EnqueueNotificationMessage(ctx context.Context, arg database.EnqueueNotificationMessageParams) error FetchNewMessageMetadata(ctx context.Context, arg database.FetchNewMessageMetadataParams) (database.FetchNewMessageMetadataRow, error) GetNotificationMessagesByStatus(ctx context.Context, arg database.GetNotificationMessagesByStatusParams) ([]database.NotificationMessage, error) GetNotificationsSettings(ctx context.Context) (string, error) GetApplicationName(ctx context.Context) (string, error) GetLogoURL(ctx context.Context) (string, error) InsertInboxNotification(ctx context.Context, arg database.InsertInboxNotificationParams) (database.InboxNotification, error) }
Store defines the API between the notifications system and the storage. This abstraction is in place so that we can intercept the direct database interactions, or (later) swap out these calls with dRPC calls should we want to split the notifiers out into their own component for high availability/throughput. TODO: don't use database types here
type StoreEnqueuer ¶
type StoreEnqueuer struct {
// contains filtered or unexported fields
}
func NewStoreEnqueuer ¶
func NewStoreEnqueuer(cfg codersdk.NotificationsConfig, store Store, helpers template.FuncMap, log slog.Logger, clock quartz.Clock) (*StoreEnqueuer, error)
NewStoreEnqueuer creates an Enqueuer implementation which can persist notification messages in the store.
func (*StoreEnqueuer) Enqueue ¶
func (s *StoreEnqueuer) Enqueue(ctx context.Context, userID, templateID uuid.UUID, labels map[string]string, createdBy string, targets ...uuid.UUID) ([]uuid.UUID, error)
Enqueue queues a notification message for later delivery, assumes no structured input data.
func (*StoreEnqueuer) EnqueueWithData ¶ added in v2.16.0
func (s *StoreEnqueuer) EnqueueWithData(ctx context.Context, userID, templateID uuid.UUID, labels map[string]string, data map[string]any, createdBy string, targets ...uuid.UUID) ([]uuid.UUID, error)
Enqueue queues a notification message for later delivery. Messages will be dequeued by a notifier later and dispatched.