Monitoring MLflow in Production
MLflow is the de-facto standard for ML experiment tracking, but "MLflow is down" in a production MLOps environment means your model training pipelines are silently failing, artifact uploads are being dropped, and your model registry is inaccessible to serving infrastructure. This guide covers how to monitor every critical MLflow component and wire up external uptime checks with Vigilmon.
MLflow's Critical Components
MLflow in production typically has three separate services:
- Tracking server — the HTTP API that your training jobs call to log metrics, parameters, and tags
- Artifact store — S3, GCS, Azure Blob, or a local filesystem path where models and files are stored
- Model registry — a subset of the tracking server API for managing model versions and stages
Each can fail independently. Training jobs can appear to run while silently swallowing connection errors. Your model serving infra can go stale because the registry is unreachable. The artifact store can become a bottleneck when large model files are being uploaded.
1. Tracking Server Health
The MLflow tracking server exposes a health endpoint:
curl -s http://localhost:5000/health
# "OK"
This confirms the Flask/Gunicorn process is alive and the backend database (SQLite, Postgres, or MySQL) is reachable.
For a more detailed check, hit the experiments list API:
curl -s http://localhost:5000/api/2.0/mlflow/experiments/search \
-H "Content-Type: application/json" \
-d '{"max_results": 1}'
A 200 response with a JSON body means the tracking server is fully functional — Flask is running, the database is reachable, and the API layer is serving requests.
Database backend check
If you're using Postgres as the MLflow backend store:
# Quick connectivity check
psql -h localhost -U mlflow -d mlflow -c "SELECT COUNT(*) FROM experiments;"
Slow results here (>500ms) indicate database saturation from concurrent training jobs.
2. Artifact Store Health
The artifact store is often the silent point of failure. Training jobs upload checkpoints and model files during training — if the store is down or throttled, jobs fail at save time, not at the start.
S3 artifact store
# Check bucket accessibility
aws s3 ls s3://your-mlflow-artifacts/ --max-items 1
# Check upload latency with a small test object
echo "health-check" | aws s3 cp - s3://your-mlflow-artifacts/.health
aws s3 rm s3://your-mlflow-artifacts/.health
Local filesystem artifact store
#!/bin/bash
ARTIFACT_ROOT="/opt/mlflow/artifacts"
# Check writable and accessible
if [ -d "$ARTIFACT_ROOT" ] && touch "$ARTIFACT_ROOT/.health_check" 2>/dev/null; then
rm -f "$ARTIFACT_ROOT/.health_check"
echo "ok"
exit 0
else
echo "artifact store not writable"
exit 1
fi
Wrap this in a simple HTTP endpoint (a 5-line FastAPI app works well) and expose it at /artifact-health for external monitoring.
3. Model Registry API
The model registry is accessed via MLflow's REST API. Check it directly:
# List registered models
curl -s "http://localhost:5000/api/2.0/mlflow/registered-models/list?max_results=1"
A 200 with a valid JSON body confirms the model registry is operational. This endpoint exercises the same database backend as the tracking server but tests a different code path that's essential for model serving infrastructure.
Python health check
For Python-based health probes that you can run as a sidecar or cron job:
import mlflow
import sys
def check_mlflow_health(tracking_uri: str) -> bool:
try:
client = mlflow.tracking.MlflowClient(tracking_uri=tracking_uri)
# Try to list experiments — exercises DB + API
experiments = client.search_experiments(max_results=1)
return True
except Exception as e:
print(f"MLflow health check failed: {e}", file=sys.stderr)
return False
if __name__ == "__main__":
healthy = check_mlflow_health("http://localhost:5000")
sys.exit(0 if healthy else 1)
Run this from a cron job every minute, or wire it into a /health HTTP endpoint in your MLflow deployment.
4. Metrics to Track
Beyond simple up/down status, instrument these metrics for capacity planning and anomaly detection:
# Add to your training pipeline to track experiment creation latency
import time
import mlflow
start = time.time()
with mlflow.start_run():
mlflow.log_metric("latency_probe", 1.0)
latency_ms = (time.time() - start) * 1000
if latency_ms > 5000: # 5 second threshold
# Alert or log warning
print(f"WARNING: MLflow run creation took {latency_ms:.0f}ms")
Key metrics to monitor:
| Metric | Normal | Alert threshold |
|---|---|---|
| /health response time | <100ms | >1000ms |
| Run creation latency | <500ms | >5000ms |
| Artifact upload throughput | Baseline × 0.5 | Baseline × 0.1 |
| Model registry list latency | <200ms | >2000ms |
| Active experiment count | Stable | Sudden drop |
5. Log Analysis for Silent Failures
MLflow's default logging doesn't surface artifact upload failures well. Enable structured logging:
# mlflow_config.py
import logging
logging.basicConfig(
level=logging.INFO,
format='{"time": "%(asctime)s", "level": "%(levelname)s", "message": "%(message)s"}'
)
Then watch for patterns that indicate silent failures:
# Watch for artifact upload failures in real time
tail -f /var/log/mlflow/mlflow.log | grep -E "(ERROR|artifact|upload|store)"
# Count errors per minute
grep "ERROR" /var/log/mlflow/mlflow.log | grep "$(date '+%Y-%m-%d %H:%M')" | wc -l
6. Integrating Vigilmon for External Uptime Checks
Internal checks miss network-level failures, DNS issues, and load balancer problems. Vigilmon provides external uptime monitoring that checks your MLflow endpoints from outside your infrastructure.
Step 1: Set up the tracking server monitor
In Vigilmon, create an HTTP monitor:
- URL:
https://mlflow.yourdomain.com/health - Method: GET
- Expected status: 200
- Expected body contains:
OK - Check interval: 60 seconds
- Locations: Select 3+ geographic regions for global coverage
Step 2: Monitor the model registry API
Create a second monitor targeting the registry endpoint:
- URL:
https://mlflow.yourdomain.com/api/2.0/mlflow/registered-models/list?max_results=1 - Method: GET
- Expected status: 200
- Check interval: 2 minutes
Step 3: Artifact store proxy health check
Expose a proxy health check endpoint in your MLflow deployment (a custom Flask route or sidecar):
from flask import Flask, jsonify
import boto3
app = Flask(__name__)
@app.route("/artifact-health")
def artifact_health():
try:
s3 = boto3.client("s3")
s3.head_bucket(Bucket="your-mlflow-artifacts")
return jsonify({"status": "ok"}), 200
except Exception as e:
return jsonify({"status": "error", "detail": str(e)}), 503
Then add a Vigilmon monitor:
- URL:
https://mlflow.yourdomain.com/artifact-health - Method: GET
- Expected status: 200
- Check interval: 5 minutes
Step 4: Configure alert escalation
# Vigilmon alert configuration
monitors:
- name: "MLflow Tracking Server"
interval: 60
alerts:
- channel: pagerduty
severity: critical
after_failures: 2
- name: "MLflow Model Registry"
interval: 120
alerts:
- channel: slack
severity: high
after_failures: 3
- name: "MLflow Artifact Store"
interval: 300
alerts:
- channel: email
severity: medium
after_failures: 2
7. Setting Up a Status Page
If you have internal stakeholders (data scientists, ML engineers, product teams) who depend on MLflow, a status page prevents repeat "is MLflow down?" Slack messages. In Vigilmon, group your MLflow monitors into a single status page and share the URL with your organization.
Alerting on Degradation, Not Just Downtime
MLflow can degrade without going fully down. Watch for these degradation signals:
- Response time creep: P95 latency on
/healthrising from 50ms to 800ms indicates DB saturation - Artifact upload errors: 5xx responses on artifact upload endpoints during peak training hours
- Registry version drift: Model versions not updating in the registry while training jobs succeed
With Vigilmon's response time monitoring enabled, you can set threshold alerts at 2× and 5× baseline to catch these before they become full outages. Your ML pipelines will be more reliable, and your on-call team will spend less time fire-fighting MLflow issues.