Bazel is Google's open-source, polyglot build system capable of building and testing Java, C++, Go, Python, TypeScript, and more in a single hermetic monorepo. Its correctness guarantees and remote execution backend (RBE) make it the build system of choice for organizations with thousands of targets — but that same distributed architecture introduces multiple failure surfaces. Remote execution workers go unhealthy, build cache servers become unreachable, and action graph evaluation can stall under load. Vigilmon gives you the monitoring layer Bazel itself doesn't provide: HTTP health checks on your RBE backend, cron heartbeats for scheduled builds, and SSL certificate alerts for your cache infrastructure.
What You'll Set Up
- HTTP health monitor for the Bazel remote execution backend
- Build cache server health monitoring
- Cron heartbeat for scheduled full-workspace builds and CI cache warm-ups
- SSL certificate monitoring for RBE and cache servers
- Maintenance windows for cache server upgrades and RBE worker deployments
Prerequisites
- Bazel 6+ monorepo with a
MODULE.bazelorWORKSPACEfile - Remote execution backend (Buildbarn, BuildBuddy, Google RBE, or self-hosted)
- Remote build cache (HTTP cache server or CAS backend)
- CI pipeline running
bazel build //...orbazel test //...on pull requests - A free Vigilmon account
Step 1: Monitor the Remote Execution Backend
Bazel's remote execution backend (RBE) is what makes distributed builds fast. When the backend is unavailable, Bazel falls back to local execution and your 10-minute build becomes a 2-hour build.
Common RBE providers expose health endpoints:
- BuildBuddy:
https://app.buildbuddy.io/health - Buildbarn (scheduler):
https://scheduler.yourdomain.com/readyz - Google RBE: monitored via GCP status page — use TCP to verify your org's quota endpoint
Add a Vigilmon HTTP monitor:
- Log in to vigilmon.online and click Add Monitor.
- Set Type to
HTTP / HTTPS. - Enter your RBE health endpoint URL.
- Set Check interval to
1 minute. - Set Expected HTTP status to
200. - Click Save.
For RBE backends that only expose gRPC (no HTTP), add a TCP port monitor instead:
- Click Add Monitor → TCP Port.
- Enter the RBE scheduler hostname and gRPC port (typically
8980or443). - Set Check interval to
1 minute.
Step 2: Monitor the Bazel HTTP Build Cache
Bazel supports an HTTP-based remote cache (--remote_cache=http://...) that's simpler to self-host than a full REAPI backend. This cache stores action results and output files — losing it means every build runs cold.
If you're running an HTTP cache server (nginx with WebDAV, Bazel's own reference server, or a custom implementation), add a health endpoint:
# nginx.conf — expose a health check alongside the WebDAV cache
server {
listen 9090;
location /health {
return 200 '{"status":"ok"}';
add_header Content-Type application/json;
}
}
server {
listen 8080;
# WebDAV cache configuration
root /var/cache/bazel;
dav_methods PUT DELETE;
dav_ext_methods PROPFIND OPTIONS;
create_full_put_path on;
dav_access user:rw group:r all:r;
}
For a custom Go-based cache server:
// health handler
http.HandleFunc("/health", func(w http.ResponseWriter, r *http.Request) {
// Check disk space and storage accessibility
var stat syscall.Statfs_t
if err := syscall.Statfs(cacheDir, &stat); err != nil {
http.Error(w, `{"status":"error"}`, http.StatusServiceUnavailable)
return
}
freeGB := float64(stat.Bavail*uint64(stat.Bsize)) / 1e9
if freeGB < 10 {
http.Error(w, `{"status":"low_disk"}`, http.StatusServiceUnavailable)
return
}
w.Header().Set("Content-Type", "application/json")
fmt.Fprintf(w, `{"status":"ok","free_gb":%.1f}`, freeGB)
})
Point Vigilmon at https://bazel-cache.yourdomain.com:9090/health. The free disk space check ensures Vigilmon alerts before the cache fills up and starts evicting or failing writes.
Step 3: Monitor RBE Worker Availability
Bazel's distributed execution depends on healthy worker pools. Buildbarn and similar systems expose per-worker metrics — but a simpler signal is whether the scheduler can accept work.
Add a wrapper script that tests action dispatch and alerts if workers are unavailable:
#!/usr/bin/env python3
# scripts/check-rbe-workers.py
import subprocess
import sys
import os
import json
import urllib.request
VIGILMON_WEBHOOK = os.environ.get('VIGILMON_WEBHOOK_URL')
MIN_WORKER_COUNT = int(os.environ.get('MIN_RBE_WORKERS', '2'))
# Run a trivial Bazel build that uses RBE and check execution strategy
result = subprocess.run(
['bazel', 'build', '--config=remote', '--verbose_failures',
'--execution_log_json_file=/tmp/exec_log.json', '//tools:noop'],
capture_output=True, text=True
)
if result.returncode != 0:
print(f"RBE build failed: {result.stderr}", file=sys.stderr)
if VIGILMON_WEBHOOK:
data = json.dumps({'event': 'rbe_build_failed', 'stderr': result.stderr[:500]}).encode()
req = urllib.request.Request(VIGILMON_WEBHOOK, data=data,
headers={'Content-Type': 'application/json'})
urllib.request.urlopen(req)
sys.exit(1)
# Parse execution log to count remote actions
with open('/tmp/exec_log.json') as f:
remote_actions = sum(
1 for line in f
if '"type":"REMOTE"' in line or '"runner":"REMOTE"' in line
)
print(f"Remote actions executed: {remote_actions}")
if remote_actions < 1 and VIGILMON_WEBHOOK:
data = json.dumps({'event': 'rbe_zero_remote_actions'}).encode()
req = urllib.request.Request(VIGILMON_WEBHOOK, data=data,
headers={'Content-Type': 'application/json'})
urllib.request.urlopen(req)
Run this script in CI alongside your build health checks. Zero remote actions on a build that should use RBE indicates workers fell back to local execution.
Step 4: Heartbeat Monitoring for Scheduled Full-Workspace Builds
Large Bazel monorepos typically run a nightly full build to warm the remote cache and catch integration failures before developers arrive. If the nightly pipeline silently fails, the next day's CI runs will be slower and may miss broken targets.
Set up a Vigilmon cron heartbeat:
- In Vigilmon, click Add Monitor → Cron Heartbeat.
- Set the expected interval to
1440minutes (24 hours). - Copy the heartbeat URL:
https://vigilmon.online/heartbeat/bazel123. - Wire it into your nightly build:
#!/bin/bash
set -euo pipefail
echo "Starting Bazel full-workspace build..."
# Build and test everything with remote execution
bazel build --config=remote //...
bazel test --config=remote //... --test_output=errors
echo "Bazel build complete"
# Signal success to Vigilmon — only fires if both commands succeeded
curl -fsS https://vigilmon.online/heartbeat/bazel123
GitHub Actions configuration:
name: Nightly Bazel build
on:
schedule:
- cron: '0 2 * * *' # 2 AM UTC
jobs:
full-build:
runs-on: self-hosted
timeout-minutes: 120
steps:
- uses: actions/checkout@v4
- name: Set up Bazelisk
uses: bazelbuild/setup-bazelisk@v3
- name: Bazel build
run: bazel build --config=remote //...
env:
BAZEL_REMOTE_CACHE: ${{ vars.BAZEL_REMOTE_CACHE }}
BAZEL_RBE_ENDPOINT: ${{ vars.BAZEL_RBE_ENDPOINT }}
- name: Bazel test
run: bazel test --config=remote //... --test_output=errors
env:
BAZEL_REMOTE_CACHE: ${{ vars.BAZEL_REMOTE_CACHE }}
BAZEL_RBE_ENDPOINT: ${{ vars.BAZEL_RBE_ENDPOINT }}
- name: Signal success to Vigilmon
if: success()
run: curl -fsS https://vigilmon.online/heartbeat/bazel123
Step 5: SSL Certificate Alerts for RBE and Cache Servers
Bazel uses gRPC over TLS to communicate with RBE workers and REAPI cache backends. An expired certificate causes Bazel to reject all remote connections with a TLS error, forcing every action to run locally.
Add SSL certificate monitoring in Vigilmon for each server:
- Open the HTTP monitor for your RBE health endpoint.
- Enable Monitor SSL certificate.
- Set Alert when certificate expires in less than
21 days. - Repeat for the build cache health endpoint if it's on a separate domain.
- Click Save.
Check certificate expiry manually:
# RBE scheduler certificate
echo | openssl s_client -servername scheduler.yourdomain.com \
-connect scheduler.yourdomain.com:443 2>/dev/null \
| openssl x509 -noout -enddate
# Build cache certificate
echo | openssl s_client -servername bazel-cache.yourdomain.com \
-connect bazel-cache.yourdomain.com:9090 2>/dev/null \
| openssl x509 -noout -enddate
For mTLS configurations (where Bazel presents a client certificate to the RBE backend), also monitor the client certificate expiry:
openssl x509 -noout -enddate -in /etc/bazel/client.crt
Step 6: Maintenance Windows for RBE Worker Deployments
When deploying new RBE worker images or scaling the worker pool, add a maintenance window to suppress false-positive alerts during the rollout:
MONITOR_ID="your-monitor-id"
API_KEY="your-vigilmon-api-key"
# Open a 15-minute maintenance window before starting the rollout
curl -X POST https://vigilmon.online/api/maintenance \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d "{\"monitor_id\": \"$MONITOR_ID\", \"duration_minutes\": 15}"
# Perform the RBE worker rolling update
kubectl set image deployment/rbe-worker \
worker=gcr.io/yourproject/rbe-worker:v2.1.0
kubectl rollout status deployment/rbe-worker --timeout=10m
# Validate build still works with the new workers
bazel build --config=remote //tools:validate
echo "Rollout complete — maintenance window will expire automatically"
For major Bazel version upgrades that require output base migration (bazel clean --expunge), extend the window to 30 minutes to cover the clean build of critical targets.
Summary
| Monitor | Target | What It Catches |
|---|---|---|
| HTTP health check | RBE scheduler /readyz | Remote execution backend down |
| HTTP health check | Cache server /health | Build cache unreachable, low disk |
| TCP port | gRPC endpoint (:8980) | Backend not accepting connections |
| Cron heartbeat | Nightly build heartbeat URL | Missed full build, CI cron failure |
| SSL certificate | RBE scheduler domain | TLS cert expiry blocking all remote actions |
| SSL certificate | Cache server domain | TLS cert expiry breaking cache reads/writes |
| Webhook | Zero remote actions | Silent fallback to local execution |
Bazel's power comes from its distributed execution model — but that distribution means more moving parts that can fail silently. With Vigilmon monitoring your RBE backend health, build cache availability, SSL certificates, and nightly build heartbeats, you'll catch infrastructure failures in minutes rather than discovering them when your CI queue has backed up and developers are waiting.