Alerts: alert when something matters¶
Alerts is Datahub's alert rule builder: it runs SQL against your warehouse on a schedule, checks the result against a threshold, and fires actions — notify a user, ping a team, call a webhook, or trigger a flow — the moment the rule's condition is met.
It's a Sentry-style WHEN / IF / THEN authoring surface for data alerts — pick what to monitor, define when to fire, choose who or what gets called — light enough that an analyst can author one without leaving the platform.
When to choose this¶
-
Watch a number against a threshold
"Alert me when active subscribers drop below 10,000." One column, one comparison, one number.
-
Catch data-quality regressions
"Alert if the null rate on
emailrises above 5%," or if any record is older than your 24-hour SLA. -
Alert on freshness and missed loads
"Alert when the daily ETL hasn't run by 9 AM." Watch for the data that should have arrived.
-
Bridge a metric to an action
"When churn-risk count climbs past 100, trigger the Risk Outreach flow." A metric becomes automation.
When not to reach for Alerts
- Heavy automation — multi-step branches or parallel work → build a Flow instead (an alert can trigger one).
- One-off troubleshooting or an ad-hoc question → use Insights or HERC.
- Data-quality tests that belong inside your ELT → use the Metadata Engine's Data Tests.
How an alert evaluates¶
Once a rule is active, Databricks runs it on the rule's schedule. Each evaluation executes the WHEN query, reads a single evaluation column, and compares that value against the IF threshold — leaving the rule either OK or TRIGGERED. When it trips, the THEN actions fire.
flowchart LR
SCH["Schedule<br/>(elapsed interval or wall-clock)"] --> Q["Run WHEN query<br/>Databricks SQL"]
Q --> COL["Read evaluation column<br/>one numeric value"]
COL --> IF{"IF threshold met?<br/>compare vs value"}
IF -->|yes| TRIG(["TRIGGERED"])
IF -->|no| OK(["OK"])
TRIG --> THEN["THEN actions<br/>notify user · notify team<br/>webhook · MS Teams · trigger flow"]
OK -.->|notify on OK, if enabled| THEN
classDef accent fill:#ff8400,stroke:#e67700,color:#ffffff,font-weight:600;
class TRIG accent
Figure 1 — Databricks runs the WHEN query on the rule's schedule, reads one evaluation column, and compares it to the IF threshold. Crossing the threshold marks the rule TRIGGERED and fires the THEN actions; if you enabled notify-on-OK, recovering back to OK sends a heads-up too.
Why teams reach for this
An analyst can stand up a production-grade alert in one sitting — write the SQL, point at a column, set a threshold, choose who gets pinged — without leaving the platform or filing a ticket with data engineering. Every rule carries an owner, an optional review gate, and a full query and execution history, so monitoring stays governed instead of scattered across dashboards and cron jobs.
Concepts¶
| Concept | What it is |
|---|---|
| Alert rule | The full definition: query, threshold, schedule, lifecycle, integration, owner. |
| WHEN | The query — Databricks SQL that returns the column to evaluate. |
| IF | The threshold — a comparison operator (>, <, >=, <=, ==, !=) and a numeric value. |
| THEN | One or more actions — notify user / notify team / webhook / MS Teams / trigger flow. |
| Status | draft → under_review → active → paused → archived (approval activates directly). |
| Sync status | Datahub's view of the alert in Databricks: ok / pending / error. |
| Query history | A persistent log of every preview / test run on this rule (and globally). Scheduled runs appear in Execution history, not here. |
| Execution history | Records from real (scheduled) evaluations. For a Databricks alert that has its own connection, the list is followed by that connection's last stored test (the API and the SQL warehouse). If your role cannot read integrations, a line says the test exists and is not visible to you. Alerts that run through a governed query or a metric do not show this yet. |
| Linked threshold | A threshold from the registry that the rule points at. The detail page shows every band with its severity, the comparison window if it has one, and whether it is archived. For a metric alert the bands decide when it fires, and the rule's own operator and value are not used: the condition reads "matches the linked threshold", and Preview metric judges the value against the same bands the scheduled run uses, naming the band it meets. Under a comparison window the preview shows the Change it judged, in the band's unit. When the metric returns no rows, the alert's When the query returns no rows setting decides, as it does for a SQL alert. When it returns rows but no usable value, or the threshold compares against an earlier period that has no value (or, for a percent change, a value of zero), the preview says the period was not evaluated, because a scheduled run reaches no verdict either; Send test and the message preview then warn that the alert would not send the message now. For any other alert the threshold is linked for reference, and the rule fires on its own IF. |
What Alerts looks like¶
| Surface | Where | What you see |
|---|---|---|
| List | /logic-engine |
DataTable with name, source, workspace, status, state, the linked action list (a link to it, filterable), and last triggered. KPI row, search, filter pills, column customisation. |
| Create | /logic-engine/new |
Five numbered sections — Basics → WHEN (warehouse + query) → IF (threshold) → THEN (actions) → Preview / Submit — each with hints from HERC. |
| Detail | /logic-engine/{id} |
Numbered read-only layout, status controls (Activate / Pause / Submit for review), workflow progress, sync card, query history, recent executions, and a Test alert sidebar. |
| Test alert | Detail → Test alert | Re-runs the rule's query immediately and shows whether it would trigger right now (with the value and row count). |
Setup — what an admin does once¶
| Prereq | Where | Why |
|---|---|---|
| Databricks integration | /admin/integrations → Databricks |
Required — Alerts is Databricks-first. The integration provides host, auth, and a SQL warehouse. |
| AI provider key | /admin/integrations → AI Provider Keys |
Powers the HERC hints in the rule builder. |
| Roles | /rolegroups |
logicengine.rules.read to view; logicengine.rules.write to create / edit / activate / pause / archive. An author needs no integrations role: the connection and channel pickers list the Databricks, Microsoft 365 and Google Workspace connections they may use, and a restricted Databricks connection only to the role groups it is granted to. An alert filed into a domain can be changed only by members of that domain: archiving, restoring, deleting, pausing, resuming and submitting it for review are refused for anyone outside it, an operator pausing or resuming it from the Operations Console included. The refusal names the domain. |
| (Optional) Workflow definition | /admin/workflows |
If you want a review gate before activation, configure a workflow for logicengine_alert_rule. The seeding sets one up by default. |
Building a rule¶
- Basics. Name, description, and integration (which Databricks workspace and warehouse the rule runs against).
- WHEN — define the query. Point at data one of two ways (see the tabs below), then write Databricks SQL in the query editor (syntax-highlighted;
Ctrl+Enterto run). Click Run query — the platform executes it against Databricks (read-only validated,LIMIT 10sample) and returns the result columns. - IF — pick the evaluation column. Choose a column from the dropdown (populated from the query result — no manual typing), then a comparison operator and a numeric threshold value. Toggle notify on OK if you also want a heads-up when the rule recovers. An alert run in Datahub can also compare against another column of the same row, or the percent or absolute change from it. An alert evaluated in Databricks, a catalog alert, a metric alert and an alert that aggregates its rows (a count, a sum, ...) take a fixed value only: Databricks is sent the column, operator and value and compares the value itself, a catalog alert's query returns only its aggregated column, a metric is one value, and an aggregate compares its result with the fixed value wherever it runs. An alert saved with such a condition before this was enforced keeps running as it is, with a warning on its page; its next edit must pick a fixed value, or, in Databricks mode, set Evaluation engine to Run in Datahub to keep the condition. A draft saved that way that never ran cannot be submitted for review or activated until it does. A catalog alert can sum, average, or take the minimum or maximum of a column only when the data asset declares that column a number. The column list shows each column's type under its name (Integer, Decimal, Text, Date, ...), so you can tell before you pick one: Integer and Decimal columns are numbers. On a text or date column those choices are greyed out, with the reason, and picking such a column switches the aggregation to Count. The check goes by the column's type on the data asset, not its values, so to sum a text column that holds numbers, first set that column's type to a number on the data asset. An alert saved before this check keeps its aggregation and shows a warning on its page, and the people its failures would reach are told once (see An aggregation its column cannot take below). Its runs fail as soon as a value is not a number, so change it to Count or to a number column.
- THEN — pick actions. Add as many actions as you want (see the action types below).
- Schedule. Pick a frequency — Every… for elapsed time, or Hourly, Daily, Weekly or Monthly for a wall-clock schedule. See Scheduling a rule below.
- Preview. The inline preview shows what would fire right now: the matched value, the row count, and whether the threshold would trip.
- Submit for review (if a workflow is configured) → the reviewer approves, which activates the rule directly.
- Activate. The platform pushes the rule to Databricks AlertsV2; Databricks owns the schedule and execution from there, while Datahub stays the source of truth for the definition and history.
Choosing what an alert watches¶
Step 2 starts with one choice, What this alert watches:
| Option | What it means |
|---|---|
| SQL query | You write or paste the query, and the alert runs it on the schedule you set. |
| Governed metric | The alert watches a metric from the Metrics module. The metric owns the calculation — there is no query to write here — and the alert only sets the threshold. |
| Governed query | The alert watches a saved query from Insights — it always runs the query's current active version, never a frozen snapshot. See Watching a governed query below. |
An alert made from a card on a semantic model watches that model instead, with no picker: see Watching a semantic model below.
Picking a governed metric is the better choice when the number already exists as a metric: the calculation stays defined in one place, so the alert and every dashboard reading that metric cannot drift apart.
The choice is permanent. An alert's source cannot be changed after it is created — to switch, build a new alert. The page says so beneath the picker.
The metric list includes drafts, each labelled with its status. That is deliberate: a draft metric is a legitimate thing to bind an alert to while both are still being worked on. A draft metric is not yet approved, so check the status hint before relying on it.
What a scheduled metric alert judges
Each run judges the last complete period at the alert's grain, worked out afresh on every run. A monthly month-over-month alert that runs on 3 October judges September against August, never October, which is still filling. The rest comes with it:
- Grain and comparison. From the linked threshold's comparison window when it has one. Otherwise from the Insights card the alert was made from. Otherwise a day against the day before.
- Connection. The one the metric's published version runs on.
- Whose access. The alert's owner, or whoever created it when it has no owner. Each run first checks that this person may still use the connection, and fails with the reason if not (see When a run fails). Preview metric, Send test and the message preview run as you, the person asking.
- The day. The run's date in the alert's schedule timezone.
- The value. Of the most recent period, against that period's own comparison.
Preview metric shows the Period judged. Every run records its period too. A metric or connection set through the API is kept. A period set there is refused with the reason, because no run would read it; set the grain instead. You need access to the metric's connection to create, edit or preview the alert.
Arriving from Insights
Create alert from card on a metric-backed Insights card lands here with the metric already selected. Nothing changes about that flow — the picker simply shows what it chose. The alert takes the card's grain and comparison but not its date range: every run judges the last complete period at that grain.
From a SQL or Data Catalog card, the alert starts on the card's query with the filters the card was showing written into it: the viewer's picks, the dashboard's defaults and its restrictions. A note at the top names those filters, and the alert's description records them. The alert keeps their values, so later changes to the dashboard's filters don't reach it. Date filters are fixed dates: a "Last 30 days" stays on the 30 days before the day you made the alert, and the note says so. Change them in the query to a relative date if the alert should follow the calendar. A metric or saved-query alert can't carry a dashboard's filters; the note names the ones it leaves out, and the alert watches the data they would have narrowed too.
When the card's threshold is an inline rule, Datahub first asks you to save it as a named threshold, which needs permission to manage thresholds. A rule with a comparison window is never turned into a one-shot alert, because a one-shot alert only carries an operator and a value, which it would judge against the metric's own value. On a metric card you save it, and it keeps its window, so the alert judges the same change the card does. When you cannot save thresholds, or the card is not metric-backed (its alert keeps a threshold for reference only), you can also continue without this rule and set the alert's condition yourself. See Thresholds that measure a change.
Three ways to point the WHEN clause at data (when the source is SQL query):
Walk the catalog tree — integration → catalog → schema — to find the table you want to monitor.
Drop full Databricks SQL straight into the query editor.
Toggle to Pick a saved query and choose one of your own or an org-shared saved (governed) query instead of writing SQL directly. The alert pins that query's current version at save time — editing the saved query afterwards never changes what an already-configured alert runs; re-pointing to a newer version is a deliberate edit, not something that happens underneath you.
What pinning means in practice
The alert snapshots the pinned version's SQL when you save. If the query's owner later publishes a new version, your alert keeps running the version it pinned. The builder says so beside the pin, naming both versions ("Pinned to v1 … active version is now v2"), and offers Re-pin to v2: nothing moves until you click it, then run the query and save the alert (on a live alert, the new pin applies once that version of the alert is active). A linked action list keeps its link when you re-pin. A saved query with parameters can't be pinned yet (alerts have no place to put the values); the picker greys those out with why, and the builder offers no re-pin to a new version that takes parameters.
An action list always lists the query's active version. So while the pin is behind, the builder warns that the linked action list can list other rows than the alert counts, and the Create action list dialog says the same before you create one.
Which connection the alert runs on
A saved query keeps a connection so it can be run on its own page. The alert runs the pinned SQL on the alert's own connection (the one chosen in section 1), which may be a different one, for example the same tables in another workspace. When they differ, the builder says so beside the pin, naming both, and warns that a linked action list runs the query on the query's own connection, so its rows can differ from what the alert counts. A new alert with no connection of its own takes the query's; the builder names it, or refuses to save one that is saved on a connection alerts can't run on yet (alerts run on Databricks connections so far). An existing SQL alert's connection can be changed while the alert is a draft or paused (pause an active alert first), and the query then has to run again on the new connection before the alert can go for review or be activated. (A metric or catalog alert runs on its source's connection, so it has none of its own to change.) A paused alert goes back to draft when its connection changes, because it was approved on the old one: activate it again, through review if your organisation requires one. Each version records the connection it was written for, so comparing the moved draft with the approved version shows Connection changing from one connection to the other, by name, and the review task says the version moves the alert from the old connection to the new one. An alert set to a connection alerts can't run on says so.
A pinned alert also gains a Link an action list picker, listing only
action-list dashboards bound to this SAME saved query.
If none exists yet and you hold Insights manage rights, Create action list makes one right
there and links it; otherwise the picker tells you to ask an Insights manager. Linking one
enables the {{action_list_link}} message placeholder, so recipients can jump straight from
the alert to the underlying rows instead of only seeing a table pasted into the notification.
To remove a link, pick the empty entry at the top of the list. If the linked action list is
archived, the alert can't be saved until you pick another one or remove the link.
While a link is set, Create action list stays greyed out — one alert links one action
list; clear the link first to create a different one. After creating one, the confirmation's
Open action list opens it in this tab as a side task of the alert, where it offers a KPI
above its table; Return brings you back to the alert as you left it (see
Building out the action list).
Open action list beside the picker does the same at any time.
Watching a governed query¶
Choosing Governed query as the source binds the alert to a saved query from Insights — your own, or one shared with you. Unlike Pick a saved query above, this is not a pin:
| Pick a saved query (SQL source) | Governed query (its own source) | |
|---|---|---|
| What it runs | The version pinned at save time | Whatever is currently the query's active version |
| A new query version | Names both versions and offers Re-pin; you re-point deliberately | Picked up automatically, next evaluation |
| Query text | Snapshotted onto the alert | Never copied — no query editor to fill in |
| Databricks-native mode | Available | Not available — the rule always runs in-app |
Whose access the query runs with
The query runs with the alert owner's access, and whoever creates the alert is its owner. The alert page shows it as Runs with. Through the API, an owner can be named instead, as long as that person can sign in and may reference the query; pointing an alert that has no owner, and no live version yet, at another governed query makes the person who does it the owner. If the owner can no longer reference the query (it was archived, or its sharing narrowed), each scheduled run fails and says so.
That access ends with the owner's account. When the owner is locked or removed, every run fails, naming them, and Runs with shows Can no longer sign in. Anyone who may edit alerts can click Take ownership: the alert then runs with their access. If the query is private to the person who left, nobody else may run it, so taking the alert over says so: edit the alert, pick a query you can reference and submit that version. Send test, Submit for review, activation and Resume say the same before a run does. An alert with no owner at all shows Take ownership too.
There is no SQL editor, no Run query preview yet, and no environment/integration picker to fill in for this source — the governed query supplies its own connection.
Under the query sits the same Link an action list picker as a pinned alert has, listing the action-list dashboards bound to this governed query. With Insights manage rights, Create action list makes one there. Here the two can never drift apart: the alert and the action list both run the query's current active version. An action list needs an active version to show, so it can only be created once the query has one.
Reviewed together, if needed
You can pick a query that is still a draft — nothing requires it to be active first. If you submit the alert for review while the query is still a draft, the query's own review is brought along in the same approval, so a reviewer sees both at once.
If the query is archived or un-shared later
An active alert whose governed query is later archived by its owner, or un-shared, does not silently go dark. The next evaluation records a visible failed run — check the rule's Execution history — naming that the query is no longer one this alert may reference, so you know to re-point it or contact the owner, rather than wondering why it stopped firing.
Watching a semantic model¶
An alert can also watch one measure of a semantic model. It is not one of the options above: you start it from a card on a dashboard that asks the model a question.
- On the card, click the alert icon (Create alert from this card), then Continue to create alert.
- If the card shows two or more measures, the dialog asks for the Measure to watch: an alert checks its threshold against one value. A card with one measure skips this.
- The alert page opens with the card's question in place. Name the alert, set the threshold and the schedule, and click Save Draft.
Step 2 shows the question read-only: the Measure, the fields it is Split by, and its Filters. Those are the card's own filters plus the dashboard filters it was showing. The note at the top of the page names them, and names any dashboard filter the card could not place, which the alert then watches without. A date filter is kept as the dates it meant that day, and there is no query to change it in. The alert judges every row the question returns: a card that shows only its top rows makes an alert that watches all of them. A card whose filters are too long to bring along (hundreds of picked values) makes no alert, and says so: pick fewer values first.
| Semantic model alert | |
|---|---|
| What it runs | The question, compiled on every run from the model's active published version |
| Query text | None: no SQL editor and no Run query preview |
| Connection | The model's own: no environment or integration picker, and no connection chip on the alert |
| Whose access | The alert's owner, or whoever created it when it has no owner |
| Condition | A fixed value only: each row holds the measure beside the fields it splits by, with no second column to compare against |
| Databricks-native mode | Not available: the rule always runs in-app, on a model on Databricks |
To watch another measure or another question, create a new alert from the card. When a new version of the model no longer has the measure, the next run fails and names it, and the alert's owner is told. Whoever submits or approves that version is warned first: the model page names the alert (see Reports that use a model).
If the page says it could not read the model question, the link was cut off or changed on the way. Save Draft stays greyed out: go back to the card and create the alert again.
Building out the action list, then coming back¶
Open action list does not open a new tab. The list opens in the same tab as a side task of the alert, with a slim bar under the header: You're on a side task for Alert "…". Your changes there are kept. Add a KPI, rename a column, and when you save a card there the bar turns to Done here and its Return button becomes primary. Only a card on that list counts: if you open another action list on the way and add a card to it, the bar still waits. Return brings you back to the alert, exactly as you left it.
sequenceDiagram
actor A as Alert author
participant R as Alert
participant L as Action list
A->>R: Open action list
alt New alert
R->>R: keep the unsaved form in this browser
else Editing an existing alert
R->>R: Save draft and go (saves to the draft)
end
R->>L: same tab, side-task bar shown
A->>L: add a KPI, save it
L-->>A: bar says "Done here"
A->>R: Return
R->>R: form back as you left it (edit: reconciled with any save made meanwhile)
- A new alert is kept in this browser for 7 days. Opening New alert again, by Return, the sidebar or after closing the bar with ×, brings the form back with a note and a Start over button. An alert you started from an Insights card comes back when you start it from that same card again, not from New alert. Starting over never deletes an action list you created: the page says it is still in Insights.
- An existing alert asks Save draft and go first: your edit is saved to the alert's draft (a running alert keeps running its current version), and the editor reopens on your return.
- If someone saved the alert while you were away, the two edits are combined field by field and the page says so. If you both changed the same field, a dialog names it and asks Keep mine or Load theirs; either way everything else either of you changed stays, and nothing is saved until you press Save.
- The list links itself to the alert on your return only if the alert has no link yet and runs the same query. If the alert was archived meanwhile, or you can no longer edit it, the page says so instead of reopening the editor.
When the metric check cannot tell¶
Saving a new alert whose SQL you wrote yourself first asks Does this already exist as a metric? It compares the query with the metrics your dbt project defines. It cannot compare anything when no dbt connection is set up, or when the connection needs a sync first (it was never synced, or its last sync ran before this check existed or did not finish). It says which, and names the connection. With several dbt connections it checks the first one.
- If you manage connections in the Metadata Engine, the check offers Configure a dbt connection (add the connection, then open it and run a sync) or Run a dbt sync. Either opens in this tab as a side task of the alert, the same way as the action list above. When a sync of the connection the check named finishes, the bar turns to Done here, even if you left that page while it ran. Coming from Configure, any connection you sync counts. Return brings the alert back and runs the check again.
- If you do not, the check says that someone who manages connections in the Metadata Engine can fix it, and Skip still saves the alert as written.
Scheduling a rule¶
The schedule reads as one sentence on a single row. The frequency decides the shape, and only the controls that frequency needs appear beside it:
| Frequency | What it means | What you set |
|---|---|---|
| Every… | Elapsed time since the rule's last run, whatever the clock says. | A number and a unit — every 15 minutes, every 6 hours, every 2 weeks. |
| Hourly | A wall-clock cadence, optionally inside a window. | The step (every 1, 2, 4… hours), the first and last hour of the window, the minute, and which weekdays. |
| Daily | Once a day at a fixed time. | Hour and minute. |
| Weekly | On chosen weekdays at a fixed time. | The day chips, hour and minute. |
| Monthly | On one day of the month at a fixed time. | Day of the month, hour and minute. |
The four wall-clock frequencies run in a timezone you pick, so 09:00 means 09:00 where you are and daylight saving moves the run with the clock rather than drifting an hour. Every… has no clock time, so it has no timezone. A plain-language summary under the row states what the pickers add up to, and Show cron expression reveals the underlying cron.
flowchart LR
F["Frequency"] --> I["Every…<br/>elapsed time"]
F --> C["Hourly · Daily<br/>Weekly · Monthly<br/>wall-clock"]
I --> INT["Runs once the<br/>interval has passed"]
C --> CRON["Runs at those times,<br/>in the rule's timezone"]
CRON -.->|if the schedule cannot be read| INT
classDef accent fill:#ff8400,stroke:#e67700,color:#ffffff,font-weight:600;
class F accent
Evaluation polls every 5 minutes, so a run starts within five minutes of its scheduled moment, and nothing can be scheduled to run faster than that.
A schedule authored outside Datahub that these pickers cannot express — a Databricks-native Quartz schedule, or a hand-written cron — is shown as Custom and left alone rather than silently rewritten by opening the form. Its timezone stays editable, and picking any other frequency replaces it.
THEN — the action types:
| Action | Config |
|---|---|
| Notify user | Pick a user. |
| Notify team | Pick a team. |
| Microsoft 365 | Pick an integration and a channel (Teams or Outlook), then optionally write a subject and message template. See message templates below. |
| Google Workspace | Pick an integration and a channel (Google Chat or Gmail), then optionally write a subject and message template — the same templates Microsoft 365 uses. The per-action recipient override is Outlook-only; Google Workspace sends to the channel's own configured recipients. |
| Trigger flow | Pick a flow definition; the alert payload becomes the flow's trigger context. |
| Webhook, MS Teams | Deprecated. Raw HTTP dispatch was retired in favour of governed Microsoft 365 channels. Existing rules keep their config but no longer send. |
One channel that should hear about every alert needs no action here
Adding a Microsoft 365 or Google Workspace action is how you give this rule its own
message, recipients, or .xlsx. If instead you want a single ops channel to receive every alert
Datahub raises, tick All alerts once on that channel, on the integration's Channels tab —
see Microsoft 365 or Google Workspace. It covers rules
written afterwards, and pipeline-run alerts too, with no action to remember.
A channel covered both ways still gets one message per fire: this rule's action, in the format configured here.
Message templates¶
Leave the message template empty and the alert sends a standard narrative (rule name, current value, threshold). For a metric alert whose linked threshold compares against an earlier period, it also states the change that was judged and the period it was measured against, between the value and the threshold ("Change vs a month earlier: -12 %"). A condition that compares the value against another column as a percent or absolute change does the same, naming that column ("Change vs prior_balance: +12 %"), except on an alert evaluated in Databricks, which compares the value itself against the threshold and states no change. Fill it in and you control the message exactly, using {{ }} placeholders:
| Placeholder | Renders |
|---|---|
{{rule_name}}, {{rule_id}} |
The rule's name and id. |
{{rule_link}} |
A link back to the alert in Datahub. It arrives clickable and reads as the alert's name, the same way {{action_list_link}} does: a link that opens a new tab in Outlook and Gmail, and a link in Teams and Google Chat (plain-text mail shows the address). A message that uses it goes out as formatted mail, like one with a table. Inserting it into the message adds the lead-in "Open in Datahub:" before it, which you can reword. In the one-line subject it is the plain address. |
{{action_list_link}} |
A link to this alert's linked action-list dashboard, so recipients can jump straight to the underlying rows. It arrives clickable and reads as the action list's name ("Action List Link: Overdue invoices"): a link that opens a new tab in Outlook and Gmail, and a link in Teams and Google Chat (plain-text mail shows the address). Inserting it, from the placeholder menu or the Insert link warning, adds the lead-in "Action List Link:" before it, which you can reword. The list they land on is never older than the run that sent the message (see cached results). Renders as nothing — not an error, just blank — until the alert runs a saved query (pinned, or watched as a governed query) with a dashboard linked to it. |
{{value}}, {{threshold}} |
The evaluated value and the threshold it was compared against (e.g. > 0). For a metric alert with a linked threshold, {{threshold}} is the band the value met (e.g. > 5 %), in % when the threshold measures a percent change; {{value}} stays the metric's own value, so use {{value_change}} to say what crossed the threshold. A condition compared against another column names that column (> prior_balance), and a percent change condition is in % (> 5 %), except on an alert evaluated in Databricks or one that aggregates its rows: those compared the value itself, and read the plain > 5. When a count, maximum or minimum was worked out from only the first 10,000 rows of a larger result, {{value}} says it is a bound: it ends in + (at least that) or starts with ≤ (at most that). |
{{value_change}} |
The change the alert judged: for a metric alert whose linked threshold compares against an earlier period, the change from that period; for a condition that compares against another column as a percent or absolute change, the change from that column, on the first row that met the condition (and only when one did). It is left empty when that change is not defined: the other column is empty on that row, or a percent change is measured from zero or a negative number. It is written with its sign and in the threshold's unit (-12 %, or +1200 EUR for a change in amount), so "Revenue moved {{value_change}}, past {{threshold}}" reads Revenue moved -12 %, past < -10 %. Rounded to two decimals, with more (up to six) when two would put it on the other side of the threshold (-10.004 %, not -10 %, beside < -10 %). Empty for every other alert; the message preview and Send test warn when a template uses it on one. |
{{triggered_at}} |
When the alert fired, in your organisation's timezone. |
{{Any_Column}} |
That column's value, from the first row that met the threshold. |
{{result_table}} |
The whole query result, as a table. |
{{row_count}}, {{total_rows}} |
How many rows the table carries, and how many the query returned in total. A channel with its own size limit may render fewer than {{row_count}} — the caption under the table always states the number actually sent. An alert reads at most 10,000 rows: when the query matched more and the warehouse could not say how many, {{total_rows}} ends in a + (10000+), so write "{{total_rows}} invoices", not "more than {{total_rows}} invoices". |
Links need your organisation's public address
{{rule_link}} and {{action_list_link}} are built on the address people reach Datahub on. When none is set, a link cannot be built, so the message leaves out each line that holds one, lead-in included, rather than sending "Work through them here:" with nothing after it. The whole line goes, so keep other placeholders off a link's line. A lead-in on the line above counts too, when that line is only your own words ending in a colon. A {{result_table}} on the same line stays. If nothing is left of the message, the standard message is sent instead, under your subject. The message preview and Send test warn when that happens, and in the alert's Execution History each scheduled run it happened to is marked "Its message left out the link line". An administrator sets the address under MCP governance, Public address; the same address is what AI assistants connect to.
{{result_table}} renders as a real table in every channel that can draw one: an HTML table in Outlook and Gmail, an Adaptive Card table in Teams, and a monospace block in Google Chat (which has no table widget — a code block is the only place its columns line up). Write text above and below it and that text keeps its place around the table.
Because a query can return far more rows than anyone wants in a chat message, the action carries a Rows in the table setting — 10, 25, 100, or all — which appears as soon as your template uses {{result_table}}. "All" is capped at 100 rows: the result is stored on every run of the alert, and no channel renders thousands of rows usefully.
The table always says what it is not showing
Whenever rows or columns are left out — by your row cap, by the 100-row ceiling, by a result wider than 12 columns, or by a channel's own message size limit — a line under the table names the total ("Showing 25 of 4,312 rows"). That line counts the rows actually sent: if a Teams card or a Chat message has to be shortened to fit, the number goes down with it and the line says why. A capped table never reads as the complete result. For the full set, follow {{rule_link}} back to the alert.
The first time you pick a channel for an action, Subject and Template are pre-filled with a working example message (using {{rule_name}}, {{triggered_at}}, {{result_table}}, and "Open in Datahub: {{rule_link}}") instead of starting blank, so you see and edit real text immediately rather than guessing what an empty field sends. Picking a different channel afterward, or reopening an alert that already has a message, never overwrites what is already there. Next to each field's label, an Insert placeholder button lists every available {{ }} token with a plain-language description and inserts it at your cursor on click — no need to copy one out of the table above by hand. {{result_table}} is only offered for the Template, since Subject is a single line.
The form warns under the channel when the channel is missing what it sends through: a Teams or Google Chat channel with no webhook, a Gmail channel with no recipients, or an Outlook channel with no recipients of its own while the action's Recipients field is empty. It does not check the channel's sender or whether the integration has that channel type switched on. Ask an integrations admin to complete the channel, or, for Outlook, enter the addresses on the action.
The Message preview panel sits under the template field and shows the composed message as you type. The server composes it with the same code that sends the real alert, so what the panel shows is what the channel receives, table and caption included. Save the rule once before you preview, because the preview runs the rule's own query, whether the alert is built on SQL, a catalog data asset, or a metric. Those rows are reused for five minutes so that typing does not re-run the query on every keystroke; Refresh data fetches them again. Teams and Google Chat shrink a message to fit their size limit, so those two channels can land fewer rows than the preview's caption states, while Outlook and Gmail send it as shown.
If you edit an already-saved alert's query, connection, or condition, the panel keeps showing rows and values from the alert as last saved — a warning names which of the three you changed, and lists them all when you changed more than one — until you save again. Renaming the alert or editing its recipients does not trigger the warning, since neither changes what the alert reads.
Use Send test when you want to confirm delivery rather than wording. It posts the message to the real channel or mailbox, which verifies the integration, the recipients, and how the channel itself renders the result.
If this alert links an action list, Send test also clears that list's cached results before the message goes out, so the {{action_list_link}} in the test message opens rows at least as fresh as the ones the message shows.
Send test covers this alert's own actions, and only those. A channel that subscribed itself to All alerts is deliberately left out: that channel belongs to whoever set it up, and a test is you checking your own wording — fanning every test out to it would page the whole team each time anyone edits a draft. To check that route, send a test from the channel itself on its integration page.
Ask HERC about the alert's SQL
The alert's SQL editor has an Ask HERC button. HERC proposes SQL for you to read and Apply; it never changes the alert itself. Revert to original asks before it replaces your edits. See How HERC edits SQL.
Lifecycle, Databricks sync, and review¶
A rule moves through a governed lifecycle before it ever runs. A configured workflow inserts a review gate between draft and activation; without one, the owner activates straight from draft. Either way, the platform pushes — Databricks executes.
stateDiagram-v2
direction LR
state "Under review" as UnderReview
[*] --> Draft
Draft --> UnderReview: Submit for review
Draft --> Active: Activate (no review gate)
UnderReview --> Active: Reviewer approves<br/>(push to Databricks)
UnderReview --> Draft: Reviewer rejects
Active --> Paused: Pause
Paused --> Active: Reactivate
Paused --> Draft: Change connection
Active --> Archived: Archive<br/>(trash in Databricks)
Paused --> Archived: Archive
classDef accent fill:#ff8400,stroke:#e67700,color:#ffffff,font-weight:600;
class Active accent
Figure 2 — A rule's lifecycle. A configured workflow adds a review gate (draft → under review) before a rule goes live; approval activates it directly. Without one, the owner activates straight from draft. Activation pushes the rule to Databricks AlertsV2, which then owns the schedule; archiving trashes the Databricks alert. Datahub stays the source of truth for the definition and history throughout.
Once a rule is live, each lifecycle event syncs one-way to Databricks:
| Lifecycle event | What syncs |
|---|---|
| Activate | Create / update the alert in Databricks. Sync status = ok if the SDK accepts; error if it rejects (the rule still saves on the platform side; the sync error is shown). |
| Pause | Set the Databricks schedule to paused. |
| Change connection (draft or paused) | Trash the alert in the old Databricks workspace; the next activation creates it on the new one. If the old copy can't be removed (the old workspace is gone, or its credentials no longer work), the move still goes ahead: the copy stays there, the save tells you to delete it, and the audit log names it. |
| Update (active rule) | Re-sync the changes. |
| Archive | Trash the alert in Databricks. An alert whose version is under review has that review ended first, and the reviewer's task closes as cancelled. Only the person who submitted the review, the person or team it is assigned to, or a task administrator can archive it then. |
| Refresh state | Poll Databricks for the latest evaluation state and last-evaluated-at. Manual button on the detail page. |
A background job polls active rules every five minutes to keep state fresh in the platform without an admin clicking Refresh.
How sync failures are handled
A Databricks rejection never blocks you: the rule always saves on the Datahub side, the sync status flips to error, and the Sync card on the detail page shows the SDK message and lets you retry. Datahub and its history stay consistent even while Databricks is unavailable.
Reviewing rules¶
If your tenant configured the review workflow:
- Submit for review on a draft rule creates a task for the reviewer role group.
- The reviewer opens the task → sees the rule details and workflow progress → approves or rejects.
- Approval activates the rule directly (pushing it to Databricks); a rejection returns it to draft.
This is the standard governance pattern — see Workflows and Tasks.
Alerts drafted by an AI agent¶
A connected AI agent (HERC or an MCP client) can draft an alert for you, but it can never put one live. It can create a draft, or build one from a dashboard card with the card's own filters. It can preview the query and the message for a channel, run the alert once without sending anything, and submit the draft for review. It cannot activate an alert, send a notification or approve a review: a person always does that.
flowchart LR
A[Agent drafts the alert] --> B[Agent previews and tests it]
B --> C{{Agent submits for review}}
C --> D[A person reads the draft query and condition]
D -->|approve| E[Alert goes live]
D -->|reject or withdraw| A
classDef accent fill:#ff8400,stroke:#e67700,color:#ffffff,font-weight:600;
class C accent
Figure 3 — An agent-drafted alert. The agent stops at submit; the reviewer sees the draft's own query and condition, and approval is the only way it goes live.
- Channels by name. The agent picks Microsoft Teams or Google Workspace channels from the connections you set up. It cannot type an email address.
- Five minutes at the fastest. An alert evaluates at most every 300 seconds.
- Editing a live alert starts a new draft. The live alert keeps running until a person approves the draft.
- Metadata-only connections. When a connection only shows metadata to agents, the agent saves the query without running it. A person runs it in the alert editor before it goes to review.
Query history¶
Every time someone runs the rule's query from the editor or the detail page — a preview or a Send test — the run is logged with duration, columns returned, row count, and trigger assessment. Scheduled runs are not logged here: their result, and why one failed, is in the rule's Execution history.
- Per-rule history lives in the detail page sidebar.
- Global history is at
/logic-engine/rules/query-history— useful for "who's been hitting Databricks the hardest" triage. It lists your own runs and every run on a saved rule. Another person's preview of a rule not yet saved is not listed, because it holds their query text and filter values. An auditor (activity.auditlog.read) sees every person's runs here, as the audit log already shows them.
OK, TRIGGERED, and recovery¶
Once active, an alert cycles between two evaluation states on every scheduled run. The Test alert sidebar card lets you check that cycle on demand instead of waiting for the next tick.
stateDiagram-v2
direction LR
[*] --> OK: rule activated
OK --> TRIGGERED: an evaluation meets the threshold<br/>THEN actions fire
TRIGGERED --> OK: a later evaluation clears it<br/>notify on OK, if enabled
classDef accent fill:#ff8400,stroke:#e67700,color:#ffffff,font-weight:600;
class TRIGGERED accent
Figure 4 — An active rule cycles between OK and TRIGGERED on each scheduled evaluation. Crossing into TRIGGERED fires the THEN actions; clearing back to OK sends a recovery heads-up only when notify-on-OK is enabled. Real evaluations are kept as execution history.
OK, TRIGGERED, and notify-on-OK
Each scheduled run leaves the rule in one of two states. OK means the evaluation column did not meet the threshold; TRIGGERED means it did, and the THEN actions fire. Turning on notify-on-OK adds a second notification when a previously triggered rule recovers back to OK — useful for closing the loop on an incident.
While triggered, re-notify
Once sends the THEN actions when the rule crosses into TRIGGERED, then stays quiet while it remains there. The next notification comes after the rule has cleared to OK and tripped again. Every run sends them on each scheduled run that meets the threshold. A metric alert offers it as Every new period: each of its runs judges the last complete period, so a daily run of a monthly metric judges the same month about 30 times, and it notifies once for each period that meets the threshold, not again on the later runs that judge that same period. It notifies for the same period again when the period clears to OK and a later run finds it over the threshold again (the data was corrected, or a run found no rows under Treat as OK), when an approved edit makes a new version of the alert judge it, and when the notification for it could not be delivered on any channel, so a failed delivery is tried again on the next run. In the Execution History such a run shows Not sent with the reason beside it: Already notified for this period, or, under Once, Already notified when the condition became true. A failed run has no result, so it leaves the state where it was: under Once, a rule that was TRIGGERED before a failure and still meets the threshold after it is not announced again.
A run whose query returns no rows is judged by When the query returns no rows: with Treat as OK (the default) the rule clears to OK, so the next time it meets the threshold it notifies again. A metric or catalog run that gets rows back but nothing it can judge — no usable value, or no earlier period to compare against — records No verdict in the execution history. That run counts as healthy, so it ends a failing streak, but it leaves OK or TRIGGERED where it was.
Metric and catalog alerts follow their schedule
Metric and catalog alerts used to run on every five-minute poll, whatever their schedule said, sent their THEN actions on every run that met the threshold, and ignored When the query returns no rows. They now run on the schedule set in the builder and follow both settings, as SQL alerts always have. So a metric or catalog alert runs less often than before (daily, unless its author picked another schedule), and the alert list shows its state as OK or TRIGGERED instead of a dash. An alert that already meets its threshold notifies once on its first run after the change, then follows While triggered, re-notify. Alerts created before that setting defaulted to Every run may be set to Once: check it in the alert's Advanced section.
When a run fails¶
A scheduled run that DataHub makes can also fail, whatever the alert is built on. (An alert Databricks evaluates reports its state from Databricks, and its sync status shows when that breaks.)
- SQL or governed query. The connection was removed or can't be reached, the query errors, or it returns more than the 10,000 rows a scheduled run reads and the rows past them decide the answer. A governed-query alert also fails while it has no owner, or while its owner can no longer reference the query, because the query runs with its owner's access.
- Metric. The metric query errors, the metric has no published version with a connection, the alert has no owner or creator to run it as, the one it runs as can no longer sign in (it runs as its owner, else its creator: Take ownership fixes it), it reads a column the metric does not return, or it has no threshold left to compare against.
- Catalog asset. The alert has no data asset or evaluation column, or the catalog query errors. That includes a value the query cannot read as a number, such as a date in a column the alert sums. The reason says so without showing the value, and names the column when it is the only one the query reads as a number.
Every run checks whose access it runs with. Before a SQL, governed-query or metric run queries anything, DataHub checks that the person it runs for, the alert's owner or else whoever created it, may still use the connection the run is about to query. Creating or editing an alert checks the person doing it once; this check covers what changed since: their access to a restricted connection was taken away, the governed query or the metric moved to another connection, or a metric that was still a draft when the alert was made has since been published. A run that fails the check does not query the connection, and fails with a reason that names the person whose access it checked and the connection. A metric or governed query brings its own connection, which is not the one the alert's page shows, so the reason says which it is. Ask an integrations administrator to give that person's role group access to the connection, or give the alert an owner who has it. An alert that has neither an owner nor a recorded creator cannot run either, because there is nobody whose access to check.
A failed run leaves OK or TRIGGERED where it was, so the rule says so in other ways while it is active:
- The alert list shows Failing in the state column. Hover it for the reason. The Failing tile counts these rules, the Triggered tile leaves them out, and the state column's filter lists them.
- The alert's page shows Last run failed in its header, with when it started failing and the reason.
- Someone gets an in-app notification (see below).
- The Execution History keeps each run's reason. Hover a cut-off reason to read all of it.
Who is notified. The rule's owner. When it has none, whoever created it. A rule made before creators were recorded notifies whoever wrote its live version, or else whoever approved it. Only someone who can still sign in is notified: a locked or removed person is skipped, and the next one is told who that was. When nobody in that line can sign in, everyone who may approve alert rules is notified. When nobody may approve them either, the members of the Administrator business role are notified, or the Administrator role group when that role has no members. Each notification says why its reader received it. Only when there is nobody at all to tell does a failure go untold: DataHub logs an error, and tries again on the rule's next failed run.
flowchart LR
F["Run fails"] --> L{"Anyone in the rule's<br/>own line can sign in?"}
L -->|yes| T1(["They are notified"])
L -->|no| A{"Anyone who may<br/>approve alert rules?"}
A -->|yes| T2(["Approvers notified"])
A -->|no| ADM(["Administrator business role,<br/>else Administrator role group"])
ADM -.->|nobody at all| LOG["Error logged,<br/>tried again on the next failed run"]
classDef accent fill:#ff8400,stroke:#e67700,color:#ffffff,font-weight:600;
class ADM accent
Figure 5 — A failing rule's notification goes down its own line (owner, creator, then whoever wrote or approved its live version), then to whoever may approve alert rules, then to the Administrator. Each notification says why its reader received it.
When. One notification when the rule starts failing, and a reminder once a day while it keeps failing. After the first successful run, a running again notification, if someone was told it was failing. There is never more than one failing notification a day, so a rule that keeps switching between failing and succeeding does not notify on every switch. The price: a rule that recovers and fails again within the day is announced again only when the next day's reminder is due.
To stop the notifications, fix the cause, or pause the alert: a paused alert doesn't run, so it can't fail.
An aggregation its column cannot take. A catalog alert that sums, averages, or takes the minimum or maximum of a column its data asset does not declare a number fails as soon as a value in that column is not a number. DataHub checks every catalog alert that is not archived once an hour, paused alerts and drafts included, and tells the same people a failure would (the line above, then whoever may approve alert rules, then the Administrator) once per alert, with a notification that opens it. That covers an alert saved before the builder refused these choices, and one whose column was later changed to text or a date on the data asset. Fix it by switching the aggregation to Count, choosing a number column, or setting the column's type to a number on the data asset. If an alert that was fixed stops fitting again, its people are told again. Administrators see how many alerts are like this on the Administration cockpit (Alerts whose aggregation needs a number column).
Test alert¶
The Test alert sidebar card on the detail page re-runs the rule's query immediately and tells you:
- Would it trigger right now? (yes / no badge)
- What value did the evaluation column return?
- How many rows did the query return overall?
Use this to sanity-check a rule after editing — you don't need to wait for the next scheduled run.
The test runs the rule exactly as a scheduled run does: the same aggregation, the same no-rows setting, and the same 10,000-row limit. Run query in the builder reads only the first 10 rows, to show you the data. Wherever a result is based on fewer rows than decide the answer, the badge reads Not settled by the sample instead of yes or no, and a row count that is only the rows read shows as 10+. When the query returns more rows than a scheduled run reads, the result says so before you activate, because a scheduled run of that rule fails when those rows don't settle the condition. Send test and the message preview warn about the same thing.
Limitations¶
| Limit | Why | Workaround |
|---|---|---|
| Databricks-only execution today. | Phase 1 scope. | A platform-native execution path is on the roadmap. |
| Webhook actions are SSRF-hardened — internal hosts and redirects to internal hosts are blocked. | Security. | Use a public-internet endpoint or a tenant-internal endpoint approved at integration setup. |
| The query must be read-only. | Safety. The platform validates and blocks DDL / DML before execution. | Encapsulate writes behind a flow triggered by the alert. |
| Threshold is numeric. | The IF clause is a single-value comparison. | For multi-value or string conditions, write the condition into the query itself and threshold on a binary column. |
| One evaluation column per rule. | Single-value threshold model. | Split into multiple rules, or fan out via a flow. |
| Sync errors don't block the rule from saving. | We never want Databricks downtime to block authoring. | Watch the sync status card; click Sync to retry. |
Audit & compliance¶
| Question a CISO might ask | Where to look |
|---|---|
| "Who created / edited this rule?" | Detail page metadata; full audit at /admin/audit-log filtered by logicengine. Every create, edit, pause, resume, archive, restore and delete names who did it. |
| "Did the query ever run a write?" | The platform's read-only validator blocks DDL / DML pre-execution; query history shows the actual SQL of every run. |
| "Where do webhook calls go?" | Each action's URL is shown; the SSRF guard blocks internal hosts (and any redirect to one). |
| "Did this rule fire a flow that did something destructive?" | Trigger-flow actions reference the flow definition by name; flow execution history shows what ran. |
| "Who approved this rule?" | Workflow progress card on the detail page → reviewer + comment. |
Troubleshooting¶
| Symptom | Likely cause | Fix |
|---|---|---|
| Sync status shows error after activate | Databricks rejected the alert (auth, warehouse, query syntax). | Open the Sync card → see the SDK message → fix and retry. |
| Preview returns "0 rows" but you expect data | The query is empty for the LIMIT 10 sample. The platform shows the true total row count from Databricks's manifest, not just the sample. |
Check the Total rows badge; revise the WHERE clause. |
| Threshold dropdown empty | You haven't run the query yet. | Click Run query in the WHEN section first. |
| Preview returns silently with no error and 0 rows | The SDK didn't raise, but Databricks reported a query error (e.g. column not found). The platform now surfaces those errors with column suggestions. | Check the inline preview — the actual error and column suggestions are shown. |
| Active rule's last-evaluated time is stale | An alert Datahub evaluates runs on its own schedule (daily unless its author picked another), so a time up to one schedule old is normal. For an alert Databricks evaluates: the 5-minute background poll hasn't ticked yet, or Databricks paused the schedule. | Check the rule's Schedule. For a Databricks alert, click Refresh state. |
| Test alert shows a different value than a scheduled execution | Time-window difference — the test runs now. | Tighten the query's date filter. |
| Webhook action fails | The SSRF guard blocked the URL. | Use a public-internet URL, or open a ticket to allowlist the internal host. |
Arriving from a domain's detail page narrows this list to that domain automatically — a banner names it, with a one-click way back out. See Domains.
See also¶
-
Multi-step automation; an alert often triggers a flow.
-
Same Databricks — build a chart of the metric you alert on.
-
The review gate and reviewer inbox before activation.
-
Wrap an alert rule in a Data Product to link it to a contract.