Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 28 additions & 13 deletions contracts/notification/notification.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,21 +25,36 @@ type NotificationWithAfterSending interface {
AfterSending(notifiable Notifiable, channel string) error
}

// NOT CURRENTLY WIRED — implementing this on a notification has no
// effect today.
type NotificationWithBackoff interface {
// NotificationWithTries is an optional extension for queued
// notifications that want to cap retry attempts on delivery failure.
// Mirrors contracts/broadcasting.ShouldBroadcastWithTries exactly, for
// consistency across the two queued-retry mechanisms in this codebase.
type NotificationWithTries interface {
Notification
// Backoff returns the number of seconds to wait before retrying
// after channel is the channel that failed.
Backoff(channel string) int
}

// NOT CURRENTLY WIRED — same root cause as NotificationWithBackoff:
type NotificationWithRetryUntil interface {
// Tries returns the maximum number of attempts for the given
// channel. 0 / not implementing this interface means the
// notification is single-shot on that channel — no retry at all,
// not even once, matching ShouldBroadcastWithTries's semantics.
Tries(channel string) int
}

// NotificationWithBackoff is an optional extension for queued
// notifications that want to control the delay before each retry
// attempt. Mirrors contracts/broadcasting.ShouldBroadcastWithBackoff
// exactly: Backoff(channel) is called once, while the notification is
// still live, and returns the FULL per-attempt schedule up front — not
// re-invoked per retry. ShouldRetry indexes into the captured slice by
// attempt number, and the last value repeats for any attempt beyond the
// slice's length (min(attempt-1, len(backoff)-1)), matching Laravel's
// Worker::calculateBackoff and BroadcastJob.ShouldRetry precisely.
//
// Only takes effect together with NotificationWithTries; without Tries
// the notification is single-shot regardless of Backoff.
type NotificationWithBackoff interface {
Notification
// RetryUntil returns the time after which delivery attempts should
// stop being retried.
RetryUntil() time.Time
// Backoff returns the delay before each retry attempt on channel,
// in order; the last value repeats for subsequent attempts.
Backoff(channel string) []time.Duration
}

type Notifiable interface {
Expand Down
14 changes: 7 additions & 7 deletions errors/list.go
Original file line number Diff line number Diff line change
Expand Up @@ -204,14 +204,14 @@ var (
NotificationChannelNotQueueable = New("notification channel %q does not support queued dispatch (does not implement ResolvableChannel)").SetModule(ModuleNotification)
NotificationInvalidQueuePayload = New("notification queue payload is missing or malformed").SetModule(ModuleNotification)
NotificationMailEmptyRoute = New("mail channel: %T.RouteNotificationFor(\"mail\") returned empty address").SetModule(ModuleNotification)
NotificationMailMarshalPayloadFailed = New("mail channel: failed to marshal payload for %T: %w").SetModule(ModuleNotification)
NotificationMailUnmarshalPayloadFailed = New("mail channel: failed to unmarshal payload: %w").SetModule(ModuleNotification)
NotificationMailSendFailed = New("mail channel: failed to send: %w").SetModule(ModuleNotification)
NotificationMailMarshalPayloadFailed = New("mail channel: failed to marshal payload for %T: %v").SetModule(ModuleNotification)
NotificationMailUnmarshalPayloadFailed = New("mail channel: failed to unmarshal payload: %v").SetModule(ModuleNotification)
NotificationMailSendFailed = New("mail channel: failed to send: %v").SetModule(ModuleNotification)
NotificationDatabaseEmptyRoute = New("database channel: %T.RouteNotificationFor(\"database\") returned empty ID").SetModule(ModuleNotification)
NotificationDatabaseMarshalDataFailed = New("database channel: failed to marshal payload for %T: %w").SetModule(ModuleNotification)
NotificationDatabaseMarshalRecordFailed = New("database channel: failed to marshal record: %w").SetModule(ModuleNotification)
NotificationDatabaseUnmarshalRecordFailed = New("database channel: failed to unmarshal record: %w").SetModule(ModuleNotification)
NotificationDatabaseInsertFailed = New("database channel: failed to insert notification record: %w").SetModule(ModuleNotification)
NotificationDatabaseMarshalDataFailed = New("database channel: failed to marshal payload for %T: %v").SetModule(ModuleNotification)
NotificationDatabaseMarshalRecordFailed = New("database channel: failed to marshal record: %v").SetModule(ModuleNotification)
NotificationDatabaseUnmarshalRecordFailed = New("database channel: failed to unmarshal record: %v").SetModule(ModuleNotification)
NotificationDatabaseInsertFailed = New("database channel: failed to insert notification record: %v").SetModule(ModuleNotification)
NotificationTableRequiresBootstrapSetup = New("notifications:table auto-registration requires the bootstrap setup (see env.IsBootstrapSetup); register the migration manually").SetModule(ModuleNotification)

OrmDriverNotSupported = New("invalid driver: %s, only support mysql, postgres, sqlite and sqlserver")
Expand Down
16 changes: 10 additions & 6 deletions mocks/notification/NotificationWithBackoff.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

129 changes: 129 additions & 0 deletions mocks/notification/NotificationWithTries.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading
Loading