Repository navigation
fix duplicate and misdirected notifications, add mail and webhook channels, events, fake, and a delivery log - #17
Merged
Conversation
…ebhook channels, events, fake, and a delivery log
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
Two bugs affected anyone using the notifier in production, and the package lacked several things people expect from a notification system (mail, events, a test fake, delivery visibility).
Bug 1: a retry re-sent what had already worked.
NotificationDispatcherran every channel in one job: the database row first, then Slack, Discord and so on. If a later channel threw, the whole job was retried and the database notification was stored again each attempt. With['database', 'slack']and Slack down, one notification produced 3 database rows.Bug 2:
notifications()read the signed-in user's notifications.notifications(),unreadNotifications(),readNotifications()andmarkNotificationsAsRead()filtered byauth()->id(), not by the entity. An admin viewing another user saw their own notifications. In a queue worker or console command there is no signed-in user, and the call threwAuth actor [web] is not defined.Also fixed: Slack failures were only logged, so the queue never retried them (Discord already threw).
ChannelDriverthrew aTypeErrorwhen constructed without the application.What changed
Delivery
DatabaseChannelis now a real channel (the dispatcher no longer special-cases it).send()returns the notification id (UUID), shared by that send's jobs.New channels
mail: structured content (greeting, lines, action button, outro, footer) or your own html/text. Supports cc, bcc, reply-to, attachments, tags, priority. All values are escaped and action links must be plain http(s).webhook: JSON body, custom headers, optional HMAC signature inX-Notification-Signature. Addresses must be http(s). Headers containing line breaks are dropped.Channels\Support\Httpis a small injectable transport, so channels are testable without the network.Notification API (all optional, defaults keep current behaviour)
contentFor($channel, $notifiable)routes totoMail(),toSlack()and so on, falling back tocontent().shouldSendVia(),throttle(),priority(),uniqueId(),backoff(),onConnection().wantsNotification()for per-person channel preferences, plusunreadNotificationsCount(),markNotificationAsRead($id),deleteNotification($id),deleteReadNotifications()andnotificationDeliveries().Observability and testing
notification_deliveries, one row per notification and channel, with status, attempts and last error. It is best effort: when the table is missing it is skipped with a warning and sending is unaffected.Notification::sending()(return false to cancel),sent(),failed(). A throwing listener is logged and ignored.Notification::fake()withassertSentTo,assertNotSentTo,assertSentTimes,assertSentVia,assertNothingSent,assertCount.DatabaseNotification::prune()and thenotification:prunecommand.Behaviour changes to review
send()returns a UUID instead of a queue job id.toMany()returns one id per recipient.ChannelDriverkeeps itsApplication $appproperty type. Making it nullable would break subclasses that redeclare it, so a channel built without the app leaves the property unset instead.NotificationDispatchergains a fourth constructor argument,$notificationId.Migration
New migration
create_notification_deliveries_table. Recommended, not required. Without it the log, "skip an already-delivered channel on retry" andthrottle()are off. Everything else works.Dependencies on
doppar/queuePriority,
uniqueId(),backoff()andonConnection()use the newer queue's job methods. On an older queue they are accepted and ignored. Everything else works with any 4.x.The queue's
queue_jobstable also needs its new columns for the notifier to queue anything on a newer queue. That belongs to the queue package's own upgrade path.Tests
predis/predisand a reachable server. They skip otherwise.