Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
90 commits
Select commit Hold shift + click to select a range
4ebc8db
docs(actions): add design spec for DQX actions & alerting feature
mwojtyczka Jun 29, 2026
3a762e8
docs(actions): add implementation plan; make action condition optional
mwojtyczka Jun 29, 2026
51cbcbf
docs(actions): rename package action -> actions (plural)
mwojtyczka Jun 29, 2026
bbd5139
docs(actions): make evaluator OCP-clean via TerminalActionError, docu…
mwojtyczka Jun 29, 2026
3ba70e9
docs(actions): drop DBSQLAlert from scope (poor fit for push-on-condi…
mwojtyczka Jun 29, 2026
d832f58
feat(actions): add action errors and config dataclasses
mwojtyczka Jun 29, 2026
a71d237
fix(actions): make Lakebase instance_name required, validate mode
mwojtyczka Jun 29, 2026
cf33287
feat(actions): add safe AST condition evaluator
mwojtyczka Jun 29, 2026
cd0ca29
fix(actions): enforce condition allowlist via full-tree pre-pass, wra…
mwojtyczka Jun 29, 2026
41a2942
feat(actions): add alert message builder
mwojtyczka Jun 29, 2026
c54caae
fix(actions): tighten frozen test, namespace metric fields to avoid k…
mwojtyczka Jun 29, 2026
08dca16
feat(actions): add secret resolver
mwojtyczka Jun 29, 2026
6287487
feat(actions): add Action core types and DQAction
mwojtyczka Jun 29, 2026
af84123
fix(actions): remove avoidable lint suppressions per AGENTS rule #6
mwojtyczka Jun 29, 2026
390b9d7
feat(actions): add webhook delivery client with retry and SSRF guard
mwojtyczka Jun 29, 2026
6a10bf5
fix(actions): remove type-ignores in delivery, fail fast on non-retry…
mwojtyczka Jun 29, 2026
2e0b9a9
feat(actions): add Slack/Teams/generic webhook destinations
mwojtyczka Jun 30, 2026
d5a6217
fix(actions): tighten destination payload types and tests
mwojtyczka Jun 30, 2026
7c74612
feat(actions): add callback alert destination
mwojtyczka Jun 30, 2026
d17f49b
fix(actions): narrow req.data to bytes in delivery test for mypy
mwojtyczka Jun 30, 2026
0908e95
feat(actions): add DQAlert and FailPipeline actions
mwojtyczka Jun 30, 2026
3bc65dd
fix(actions): enforce unique destination names, remove avoidable test…
mwojtyczka Jun 30, 2026
7d012d5
feat(actions): add alert state store and event stores
mwojtyczka Jun 30, 2026
9e00f21
fix(actions): annotate _before_connect_listener return, drop bare-exc…
mwojtyczka Jun 30, 2026
b4f0a91
feat(actions): add action serializer and storage handlers
mwojtyczka Jun 30, 2026
d0d2835
fix(actions): escape run_config_name in replaceWhere, make serializer…
mwojtyczka Jun 30, 2026
22b3601
fix(actions): drop now-stale import-untyped ignore on WebhookClient
mwojtyczka Jun 30, 2026
f672f65
fix(actions): type condition operator dispatch to remove type-ignores
mwojtyczka Jun 30, 2026
6bee4c7
feat(actions): add action evaluator orchestrator
mwojtyczka Jun 30, 2026
3efe573
test(actions): cover evaluator terminal-error ordering and alert-befo…
mwojtyczka Jun 30, 2026
40fcd99
feat(actions): expose public action API via package __init__
mwojtyczka Jun 30, 2026
9d4731c
feat(actions): wire actions into DQEngine batch flow
mwojtyczka Jun 30, 2026
205e813
fix(actions): validate observer in DQEngineCore, clarify batch action…
mwojtyczka Jun 30, 2026
f572e64
feat(actions): evaluate actions per streaming micro-batch
mwojtyczka Jun 30, 2026
51a099b
fix(actions): sanitize evaluator exception text, assert metrics write…
mwojtyczka Jun 30, 2026
5374acc
docs(actions): document actions and alerting feature
mwojtyczka Jun 30, 2026
6256571
fix(actions): address final-review notes
mwojtyczka Jun 30, 2026
ed49b79
fix(actions): close SSRF and condition-DoS gaps from review
mwojtyczka Jun 30, 2026
3fe161f
fix(actions): extract one shared log-sanitizer, fixing evaluator's we…
mwojtyczka Jun 30, 2026
fa24fa9
fix(actions): make evaluator lazy-init and ActionStateStore thread-safe
mwojtyczka Jun 30, 2026
077b07a
fix(actions): fire streaming actions even without a metrics_config
mwojtyczka Jun 30, 2026
55cc9fe
docs(actions): correct STATUS_CHANGE semantics and note streaming del…
mwojtyczka Jun 30, 2026
314ffc4
fix(actions): preserve metrics-observer error message in streaming li…
mwojtyczka Jun 30, 2026
40fb833
test(actions): split SSRF-encoding cases into their own class (pylint…
mwojtyczka Jun 30, 2026
1932d20
feat(actions): persist alert state via optional action_events_config
mwojtyczka Jun 30, 2026
11f9987
Merge branch 'main' into alerting
mwojtyczka Jun 30, 2026
4887836
chore(actions): drop docs/superpowers planning dir and revert CHANGELOG
mwojtyczka Jun 30, 2026
78e5877
fix(actions): migrate action configs to Pydantic and repair merge cor…
mwojtyczka Jun 30, 2026
140fc7d
fix(actions): use timezone.utc instead of datetime.UTC for Python 3.1…
mwojtyczka Jun 30, 2026
ded0435
docs(actions): make generated API docs MDX-safe (docs-build)
mwojtyczka Jun 30, 2026
8bbc32f
test(app): make TestGetOboWs hermetic against ambient Databricks auth
mwojtyczka Jun 30, 2026
42b2a45
test(actions): annotate test functions with -> None to silence mypy a…
mwojtyczka Jun 30, 2026
3f452f9
Merge branch 'main' into alerting
mwojtyczka Jun 30, 2026
558ad6f
refactor(actions): migrate action models to Pydantic v2
mwojtyczka Jun 30, 2026
6ba5a99
refactor(actions): collapse ActionSerializer onto Pydantic model_dump…
mwojtyczka Jun 30, 2026
5fd28fd
test(actions): assert Pydantic construction-time validation
mwojtyczka Jun 30, 2026
554d5ee
Merge branch 'main' into alerting
mwojtyczka Jul 1, 2026
328182c
docs(actions): replace backticks with italics and clear GitGuardian f…
mwojtyczka Jul 1, 2026
ec2f791
feat(actions): add serialize_actions/deserialize_actions helpers and …
mwojtyczka Jul 1, 2026
fd268ab
feat(engine): normalize action dict metadata in DQEngine constructor
mwojtyczka Jul 1, 2026
f3ad40f
test(actions): add unit tests for action metadata API + docs
mwojtyczka Jul 1, 2026
bed1a16
fix(actions): correct wire-format docstring, mixed-list type hint, an…
mwojtyczka Jul 1, 2026
aedcc62
docs(actions): pair YAML+Python metadata examples and fix MDX code fe…
mwojtyczka Jul 1, 2026
a8a4755
test(actions): integration tests for metadata action API
mwojtyczka Jul 1, 2026
70a3633
test: make integration TEST_CATALOG overridable via DQX_TEST_CATALOG
mwojtyczka Jul 1, 2026
c0f6e2b
docs(actions): document action event history and auditing
mwojtyczka Jul 1, 2026
5c3db85
docs(actions): consolidate Python and YAML action examples into Tabs
mwojtyczka Jul 1, 2026
34cdf9f
fix(actions): avoid GitGuardian false positive on webhook credential …
mwojtyczka Jul 1, 2026
27fed4f
docs(actions): document actions and event-history table structures
mwojtyczka Jul 1, 2026
c29d283
docs(actions): place 'Using actions with DQEngine' right after defining
mwojtyczka Jul 1, 2026
232cee1
docs: restructure actions guide, expand README capabilities, drop int…
mwojtyczka Jul 1, 2026
40e571c
docs(actions): lead with define-and-run examples, pair Python/YAML ta…
mwojtyczka Jul 1, 2026
4572b19
docs(readme): move Key capabilities into its own section between Docu…
mwojtyczka Jul 1, 2026
40c889c
docs(readme): move Key capabilities section before Documentation
mwojtyczka Jul 1, 2026
66c7dac
feat(actions): add LogDQAlertDestination and an alerting demo
mwojtyczka Jul 1, 2026
5707a5a
feat(actions): auto-load per-run-config actions in the workflow runner
mwojtyczka Jul 1, 2026
46699f8
feat(actions): scope action events by run config
mwojtyczka Jul 2, 2026
6a9021d
docs(actions): clarify streaming action-evaluation and FailPipeline s…
mwojtyczka Jul 2, 2026
8e12fc3
feat(actions): add NoOpAction (dry-run / audit + test double)
mwojtyczka Jul 2, 2026
e926021
fix(actions): keep status UNHEALTHY on suppressed runs so STATUS_CHAN…
mwojtyczka Jul 2, 2026
c419bb2
fix(actions): address code-review findings (durability, alert conditi…
mwojtyczka Jul 2, 2026
e6a82c8
refactor(actions): drop 'from __future__ import annotations' from the…
mwojtyczka Jul 2, 2026
f2d81d7
fix(streaming): decouple metrics listener from actions to fix SparkSe…
mwojtyczka Jul 3, 2026
8fc69a9
refactor - remove annonations and improve agent instructions
mwojtyczka Jul 3, 2026
d59bac8
updated teams integration and add tests
mwojtyczka Jul 3, 2026
e9c1a2d
updated docs and fix ts issue
mwojtyczka Jul 5, 2026
6e8a3ba
fix(actions): address code-review findings on condition operators and…
mwojtyczka Jul 5, 2026
153ec6c
Merge branch 'main' into alerting
mwojtyczka Jul 16, 2026
fd9a659
Merge branch 'main' into alerting
mwojtyczka Jul 17, 2026
ad6a319
fmt
mwojtyczka Jul 17, 2026
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
7 changes: 7 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,13 @@ model: Any # type: ignore[assignment] — mlflow has no stubs
```
`Any` in `anomaly/` is a known legacy exception. New code outside that module must not introduce it.

**Avoid `from __future__ import annotations`**. Making every annotation a lazy
string hides circular dependencies and heavy-import problems that should fail loudly at import time. Keep
annotations eager. **Quoted forward references** (e.g. `config: "ScoringConfig"`) and `if TYPE_CHECKING:`
imports should generally be avoided too — they defer the same problem one annotation at a time. When you
hit a circular import, prefer to restructure (move the shared type to a module both sides import, or break
the dependency); reach for a `TYPE_CHECKING` import plus a quoted reference only as a last resort, or for a self-reference.

### Docstrings

Use [Google Style Python Docstrings](https://sphinxcontrib-napoleon.readthedocs.io/en/latest/example_google.html) for public functions, classes, and modules. See [Writing Docstrings](https://databrickslabs.github.io/dqx/docs/dev/contributing/#writing-docstrings) for full guidance.
Expand Down
17 changes: 17 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,23 @@ Simplified Data Quality checking at Scale for PySpark Workloads on streaming and
[![PyPI](https://img.shields.io/pypi/v/databricks-labs-dqx?label=pypi%20package&cacheSeconds=3600)](https://pypi.org/project/databricks-labs-dqx/)
![PyPI Downloads](https://static.pepy.tech/personalized-badge/databricks-labs-dqx?period=month&units=international_system&left_color=grey&right_color=orange&left_text=PyPI%20downloads&cacheSeconds=3600)

# ✨ Key capabilities

- **Rule-based quality checks** — 80+ built-in checks (null, range, regex, referential, aggregate, geo, PII, and more) for row-level and column/dataset-level validation, with support for custom check functions.
- **Code or config checks** — define checks programmatically as code or declaratively as YAML/JSON configuration.
- **Check levels** — mark failed checks as warning or error.
- **Custom reactions to failed checks** — drop, mark, or quarantine invalid data flexibly.
- **Detailed failure info** — get detailed insights into why each check failed.
- **AI-assisted rule generation** — LLM-driven rule suggestions from business descriptions, powered by DSPy and Databricks Model Serving.
- **Data profiling & rule generation** — automatic statistics collection and quality rule candidate generation from existing data.
- **ML row anomaly detection** — Isolation Forest–based row anomaly detection with SHAP explanations and AI-generated narratives.
- **Data contracts** — generate quality rules from ODCS data contracts, including schema validation.
- **Summary metrics & quality dashboard** — built-in and custom aggregate metrics (input/error/warning/valid row counts, per-check breakdowns) persisted to Delta tables, with a Lakeview quality dashboard for tracking and identifying data quality issues.
- **Actions and alerting** — automatically send Slack, Microsoft Teams, or generic webhook alerts and/or fail the pipeline when summary metrics cross a threshold.
- **Flexible checks storage** — save and load quality rules from YAML/JSON files, Unity Catalog tables, Volumes, or Lakebase (PostgreSQL).
- **DQX Studio** — browser-based no-code UI for authoring, reviewing, running, and monitoring quality rules, deployed as a Databricks App.
- **Data format agnostic & streaming support** — works with PySpark DataFrames and applies checks to both batch and Spark Structured Streaming (including Lakeflow Pipelines / DLT) using the same API.

# 📖 Documentation

The complete documentation is available at: [https://databrickslabs.github.io/dqx/](https://databrickslabs.github.io/dqx/)
Expand Down
146 changes: 146 additions & 0 deletions demos/dqx_demo_alerting.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
# Databricks notebook source
# MAGIC %md
# MAGIC # Alerting with DQX Actions
# MAGIC
# MAGIC This short demo shows how to react automatically to data quality problems using DQX **actions**. After checks run, DQX evaluates each action's optional *condition* against the observed summary metrics and, when it matches, fires the action — for example sending an alert.
# MAGIC
# MAGIC We use a `LogDQAlertDestination`, which writes the alert to the driver log and contacts no external system, so the demo runs end-to-end anywhere. We also show how to add a Slack destination: supply a Slack incoming-webhook URL in the `slack_webhook_url` widget and the demo will additionally deliver to Slack.
# MAGIC
# MAGIC See the [Actions and Alerting guide](https://databrickslabs.github.io/dqx/docs/guide/actions_and_alerts) for the full reference.

# COMMAND ----------

# MAGIC %md
# MAGIC ## Install DQX

# COMMAND ----------

dbutils.widgets.text("test_library_ref", "", "Test Library Ref")

if dbutils.widgets.get("test_library_ref") != "":
%pip install '{dbutils.widgets.get("test_library_ref")}'
else:
%pip install databricks-labs-dqx

%restart_python

# COMMAND ----------

# Optional: provide a Slack incoming-webhook URL to also deliver alerts to Slack.
# Leave empty to log alerts only (no external calls).
dbutils.widgets.text("slack_webhook_url", "", "Slack Webhook URL")
slack_webhook_url = dbutils.widgets.get("slack_webhook_url")

# COMMAND ----------

# MAGIC %md
# MAGIC ## Create a small dataset with some invalid rows
# MAGIC
# MAGIC Two rows have a null `name` or `age`, so an error-level check will flag them and drive our alert.

# COMMAND ----------

df = spark.createDataFrame(
[
(1, "Alice", 30),
(2, None, 25), # null name -> error
(3, "Bob", None), # null age -> error
(4, "Carol", 40),
],
"id int, name string, age int",
)
display(df)

# COMMAND ----------

# MAGIC %md
# MAGIC ## Define the quality checks
# MAGIC
# MAGIC We require `name` and `age` to be non-null at the error level.

# COMMAND ----------

import yaml

checks = yaml.safe_load(
"""
- criticality: error
check:
function: is_not_null
for_each_column:
- name
- age
"""
)

# COMMAND ----------

# MAGIC %md
# MAGIC ## Configure the alerting action
# MAGIC
# MAGIC Actions require a `DQMetricsObserver` because they evaluate the metrics it collects. Our action fires whenever at least one error row is observed (`error_row_count > 0`) and delivers the alert to the driver log — plus Slack if a webhook URL was provided.

# COMMAND ----------

from databricks.sdk import WorkspaceClient
from databricks.labs.dqx.engine import DQEngine
from databricks.labs.dqx.metrics_observer import DQMetricsObserver
from databricks.labs.dqx.actions import (
DQAction,
DQAlert,
LogDQAlertDestination,
SlackDQAlertDestination,
)

# Always log alerts; add Slack only when a webhook URL is supplied.
destinations = [LogDQAlertDestination(name="driver-log", level="warning")]
if slack_webhook_url:
destinations.append(SlackDQAlertDestination(name="slack", webhook_url=slack_webhook_url))

actions = [
DQAction(
condition="error_row_count > 0",
action=DQAlert(destinations=destinations),
)
]

observer = DQMetricsObserver(name="alerting_demo")
engine = DQEngine(WorkspaceClient(), observer=observer, actions=actions)

# COMMAND ----------

# MAGIC %md
# MAGIC ## Apply the checks and evaluate the actions
# MAGIC
# MAGIC After applying checks we trigger a Spark action (`count()`) to materialize the observed metrics, then call `evaluate_actions`. The returned results describe which actions fired; the alert itself is written to the driver log (look for the `[DQX alert]` line above the cell output).

# COMMAND ----------

checked_df, observation = engine.apply_checks_by_metadata(df, checks)

# Materialize the observation so metrics are populated.
checked_df.count()

results = engine.evaluate_actions(observation.get, input_location="in-memory demo dataframe")

for result in results:
print(f"action={result.action_name} fired={result.fired} status={result.status.value}")

# COMMAND ----------

# MAGIC %md
# MAGIC ## Wiring a real Slack alert
# MAGIC
# MAGIC To deliver to Slack, create a [Slack incoming webhook](https://api.slack.com/messaging/webhooks) and pass its URL to the `slack_webhook_url` widget above (delivery is restricted to `hooks.slack.com`). In production, store the URL in a Databricks secret scope and reference it with `DQSecret` rather than passing a plaintext string:
# MAGIC
# MAGIC ```python
# MAGIC from databricks.labs.dqx.config import DQSecret
# MAGIC from databricks.labs.dqx.actions import SlackDQAlertDestination
# MAGIC
# MAGIC SlackDQAlertDestination(
# MAGIC name="slack",
# MAGIC webhook_url=DQSecret(scope="dq-secrets", key="slack-webhook-url"),
# MAGIC )
# MAGIC ```
# MAGIC
# MAGIC You can also attach actions directly to `apply_checks_and_save_in_table` so they fire automatically after each save (batch or streaming) — see the guide for details.
1 change: 1 addition & 0 deletions docs/dqx/docs/demos.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ Import the following notebooks in the Databricks workspace to try DQX out:
* [DQX Intermediate Demo Notebook](https://github.com/databrickslabs/dqx/blob/v0.15.0/demos/dqx_intermediate_demo_library.py) - intermediate-level DQX usage as a library.
* [DQX Comprehensive Demo Notebook](https://github.com/databrickslabs/dqx/blob/v0.15.0/demos/dqx_demo_library.py) - comprehensive DQX usage as a library.
* [DQX Demo Notebook for Data Quality Summary Metrics](https://github.com/databrickslabs/dqx/blob/v0.15.0/demos/dqx_demo_summary_metrics.py) - demonstrates how to generate summary-level data quality metrics when validating data with DQX.
* [DQX Demo Notebook for Actions and Alerting](https://github.com/databrickslabs/dqx/blob/v0.15.0/demos/dqx_demo_alerting.py) - demonstrates how to react to data quality problems by firing alerts (driver log, with optional Slack) when summary metrics cross a threshold.
* [DQX Demo Notebook for Profiling and Applying Checks at Scale on Multiple Tables](https://github.com/databrickslabs/dqx/blob/v0.15.0/demos/dqx_multi_table_demo.py) - demonstrates how to use DQX as a library at scale to apply checks on multiple tables.
* [DQX Demo Notebook for Row Anomaly Detection](https://github.com/databrickslabs/dqx/blob/v0.15.0/demos/dqx_row_anomaly_detection_demo.py) - comprehensive demo showing how to use DQX Row Anomaly Detection to detect unusual patterns in your data.
* [DQX Demo Notebook for AI-assisted checks generation](https://github.com/databrickslabs/dqx/blob/v0.15.0/demos/dqx_demo_ai_assisted_checks_generation.py) - demonstrates how to generate DQX rules/checks with LLM using natural language.
Expand Down
Loading
Loading