Google Cloud Dataflow is a fully managed service for running Apache Beam pipelines at scale — both streaming (real-time event processing) and batch (large-scale data transforms). It's reliable, but streaming jobs can fall behind on event processing, batch jobs can fail partway through large datasets, and GCP's built-in alerting requires CloudMonitoring policies that teams often configure too broadly or not at all. Vigilmon gives you a focused external health check that confirms your Dataflow jobs are healthy without wading through the GCP console.
What You'll Set Up
- Cron heartbeat monitors to confirm batch Dataflow jobs complete on schedule
- HTTP endpoint monitor backed by a Cloud Run service for streaming job health
- Watermark lag alerting for streaming pipelines
- Alert channels for job failures and processing lag
Prerequisites
- A Google Cloud project with at least one Dataflow job (batch or streaming)
gcloudCLI installed and authenticated- A free Vigilmon account
Step 1: Add a Heartbeat Monitor for Batch Dataflow Jobs
Batch Dataflow jobs have a defined start and end. If a batch job fails or never starts, there's no external signal. Set up a Vigilmon heartbeat to confirm each batch job completes on schedule.
- Log in to vigilmon.online and click Add Monitor.
- Select Cron Heartbeat as the monitor type.
- Name it after your job: e.g.,
dataflow-daily-aggregation. - Set the expected ping interval to match your job's schedule (e.g.,
1440minutes for a daily batch run). - Copy the heartbeat URL:
https://vigilmon.online/heartbeat/abc123. - Click Save.
Step 2: Ping Vigilmon at the End of Each Batch Pipeline
Apache Beam pipelines are Java, Python, or Go programs. Add a Vigilmon ping at the end of the pipeline's successful completion path.
Python (Apache Beam)
import apache_beam as beam
import urllib.request
def run_pipeline():
options = beam.options.pipeline_options.PipelineOptions(
runner="DataflowRunner",
project="my-gcp-project",
region="us-central1",
temp_location="gs://my-bucket/temp",
)
with beam.Pipeline(options=options) as p:
(
p
| "ReadFromBigQuery" >> beam.io.ReadFromBigQuery(query="SELECT ...")
| "Transform" >> beam.Map(my_transform_fn)
| "WriteToBigQuery" >> beam.io.WriteToBigQuery("my_project:my_dataset.output_table")
)
# Pipeline context manager exits only after job completes successfully
urllib.request.urlopen(
"https://vigilmon.online/heartbeat/abc123",
timeout=5
)
if __name__ == "__main__":
run_pipeline()
Java (Apache Beam)
import java.net.HttpURLConnection;
import java.net.URL;
public class MyPipeline {
public static void main(String[] args) throws Exception {
Pipeline p = Pipeline.create(PipelineOptionsFactory.fromArgs(args).create());
// ... pipeline definition ...
PipelineResult result = p.run();
result.waitUntilFinish(); // blocks until job completes
if (result.getState() == PipelineResult.State.DONE) {
// Ping Vigilmon on success
URL url = new URL("https://vigilmon.online/heartbeat/abc123");
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setConnectTimeout(5000);
conn.getResponseCode();
conn.disconnect();
}
}
}
The ping runs only after waitUntilFinish() returns with a DONE state — meaning the Dataflow job completed without errors.
Step 3: Monitor Streaming Job Health via Cloud Run
Streaming Dataflow jobs run continuously and don't "finish" — so a heartbeat-per-run doesn't apply. Instead, deploy a Cloud Run service that queries the Dataflow API for streaming job health and watermark lag:
import os
import requests
from flask import Flask, jsonify
from google.auth import default
from google.auth.transport.requests import Request
app = Flask(__name__)
PROJECT_ID = os.environ["GCP_PROJECT_ID"]
REGION = os.environ["DATAFLOW_REGION"]
LAG_THRESHOLD_SECONDS = 60
def get_access_token():
creds, _ = default(scopes=["https://www.googleapis.com/auth/cloud-platform"])
creds.refresh(Request())
return creds.token
@app.route("/health/dataflow")
def dataflow_health():
token = get_access_token()
headers = {"Authorization": f"Bearer {token}"}
url = (
f"https://dataflow.googleapis.com/v1b3/projects/{PROJECT_ID}"
f"/locations/{REGION}/jobs"
f"?filter=ACTIVE&view=JOB_VIEW_SUMMARY"
)
resp = requests.get(url, headers=headers, timeout=10)
jobs = resp.json().get("jobs", [])
streaming_jobs = [j for j in jobs if j.get("type") == "JOB_TYPE_STREAMING"]
if not streaming_jobs:
return jsonify({"status": "no_streaming_jobs"}), 503
for job in streaming_jobs:
state = job.get("currentState", "")
if state not in ("JOB_STATE_RUNNING",):
return jsonify({"status": "not_running", "job": job["name"], "state": state}), 503
return jsonify({"status": "ok", "streaming_jobs": len(streaming_jobs)}), 200
if __name__ == "__main__":
app.run(host="0.0.0.0", port=8080)
Deploy to Cloud Run:
gcloud run deploy dataflow-health \
--source . \
--region us-central1 \
--allow-unauthenticated \
--set-env-vars GCP_PROJECT_ID=my-project,DATAFLOW_REGION=us-central1
Add a Vigilmon HTTP monitor:
- Click Add Monitor → HTTP / HTTPS.
- Enter the Cloud Run URL:
https://dataflow-health-abc123-uc.a.run.app/health/dataflow. - Set Expected HTTP status to
200. - Set Check interval to
2 minutes. - Click Save.
Step 4: Monitor Watermark Lag for Streaming Jobs
Watermark lag measures how far behind your streaming pipeline is from real-time event timestamps. A growing lag means your pipeline is falling behind its input. Extend the Cloud Run health endpoint to include lag:
def get_job_metrics(job_id, token):
url = (
f"https://dataflow.googleapis.com/v1b3/projects/{PROJECT_ID}"
f"/locations/{REGION}/jobs/{job_id}/metrics"
)
resp = requests.get(url, headers={"Authorization": f"Bearer {token}"}, timeout=10)
return resp.json().get("metrics", [])
@app.route("/health/dataflow/lag")
def dataflow_lag_health():
token = get_access_token()
# ... get streaming jobs ...
for job in streaming_jobs:
metrics = get_job_metrics(job["id"], token)
for metric in metrics:
if metric.get("name", {}).get("name") == "SystemLag":
lag_ms = metric.get("scalar", 0)
lag_seconds = lag_ms / 1000
if lag_seconds > LAG_THRESHOLD_SECONDS:
return jsonify({
"status": "lagging",
"job": job["name"],
"lag_seconds": lag_seconds
}), 503
return jsonify({"status": "ok"}), 200
Add a separate Vigilmon monitor pointing to /health/dataflow/lag. When lag exceeds 60 seconds, the endpoint returns 503 and Vigilmon fires an alert — giving you an early warning before downstream consumers notice missing events.
Step 5: Set Up a Scheduled Cron Ping for Streaming Jobs
For critical streaming jobs, also run a cron job that pings a separate Vigilmon heartbeat every few minutes — giving you a liveness signal even if the Cloud Run health endpoint has deployment issues:
#!/bin/bash
# /opt/scripts/ping-dataflow-liveness.sh
PROJECT="my-gcp-project"
REGION="us-central1"
HEARTBEAT_URL="https://vigilmon.online/heartbeat/streaming-abc456"
RUNNING=$(gcloud dataflow jobs list \
--project="$PROJECT" \
--region="$REGION" \
--status=active \
--format="value(id)" 2>/dev/null | wc -l)
if [ "$RUNNING" -gt 0 ]; then
curl -s "$HEARTBEAT_URL"
fi
Add to cron:
*/5 * * * * /opt/scripts/ping-dataflow-liveness.sh
Set the Vigilmon heartbeat interval to 15 minutes to allow a few missed pings before alerting.
Step 6: Configure Alert Channels
- Go to Alert Channels in Vigilmon and add Slack, PagerDuty, or email.
- For streaming jobs processing payment events or user activity, set Consecutive failures before alert to
1— lag grows quickly once a pipeline stalls. - For batch jobs where a retry is acceptable, set it to
2. - Use Maintenance windows during Dataflow job upgrades or intentional restarts:
curl -X POST https://vigilmon.online/api/maintenance \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{"monitor_id": "abc123", "duration_minutes": 15}'
Summary
| Monitor | Target | What It Catches | |---|---|---| | Cron heartbeat | Batch pipeline completion | Failed batch run, missed schedule | | HTTP endpoint | Cloud Run status service | Streaming job not in RUNNING state | | HTTP endpoint (lag) | Cloud Run lag health route | Watermark lag exceeding threshold | | Cron heartbeat | Streaming job liveness cron | Cloud Run health endpoint outage |
Google Cloud Dataflow handles the hard parts of distributed stream and batch processing. Vigilmon handles the part Dataflow doesn't: telling you from outside GCP when a job has stopped producing results, fallen behind on lag, or simply never started. A few monitors and a Web Activity ping turn a silent failure into a page.