A programmable alerting system that periodically runs user-defined Python functions and sends notifications based on their result
Caution
You will likely want to fork the repo when using it as its not very configurable, specifically alert channels.
- Decorator-based alerts: Register alert functions with the
@alertdecorator - Cron scheduling: Use familiar cron syntax for flexible scheduling
- Edge-triggered alerting: Alerts only fire on False → True transitions (prevents spam)
- Alert channels: Extensible system supports Discord, email, console, and custom channels
- SQLite state tracking: Maintains alert history and state for deduplication
- Metadata support: Return rich metadata from alert functions for detailed notifications
- With uv:
uv sync- Edit
config.yamlwith your settings.
Create alert functions in a Python file (e.g., my_alerts.py) and place it in the alerts directory:
from scheduler import alert
@alert(cron="*/5 * * * *", channels=["email"])
def check_server_status():
"""Check if server is responding every 5 minutes."""
import requests
try:
response = requests.get("https://myserver.com/health", timeout=5)
is_down = response.status_code != 200
return {
'alert': is_down,
'message': f'Server returned status {response.status_code}',
'subject': 'Server Down Alert'
}
except Exception as e:
return {
'alert': True,
'message': f'Server unreachable: {e}',
'subject': 'Server Unreachable'
}
@alert(cron="0 9 * * MON", channels=["email", "console"])
def weekly_report():
"""Send weekly report every Monday at 9 AM."""
error_rate = calculate_error_rate()
return {
'alert': error_rate > 0.05,
'message': f'Weekly error rate: {error_rate:.2%}',
'error_rate': error_rate
}uv run python main.pyAlert functions can return:
- Boolean: Simple true/false
return True # Alert will fire- Dictionary (recommended): Rich metadata
return {
'alert': True, # Required: whether to alert
'message': 'Custom message', # Included in notification
'subject': 'Email subject', # Email subject line
'severity': 'high', # Any custom metadata
'value': 123
}Extend AlertChannel in alert_channels.py:
class SlackAlert(AlertChannel):
def __init__(self, webhook_url):
self.webhook_url = webhook_url
def send_alert(self, function_name, metadata, timestamp):
# Implement Slack webhook logic
passRegister in main.py:
channels['slack'] = SlackAlert(webhook_url="...")alert_state: Tracks current state of each alert
function_name: Alert function namelast_result: Last boolean resultlast_alert_time: When alert was last sentlast_run_time: When function last executedlast_metadata: Metadata from last run
alert_history: Complete execution log
- All executions with timestamps, results, and metadata
MIT