tutorial

Monitoring OpenRouteService with Vigilmon

OpenRouteService is the open source routing engine behind accessibility, emergency response, and logistics routing based on OpenStreetMap — but its Spring Boot process has no built-in alerting when graphs go stale or JVM memory pressure builds. Here's how to monitor ORS health, routing latency, vehicle profiles, and graph freshness with Vigilmon.

OpenRouteService (ORS) is an open source routing engine developed by HeiGIT at Heidelberg University, providing routing, isochrones, distance matrices, and geocoding based on OpenStreetMap data. It goes beyond car-and-bike routing with specialized profiles for wheelchair accessibility, heavy goods vehicles with height and weight restrictions, and emergency response vehicles — making it mission-critical for humanitarian logistics, accessibility applications, and urban planning tools. ORS runs as a Spring Boot Java application that loads compressed road network graphs into JVM heap memory — when graphs go stale, vehicle profiles fail to load, or heap pressure builds, routing requests fail silently or return stale results. Vigilmon gives you real-time visibility into ORS health, per-profile availability, routing latency, and graph freshness.

What You'll Set Up

  • ORS health endpoint monitor
  • Routing latency alert for /v2/directions
  • Isochrone and matrix endpoint latency checks
  • Vehicle profile availability monitoring
  • JVM heap utilization heartbeat
  • Graph data freshness alert

Prerequisites

  • OpenRouteService 7.x or 8.x deployed (Docker or standalone JAR)
  • At least one vehicle profile loaded (e.g. driving-car)
  • A free Vigilmon account

Step 1: Monitor the ORS Health Endpoint

ORS exposes a built-in health endpoint at /ors/v2/health that reports the service status and loaded profile count:

curl http://localhost:8082/ors/v2/health
# {"status":"ready","services":{"routing":{"status":"ready","profiles":{"driving-car":"ready","cycling-regular":"ready"}}}}

Add a Vigilmon HTTP monitor:

  1. Log in to vigilmon.online and click Add Monitor.
  2. Set Type to HTTP / HTTPS.
  3. Enter your ORS health URL: https://ors.yourdomain.com/ors/v2/health.
  4. Set Expected response contains to "status":"ready".
  5. Set Check interval to 1 minute.
  6. Click Save.

The health endpoint reflects the actual graph loading state — during startup, ORS reports "status":"loading" until all graphs are loaded into memory. Once ready, it switches to "status":"ready". A crash or JVM OOM causes this endpoint to stop responding entirely, triggering Vigilmon's timeout alert.

ORS can take 2–10 minutes to start up on large OSM extracts (the graph loading phase is memory-intensive). If you restart ORS frequently, set Consecutive failures before alert to 5 to avoid startup false alarms.


Step 2: Monitor Routing Request Latency

The /v2/directions endpoint is the core ORS workload — point-to-point routing using Contraction Hierarchies. CH routing is typically fast (under 100ms for moderate distances), but large cross-country queries or cold JVM caches can push latency over 500ms.

Add a synthetic routing probe using a known short-distance pair:

curl -X POST "https://ors.yourdomain.com/ors/v2/directions/driving-car/json" \
  -H "Content-Type: application/json" \
  -d '{
    "coordinates": [[8.681495, 49.41461], [8.687872, 49.420318]],
    "instructions": false
  }'

Add a Vigilmon HTTP monitor for this probe:

  1. Click Add MonitorHTTP / HTTPS.
  2. Set Method to POST.
  3. URL: https://ors.yourdomain.com/ors/v2/directions/driving-car/json.
  4. Set Request body to: {"coordinates":[[8.681495,49.41461],[8.687872,49.420318]],"instructions":false}
  5. Set Request headers: Content-Type: application/json.
  6. Set Expected response contains to "routes".
  7. Under Advanced, set Alert if response time exceeds to 500 ms.
  8. Set Check interval to 2 minutes.
  9. Click Save.

The coordinates above are a short urban route in Heidelberg (ORS's home city) — an ideal benchmark because it's representative of real usage and the routing graph is always well-covered for this area. Latency over 500ms on this query indicates JVM GC pressure or graph memory eviction.


Step 3: Monitor Isochrone Calculation Latency

Isochrone computation (reachability polygons) is more expensive than point-to-point routing — ORS must explore all reachable nodes within a time or distance budget, then compute a concave hull. Large isochrones over 30 minutes can take 1–3 seconds on complex urban graphs.

Add a synthetic isochrone probe with a moderate time range:

curl -X POST "https://ors.yourdomain.com/ors/v2/isochrones/driving-car" \
  -H "Content-Type: application/json" \
  -d '{
    "locations": [[8.681495, 49.41461]],
    "range": [300, 600],
    "range_type": "time"
  }'

Add a Vigilmon HTTP monitor with Alert if response time exceeds set to 3000 ms. A 5-minute (300s) and 10-minute (600s) driving isochrone in an urban area is a good representative benchmark — fast enough to complete in under a second on healthy hardware, but heavy enough to expose graph performance issues.


Step 4: Monitor Vehicle Profile Availability

ORS loads each vehicle profile (driving-car, cycling-regular, wheelchair, hgv, etc.) as a separate routing graph. If a profile fails to load — due to a corrupt graph file, insufficient heap, or missing OSM data — it silently disappears from the health response.

Build a profile availability monitoring script:

#!/bin/bash
# check-ors-profiles.sh

ORS_HEALTH_URL="https://ors.yourdomain.com/ors/v2/health"
VIGILMON_KEY="${VIGILMON_API_KEY}"
MONITOR_ID="${VIGILMON_PROFILE_MONITOR_ID}"
EXPECTED_PROFILES=("driving-car" "cycling-regular" "foot-walking" "wheelchair")

HEALTH=$(curl -s "$ORS_HEALTH_URL")

MISSING_PROFILES=()
for PROFILE in "${EXPECTED_PROFILES[@]}"; do
  if ! echo "$HEALTH" | grep -q "\"$PROFILE\":\"ready\""; then
    MISSING_PROFILES+=("$PROFILE")
  fi
done

if [ ${#MISSING_PROFILES[@]} -gt 0 ]; then
  MISSING_STR=$(IFS=','; echo "${MISSING_PROFILES[*]}")
  curl -s -X POST \
    "https://vigilmon.online/api/monitors/${MONITOR_ID}/report" \
    -H "Authorization: Bearer ${VIGILMON_KEY}" \
    -H "Content-Type: application/json" \
    -d "{\"status\":\"down\",\"message\":\"ORS profiles not ready: ${MISSING_STR}\"}"
fi

Run via cron every 5 minutes. The wheelchair profile is especially important to monitor independently — if it goes missing, accessibility routing applications silently fall back to car routing or return errors.


Step 5: Monitor JVM Heap Utilization

ORS loads large routing graphs into JVM heap memory. A 500MB OSM extract for a single country can require 4–8GB of heap; global extracts can require 32GB+. As heap fills, JVM GC cycles lengthen and routing latency spikes before the process eventually crashes with OutOfMemoryError.

ORS exposes JVM metrics via Spring Boot Actuator (if enabled):

curl http://localhost:8082/actuator/metrics/jvm.memory.used
# {"name":"jvm.memory.used","measurements":[{"statistic":"VALUE","value":3865470976}]}

Enable the actuator in your ORS application.yml:

management:
  endpoints:
    web:
      exposure:
        include: health,metrics
  endpoint:
    health:
      show-details: always

Build a heap monitoring script:

#!/bin/bash
# check-ors-heap.sh

ACTUATOR_URL="http://localhost:8082/actuator/metrics/jvm.memory.max"
USED_URL="http://localhost:8082/actuator/metrics/jvm.memory.used"
VIGILMON_KEY="${VIGILMON_API_KEY}"
MONITOR_ID="${VIGILMON_HEAP_MONITOR_ID}"
HEAP_ALERT_PCT=80

MAX=$(curl -s "$ACTUATOR_URL" | python3 -c "import sys,json; print(json.load(sys.stdin)['measurements'][0]['value'])")
USED=$(curl -s "$USED_URL" | python3 -c "import sys,json; print(json.load(sys.stdin)['measurements'][0]['value'])")

PCT=$((USED * 100 / MAX))

if [ "$PCT" -gt "$HEAP_ALERT_PCT" ]; then
  curl -s -X POST \
    "https://vigilmon.online/api/monitors/${MONITOR_ID}/report" \
    -H "Authorization: Bearer ${VIGILMON_KEY}" \
    -H "Content-Type: application/json" \
    -d "{\"status\":\"down\",\"message\":\"ORS JVM heap at ${PCT}% (${USED} / ${MAX} bytes)\"}"
fi

Run every 2 minutes via cron. Alert at 80%: above that threshold, GC pauses start affecting routing latency. At 95%, ORS is likely minutes away from an OOM crash.


Step 6: Monitor Graph Data Freshness

ORS routing graphs are built from OpenStreetMap PBF data. Stale graphs mean your routing results don't reflect recently added roads, updated turn restrictions, or new pedestrian paths. For wheelchair and emergency vehicle profiles, stale graphs can mean wrong or dangerous routing recommendations.

Add a cron heartbeat that fires only when a successful graph rebuild completes:

  1. Click Add MonitorCron Heartbeat in Vigilmon.
  2. Set the expected interval to match your rebuild schedule (e.g. 10080 minutes = 7 days for weekly OSM updates).
  3. Copy the heartbeat URL.

In your graph build script:

#!/bin/bash
# rebuild-ors-graphs.sh

OSM_PBF_URL="https://download.geofabrik.de/europe/germany-latest.osm.pbf"
ORS_GRAPHS_DIR="/opt/openrouteservice/graphs"
VIGILMON_HEARTBEAT="https://vigilmon.online/heartbeat/abc123"

# Download fresh OSM data
wget -q -O /tmp/germany-latest.osm.pbf "$OSM_PBF_URL" || { echo "OSM download failed"; exit 1; }

# Stop ORS, replace graphs, restart
systemctl stop openrouteservice

# Run ORS graph builder
java -jar /opt/openrouteservice/ors.jar \
  --ors.engine.source_file=/tmp/germany-latest.osm.pbf \
  --ors.engine.graphs_root_path="$ORS_GRAPHS_DIR" \
  --ors.engine.mode=graph_builder

if [ $? -eq 0 ]; then
  systemctl start openrouteservice
  # Wait for ORS to finish loading graphs
  for i in $(seq 1 60); do
    STATUS=$(curl -s https://ors.yourdomain.com/ors/v2/health | grep -o '"status":"ready"')
    [ "$STATUS" = '"status":"ready"' ] && break
    sleep 10
  done
  # Signal fresh graph to Vigilmon
  curl -s "$VIGILMON_HEARTBEAT"
else
  echo "Graph build failed"
  exit 1
fi

If the weekly OSM update fails — download error, build crash, ORS startup failure — the heartbeat never fires and Vigilmon alerts after 7 days, prompting investigation before graphs are 2+ weeks stale.


Step 7: Configure Alert Channels

  1. Go to Alert Channels in Vigilmon and add Slack, email, or PagerDuty.
  2. For the ORS health endpoint, set Consecutive failures before alert to 3 — ORS takes 2–10 minutes to restart on large extracts.
  3. For routing latency, set Alert if response time exceeds to 500 ms with Consecutive failures at 2.
  4. Use Maintenance windows during graph rebuilds:
curl -X POST https://vigilmon.online/api/maintenance \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -d '{
    "monitor_id": "ors-health-monitor-id",
    "duration_minutes": 30,
    "reason": "ORS graph rebuild and restart"
  }'

Summary

| Monitor | Target | What It Catches | |---|---|---| | ORS health endpoint | /ors/v2/health | Server crash, graph load failure | | Routing latency | /v2/directions POST (timed) | JVM GC pressure, slow CH lookup | | Isochrone latency | /v2/isochrones POST (timed) | Graph traversal bottleneck | | Profile availability | Health endpoint parser script | Missing wheelchair/HGV profile | | JVM heap | Actuator metrics script | Memory pressure before OOM crash | | Graph freshness | Cron heartbeat after rebuild | Stale OSM data, build failure |

OpenRouteService enables routing experiences that no commercial API provides — wheelchair accessibility, emergency vehicle routing, and logistics optimization based on real OSM attributes. With Vigilmon monitoring each layer of the ORS stack, you get early warning of JVM memory pressure, stale routing graphs, and missing vehicle profiles before they affect the accessibility applications and humanitarian logistics tools that depend on them.

Monitor your app with Vigilmon

Free plan — 5 monitors, no credit card required. Up and running in 60 seconds.

Start free →