Featured image of post Build an Automated Data Monitoring & Alert System with DuckDB + Cron

Build an Automated Data Monitoring & Alert System with DuckDB + Cron

Learn how to build a fully automated data health monitoring system using DuckDB, Python, and Telegram Bot API. Detect anomalies in real-time and get instant notifications—zero cost.

Build an Automated Data Monitoring & Alert System with DuckDB + Cron

Do you ever face this pain point—your business data grows every day, but you have no idea when something goes wrong. By the time your customers complain, the damage is already done.

Today I’ll show you how to build a fully automated Data Health Monitoring System using DuckDB. It runs queries on a schedule, detects anomalies, and sends instant Telegram alerts. No complex ETL, no expensive monitoring tools—just a Python script + DuckDB.

DuckDB Data Monitoring & Alert System Architecture

1. Why Do You Need Data Monitoring?

Let’s clarify the value first. Why build a monitoring system?

  • E-commerce: GMV drops 30% overnight—you need to catch it before customers place orders, not discover it the next day from reports
  • Finance: A stock breaks through a key level with high volume—push the signal to subscribers instantly
  • SaaS: User registrations drop for 3 consecutive days—something is broken in your product
  • Content: A video’s views spike unexpectedly—catch the trend while it’s hot

The common thread: fast detection, accurate alerts, minimal cost.

DuckDB’s role in this system: it’s not a database—it’s a query engine. It reads directly from CSV/Parquet/API files, runs one SQL query to find anomalies, and hands results to Telegram for delivery.

2. System Architecture

CSV/Parquet Data Sources
 ↓
 DuckDB (Query Engine)
 ↓
 Python Anomaly Detection
 ↓
 Telegram Bot API
 ↓
 Real-time Mobile Notifications

Everything runs in Python with zero external service dependencies. Data is stored in a single .duckdb file with incremental appends.

3. Core Monitoring Logic

Let’s say you’re an e-commerce seller tracking three core metrics:

  • Daily order volume anomalies
  • Sustained decline in average order value
  • Sudden spikes in refund rate

Your data source is daily order CSV exports. Here’s the DuckDB monitoring query:

import duckdb
import json
from datetime import datetime, timedelta

con = duckdb.connect("monitor.duckdb")

# Merge historical orders into a persistent table (one-time import)
con.execute("""
 CREATE TABLE IF NOT EXISTS orders AS
 SELECT * FROM read_csv_auto('orders_2024*.csv')
""")

# Monitor query: compute core metrics for the past 14 days
def check_health():
 today = datetime.now().date()
 
 result = con.execute("""
 WITH daily_stats AS (
 SELECT
 DATE(order_date) AS stat_date,
 COUNT(*) AS order_count,
 ROUND(AVG(amount), 2) AS avg_order_value,
 ROUND(SUM(CASE WHEN status = 'refunded' THEN 1 ELSE 0 END) * 100.0 / COUNT(*), 2) AS refund_rate
 FROM orders
 WHERE DATE(order_date) >= CURRENT_DATE - INTERVAL '14' DAY
 GROUP BY DATE(order_date)
 )
 SELECT
 MAX(CASE WHEN stat_date = CURRENT_DATE - INTERVAL '1' DAY THEN order_count END) AS yesterday_orders,
 AVG(order_count) OVER (ORDER BY stat_date ROWS BETWEEN 6 PRECEDING AND 1 PRECEDING) AS ma7_orders,
 MAX(CASE WHEN stat_date = CURRENT_DATE - INTERVAL '1' DAY THEN refund_rate END) AS yesterday_refund_rate,
 AVG(refund_rate) OVER (ORDER BY stat_date ROWS BETWEEN 6 PRECEDING AND 1 PRECEDING) AS ma7_refund_rate
 FROM daily_stats
 ORDER BY stat_date DESC
 LIMIT 1
 """).fetchone()
 
 return {
 'yesterday_orders': result[0],
 'ma7_orders': result[1],
 'yesterday_refund_rate': result[2],
 'ma7_refund_rate': result[3]
 }

Key points:

  1. read_csv_auto('orders_2024*.csv') — DuckDB supports wildcards to read multiple files at once, no manual concatenation needed
  2. Window function AVG(...) OVER (...) — Computes 7-day moving average without pre-aggregation
  3. Results persist in .duckdb file — Incremental append, not full rebuild each time

4. Anomaly Detection Algorithm

With baseline metrics in hand, the next step is determining whether something is actually abnormal.

We use a simple statistical approach: if the current value deviates from the 7-day average beyond a threshold, flag it as anomalous.

def detect_anomalies(stats):
 """Returns a list of anomalies, each with metric name, current value, expected range, and severity."""
 anomalies = []
 
 # Order volume anomaly
 if stats['ma7_orders'] > 0:
 order_drop = (stats['yesterday_orders'] - stats['ma7_orders']) / stats['ma7_orders']
 if order_drop < -0.20: # Drop exceeds 20%
 anomalies.append({
 'metric': 'Orders',
 'value': stats['yesterday_orders'],
 'expected': f"~{stats['ma7_orders']:.0f}",
 'severity': '🔴 Critical',
 'message': f"Yesterday's orders: {stats['yesterday_orders']}, down {abs(order_drop)*100:.1f}% from 7-day avg"
 })
 elif order_drop > 0.50: # Surge exceeds 50%
 anomalies.append({
 'metric': 'Orders',
 'value': stats['yesterday_orders'],
 'expected': f"~{stats['ma7_orders']:.0f}",
 'severity': '🟡 Attention',
 'message': f"Yesterday's orders: {stats['yesterday_orders']}, up {order_drop*100:.1f}% from 7-day avg—verify if this is a legitimate promotion"
 })
 
 # Refund rate anomaly
 if stats['ma7_refund_rate'] > 0:
 refund_spike = (stats['yesterday_refund_rate'] - stats['ma7_refund_rate']) / stats['ma7_refund_rate']
 if refund_spike > 0.50: # Refund rate surges 50%
 anomalies.append({
 'metric': 'Refund Rate',
 'value': f"{stats['yesterday_refund_rate']:.2f}%",
 'expected': f"~{stats['ma7_refund_rate']:.2f}%",
 'severity': '🔴 Critical',
 'message': f"Yesterday's refund rate: {stats['yesterday_refund_rate']:.2f}%, up {refund_spike*100:.1f}% from 7-day avg"
 })
 
 return anomalies

Benefits of this approach:

  • Tunable thresholds (-0.20, 0.50)—adjust based on business sensitivity
  • Detects both drops and surges in a single pass
  • Structured output—easy to push via Telegram or log to file

5. Telegram Push Module

Use Python’s requests library to call the Telegram Bot API and push anomaly alerts to a channel or group.

import requests

TELEGRAM_BOT_TOKEN = "YOUR_BOT_TOKEN"
CHAT_ID = "YOUR_CHAT_ID" # Group ID or channel ID

def send_telegram(message):
 url = f"https://api.telegram.org/bot{TELEGRAM_BOT_TOKEN}/sendMessage"
 payload = {
 'chat_id': CHAT_ID,
 'text': message,
 'parse_mode': 'HTML'
 }
 try:
 r = requests.post(url, json=payload, timeout=10)
 return r.json().get('ok', False)
 except Exception as e:
 print(f"Push failed: {e}")
 return False

def notify_anomalies(anomalies):
 if not anomalies:
 send_telegram(
 f"✅ <b>Daily Data巡检 Complete</b>\n\n"
 f"📅 {datetime.now().strftime('%Y-%m-%d')}\n"
 f"All metrics normal. No action needed.\n\n"
 f"— DuckDB Monitor Bot"
 )
 return
 
 lines = [
 f"🚨 <b>Data Anomaly Alert</b>",
 f"📅 {datetime.now().strftime('%Y-%m-%d %H:%M')}",
 ""
 ]
 
 for a in anomalies:
 lines.append(f"{a['severity']} {a['metric']}")
 lines.append(f" Current: {a['value']}")
 lines.append(f" Expected: {a['expected']}")
 lines.append(f" {a['message']}")
 lines.append("")
 
 lines.append("--- DuckDB Monitor Bot")
 
 send_telegram("\n".join(lines))

6. Complete Script & Cron Scheduling

Now combine everything into a complete monitoring script:

import os
import glob
import json
from datetime import datetime

def incremental_update():
 """Incremental update: only import new CSV files"""
 today_str = datetime.now().strftime('%Y%m%d')
 new_files = glob.glob(f'orders_{today_str}*.csv')
 
 if not new_files:
 print("No new data files today")
 return
 
 for f in new_files:
 count = con.execute(f"SELECT COUNT(*) FROM read_csv_auto('{f}')").fetchone()[0]
 con.execute(f"""
 INSERT INTO orders
 SELECT * FROM read_csv_auto('{f}')
 WHERE order_id NOT IN (SELECT order_id FROM orders)
 """)
 print(f"Imported {f}: {count} records")

def main():
 # 1. Incremental data update
 incremental_update()
 
 # 2. Run health check
 stats = check_health()
 anomalies = detect_anomalies(stats)
 
 # 3. Push results
 notify_anomalies(anomalies)
 
 # 4. Log today's run
 log_entry = {
 'date': datetime.now().strftime('%Y-%m-%d'),
 'anomalies': len(anomalies),
 'stats': stats
 }
 with open('monitor_log.jsonl', 'a') as f:
 f.write(json.dumps(log_entry, ensure_ascii=False) + '\n')
 
 print(f"巡检 complete. Found {len(anomalies)} anomalies")

if __name__ == '__main__':
 main()

Schedule with cron (Linux):

# Run automatically at 9 AM every day
0 9 * * * cd /home/user/duckdb-monitor && python3 monitor.py >> monitor.log 2>&1

Or use macOS launchd or Windows Task Scheduler—the principle is the same.

7. Advanced: Multi-Source Cross-Database Monitoring

Real-world monitoring often requires crossing data sources. Your e-commerce data is in Shopify API, logistics data is in a JSON file, and financial data is in Excel.

DuckDB’s strength shines here—you don’t need to ETL everything into one database first. Just ATTACH different sources:

# Attach: Shopify orders (CSV)
con.execute("ATTACH 'shopify_orders.csv' AS shopify (READ_ONLY)")

# Attach: Logistics data (JSON)
con.execute("ATTACH 'logistics.json' AS log (READ_ONLY, TYPE JSON)")

# Attach: Financial data (Excel)
con.execute("ATTACH 'finance.xlsx' AS fin (READ_ONLY)")

# Cross-source query: find SKUs with late shipping AND high refund rates
con.execute("""
 SELECT 
 s.sku,
 s.product_name,
 s.order_count,
 AVG(l.transit_days) AS avg_transit,
 SUM(CASE WHEN f.status = 'refunded' THEN 1 ELSE 0 END) AS refund_count
 FROM shopify.orders s
 LEFT JOIN log.packages l ON s.tracking_number = l.tracking_id
 LEFT JOIN fin.refunds r ON s.order_id = r.order_id
 GROUP BY s.sku, s.product_name
 HAVING avg_transit > 7 AND refund_count > 5
 ORDER BY refund_count DESC
""").fetchdf()

ATTACH is one of DuckDB’s most underrated features. It lets you query CSV, JSON, Excel, Parquet, PostgreSQL, MySQL, and more—in a single query—without any ETL preprocessing.

8. Comparison with Traditional Monitoring Tools

FeatureDuckDB + PythonGrafana + PrometheusCommercial SaaS (Datadog)
Data source accessDirect CSV/JSON/Excel readRequires Exporter agentsAPI integration, complex config
Anomaly detectionCustom Python logicAlert rule configurationBuilt-in AI anomaly detection
Push notificationsTelegram Bot APISlack/PagerDutyMulti-channel
Deployment cost$0 (local/VPS)Self-hosted infrastructure/node/month
Learning curvePython + SQLHighMedium
CustomizationFully controllableMediumLow
Best forSMBs, indie developersLarge infra teamsEnterprise

10. Summary

ComponentTechnologyCost
Data queryingDuckDB (Python API)Free
Data storageSingle .duckdb fileFree
Anomaly detectionPython logic + SQL window functionsFree
Push notificationsTelegram Bot APIFree
SchedulingLinux cron / cloud VPSFree
Total cost$0

Compared to commercial monitoring tools (Grafana + PagerDuty, thousands to tens of thousands annually), this approach is functionally competitive at zero cost.

Remember: The essence of monitoring isn’t technology—it’s the awareness to catch problems before they cascade. DuckDB just makes it trivially simple.


📖 Full runnable code (including multi-source ATTACH examples, Telegram template, and cron configuration guide) is available at duckdblab.org, with complete step-by-step deployment instructions.

💡 Want to systematically learn DuckDB for monitoring, automation, and data products? duckdblab.org has a complete tutorial series.


本文信息

项目内容
DuckDB 版本v1.5.x(部分功能基于 v2.0 Preview)
最后验证2026-09-12
测试环境Linux / x86_64 / 16GB RAM
官方文档DuckDB Documentation
GitHubpengzz9527/duckdb-blog

如发现错误,欢迎通过 GitHub Issue 或邮件 contact@duckdblab.org 反馈。

📺 Watch video tutorials → Olap Studio YouTube

Subscribe for more DuckDB & AI automation tutorials