Powering cross-channel configurable alerts with Knock
Powering customer-defined, cross-channel alerting is a common notifications use case. In this guide, we’ll lay out the different options for powering alerting using Knock and the trade-offs of each.
What do we mean by alerting?
Alerting flows are common in many products today; you see them in infrastructure tools such as Datadog or Honeycomb when you’re defining a monitor / alarm. You also see them in product-management or data tools such as Amplitude or Mixpanel when you want to get a custom alert when a certain condition is met.
An alerting notification flow typically has the following characteristics:
- The user defines the channels that a notification should be sent on, as well as any escalation rules (send to email, then wait X minutes before sending to SMS).
- The user defines the list of recipients that the alert notification should be sent to.
Here's an example of an alert: creating a monitor for an ALB metric in Datadog:
Modeling a Knock workflow for alerts
A Knock workflow encapsulates a single type of notification in your system and collects together the cross-channel orchestration logic and associated behavior for how a notification should be sent to a recipient.
For our alert workflow, we find it’s best to have a single workflow that has all possible channels that an alert could be sent to. We can then use trigger conditions per-channel step to have a given alert's configuration control whether a particular channel should be used for a given recipient.
Here’s an example workflow:
Here we’re using a trigger condition on each channel step
data.channels and checking it includes the channel type (
Using Knock to power alerts
Option 1: Manage your alert objects and recipient lists in Knock
In this option, you'll use a Knock Object to model your alerts and use Object Subscriptions to manage the list of recipients that should be notified when an alert is triggered.
Your alert object is stored under an
alerts collection and includes:
- A unique id for the alert. This will come from your system.
- The list of channels the alert should notify. We’ll use this within our workflow as a trigger condition on each step to determine if the alert should send to that channel.
- Metadata. An opportunity to send any custom data that may be useful in the alert notification templates or to provide additional context to downstream notifications.
You can set an alert and its current status in Knock by using the objects set API, which will always perform an “upsert” (replacing existing fields).
To ensure the alert goes to the subscribed recipients you can use object subscriptions to subscribe recipients to the alert object.
When our alert is triggered, all we need to do now is trigger our alert workflow with the alert object we configured earlier.
Under the hood, Knock fanouts to all subscribers on the alert object on your behalf, and you can access the
alert object (and its properties) in the workflow builder, trigger conditions, and notification templates to inject context about the currently executing alert for each subscribed recipient.
- Knock manages all aspects of your alerting data model and becomes the source of truth for alerts and users subscribed to them
- Object subscriptions work well for when you have a large set of recipients and don’t want to send the full list to Knock
- Simple to model non-user recipient channels (like Slack) that can be connect directly to the alert object itself
- More bookkeeping; have to update Knock when a model changes or a user is added or removed from an alert
Option 2: Manage alerting objects and recipient lists in your model
The other way to power alerting using Knock is to keep your alerts data model (along with their subscribers) within your system and trigger workflows in Knock for those objects.
In the example above, we’re sending the
alert as a property in the data payload so it can be used within the workflow builder and our notification templates.
- Your alerting data model lives in your system, which may be a more natural place for it, depending on the data you’re storing and how you’re using the alerts in your system
- Less bookkeeping; the only call to Knock is when the alert is triggered
- Sending to a large number of recipients requires making multiple calls to Knock (recipients are capped at 1000 per trigger)
- Have to fetch and pass the alert object to Knock on every alert invocation
- More complex to send to a non-user recipient for a channel such as Slack or MS Teams
User preferences in an alerting model
One interesting facet of our alerts workflow as defined is how per-recipient preferences work in conjunction with an alerting model.
We see these as two distinct problems:
- Which channels is the alert configured to send on (e.g. which channels should they alert send if everything was on).
- Which channels should the recipient receive the alert notifications on, given the preferences they've configured for themselves across your application.
User preferences solve the latter problem, while in the design laid out above, the channels and trigger conditions on each channel step handle alert-channel configuration.
Therefore, it’s entirely possible to define an alerting system using Knock where a recipient is subscribed to an alert that sends to in-app and escalates to email, but the recipient may have opted out of receiving all emails and so the alert is never sent to the recipient’s email.