TigerGraph is a native parallel graph database built for real-time deep-link analytics — but its operational health is not visible from the outside by default. The REST++ API that your application queries listens on port 14240, and while TigerGraph exposes a /api/ping endpoint, a successful ping does not confirm that your GSQL installed queries are executing, that a loading job completed its ETL pipeline, or that a replica has not fallen behind the primary. A loading job can fail with a partial import, leaving your graph with stale vertex and edge data, while the ping endpoint continues to return {"error":false,"message":"pong","results":null} as if nothing went wrong.
Vigilmon gives you external visibility into TigerGraph health through HTTP probe monitoring and heartbeat monitoring for GSQL loading jobs and scheduled graph analytics queries. This tutorial walks through both.
Why TigerGraph Monitoring Needs More Than Process Checks
TigerGraph's built-in status tools and the TigerGraph Admin Portal tell you the service is running. They cannot tell you:
- Whether the REST++ API on port 14240 is reachable from your application servers at the network layer
- Whether a GSQL installed query is returning correct results rather than empty sets due to a schema mismatch
- Whether a loading job has stalled mid-run with a partial ETL import, leaving graph data inconsistent
- Whether a replica instance has fallen behind the primary and is serving stale traversal results
- Whether a specific graph in a multi-graph deployment has lost connectivity while other graphs appear healthy
- Whether concurrent GSQL query execution has saturated the thread pool, causing timeouts that surface only at the application layer
These are the failure modes that produce silent data errors or cascading query timeouts without clean alerts. External monitoring through Vigilmon catches them by probing the actual connectivity and logic paths your application depends on.
Step 1: Build a TigerGraph Health Endpoint
TigerGraph's REST++ API exposes /api/ping and /api/version on port 14240. A complete health check combines these built-in probes with a lightweight GSQL installed query execution to verify that graph analytics queries are actually running. Expose this as a single health endpoint using FastAPI so Vigilmon has a stable URL to probe.
# health_tigergraph.py — run as a sidecar or standalone service with access to TigerGraph
import os
import requests
from fastapi import FastAPI
from fastapi.responses import JSONResponse
app = FastAPI()
TG_HOST = os.environ.get("TIGERGRAPH_HOST", "localhost")
TG_PORT = os.environ.get("TIGERGRAPH_PORT", "14240")
TG_GRAPH = os.environ.get("TIGERGRAPH_GRAPH", "MyGraph")
TG_SECRET = os.environ.get("TIGERGRAPH_SECRET", "") # GSQL secret for token auth
TG_BASE = f"http://{TG_HOST}:{TG_PORT}"
_token: str | None = None
def get_token() -> str:
"""Request a short-lived REST++ bearer token using a GSQL secret."""
global _token
if _token:
return _token
resp = requests.post(
f"{TG_BASE}/requesttoken",
json={"secret": TG_SECRET, "lifetime": 3600},
timeout=5,
)
resp.raise_for_status()
_token = resp.json()["results"]["token"]
return _token
@app.get("/health/tigergraph")
def tigergraph_health():
checks: dict = {}
# 1. Ping check — confirms REST++ API is reachable
try:
ping_resp = requests.get(f"{TG_BASE}/api/ping", timeout=5)
ping_data = ping_resp.json()
checks["ping"] = "ok" if not ping_data.get("error") and ping_data.get("message") == "pong" else "degraded"
except Exception as exc:
return JSONResponse(status_code=503, content={"status": "down", "reason": "ping_failed", "error": str(exc)})
if checks["ping"] != "ok":
return JSONResponse(status_code=503, content={"status": "degraded", "checks": checks})
# 2. Version check — confirms REST++ server is fully initialised
try:
ver_resp = requests.get(f"{TG_BASE}/api/version", timeout=5)
ver_resp.raise_for_status()
checks["version"] = ver_resp.json().get("results", {}).get("version", "unknown")
except Exception as exc:
checks["version"] = f"error: {exc}"
# 3. GSQL installed query probe — confirms graph analytics queries are executable
try:
token = get_token()
# Call a lightweight installed query (replace 'health_probe' with an actual installed query)
query_resp = requests.get(
f"{TG_BASE}/query/{TG_GRAPH}/health_probe",
headers={"Authorization": f"Bearer {token}"},
timeout=10,
)
if query_resp.status_code == 200 and not query_resp.json().get("error"):
checks["gsql_query"] = "ok"
else:
checks["gsql_query"] = "degraded"
return JSONResponse(status_code=503, content={"status": "degraded", "checks": checks})
except Exception as exc:
checks["gsql_query"] = f"error: {exc}"
return JSONResponse(status_code=503, content={"status": "degraded", "checks": checks})
return {"status": "ok", "checks": checks}
Install dependencies and run:
pip install fastapi uvicorn requests
uvicorn health_tigergraph:app --host 0.0.0.0 --port 8080
Verify the endpoint before wiring up Vigilmon:
curl -i http://your-server.example.com:8080/health/tigergraph
# HTTP/1.1 200 OK
# {"status":"ok","checks":{"ping":"ok","version":"3.x.x","gsql_query":"ok"}}
The health_probe GSQL installed query should be a minimal read-only query against a representative graph — for example, counting a small vertex type:
-- Install this query in TigerGraph Studio or via GSQL CLI
CREATE QUERY health_probe() FOR GRAPH MyGraph {
TYPEDEF TUPLE <INT vertex_count> Result;
SetAccum<VERTEX> @@probe_set;
start = {ANY};
sample = SELECT s FROM start:s LIMIT 1;
PRINT sample.size() AS vertex_count;
}
INSTALL QUERY health_probe
Step 2: Configure Vigilmon HTTP Monitor for TigerGraph
- Log in to vigilmon.online and go to Monitors → New Monitor
- Choose HTTP / HTTPS
- Set the URL to your health endpoint:
http://your-server.example.com:8080/health/tigergraph - Set the check interval to 1 minute
- Under Expected response, configure:
- Status code:
200 - Response body contains:
"status":"ok" - Response time threshold:
5000ms
- Status code:
- Under Alert channels, assign your Slack or PagerDuty channel
- Save the monitor
Vigilmon probes from multiple geographic regions simultaneously, requiring multi-region consensus before opening an incident. This eliminates false alarms from transient single-probe network hiccups.
Monitoring Primary vs. Replica Instances Separately
TigerGraph supports distributed deployments with a primary instance handling writes and replica instances serving read-heavy analytics workloads. Create separate monitors for each role:
[tigergraph-primary] /health/tigergraph?role=primary— immediate P1 page on failure; graph writes and loaded data stop[tigergraph-replica-1] /health/tigergraph?role=replica— P2 Slack alert; read-heavy analytics workloads degrade[tigergraph-replica-2] /health/tigergraph?role=replica— P2 Slack alert
Pass the role query parameter to your health handler to direct the probe at the appropriate TigerGraph instance endpoint. Set the TIGERGRAPH_HOST environment variable per instance when deploying the health sidecar.
In a multi-graph deployment, create one additional monitor per critical graph using the graph-scoped health endpoint (/health/tigergraph?graph=OrdersGraph), since TigerGraph isolates each graph's vertex and edge schema — a failure in one graph's schema or loading pipeline does not always surface in the default graph's health check.
Use Vigilmon's status page grouping to surface all TigerGraph monitors in a single pane for on-call engineers.
Step 3: Heartbeat Monitoring for TigerGraph Graph Analytics Jobs
TigerGraph Loading Jobs run ETL pipelines that ingest vertex and edge data into your graph from CSV, JSON, or streaming sources. These jobs are asynchronous — you submit the job and the status is available only through the REST++ API or the Admin Portal. When a loading job fails due to malformed data, a connector timeout, or a schema type mismatch, it logs the failure but does not proactively alert your team. Scheduled GSQL installed queries that refresh computed graph properties or recommendation caches also run silently.
Vigilmon heartbeat monitors detect silent stalls: your pipeline pings Vigilmon after each successful completion. If pings stop arriving within the expected window, Vigilmon fires an alert.
Set Up the Heartbeat Monitor
- In Vigilmon, go to Monitors → New Monitor → Heartbeat
- Set the name:
tigergraph-loading-job - Set the expected interval: 6 hours (adjust to your loading job schedule)
- Set the grace period: 1 hour
- Save — copy the unique heartbeat URL, e.g.
https://vigilmon.online/heartbeat/abc123xyz
Wire It Into a TigerGraph Loading Job Poller
# tigergraph_loader.py
import os
import time
import requests
TG_HOST = os.environ["TIGERGRAPH_HOST"]
TG_PORT = os.environ.get("TIGERGRAPH_PORT", "14240")
TG_GRAPH = os.environ["TIGERGRAPH_GRAPH"]
TG_SECRET = os.environ["TIGERGRAPH_SECRET"]
TG_BASE = f"http://{TG_HOST}:{TG_PORT}"
VIGILMON_HEARTBEAT_URL = os.environ["VIGILMON_HEARTBEAT_URL"]
def get_token() -> str:
resp = requests.post(
f"{TG_BASE}/requesttoken",
json={"secret": TG_SECRET, "lifetime": 3600},
timeout=5,
)
resp.raise_for_status()
return resp.json()["results"]["token"]
def run_loading_job(job_name: str, data_source: str) -> None:
token = get_token()
headers = {"Authorization": f"Bearer {token}"}
# Trigger the loading job via REST++
trigger_resp = requests.post(
f"{TG_BASE}/ddl/{TG_GRAPH}",
headers=headers,
params={"tag": job_name, "filename": data_source},
timeout=30,
)
trigger_resp.raise_for_status()
job_id = trigger_resp.json().get("results", {}).get("jobId")
print(f"Loading job started: {job_id}")
# Poll for completion
while True:
time.sleep(30)
status_resp = requests.get(
f"{TG_BASE}/showloadingstatus/{TG_GRAPH}",
headers=headers,
params={"jobId": job_id},
timeout=10,
)
status_data = status_resp.json()
overall = status_data.get("results", [{}])[0].get("overallStatus", {})
status = overall.get("status", "unknown")
print(f"Loading job status: {status}")
if status in ("success", "failed", "aborted"):
break
if status != "success":
raise RuntimeError(f"Loading job {job_id} finished with status: {status}")
# Ping Vigilmon on successful completion
try:
requests.get(VIGILMON_HEARTBEAT_URL, timeout=5)
print("Heartbeat sent to Vigilmon")
except Exception:
pass # Non-fatal — job succeeded; heartbeat failure is logged separately
if __name__ == "__main__":
run_loading_job(
job_name=os.environ["TG_LOADING_JOB_NAME"],
data_source=os.environ["TG_DATA_SOURCE"],
)
Wire It Into a Scheduled GSQL Analytics Query
For scheduled GSQL installed queries that refresh graph-derived data (recommendation scores, community detection labels, centrality metrics):
# tigergraph_scheduled_query.py
import os
import requests
TG_HOST = os.environ["TIGERGRAPH_HOST"]
TG_PORT = os.environ.get("TIGERGRAPH_PORT", "14240")
TG_GRAPH = os.environ["TIGERGRAPH_GRAPH"]
TG_SECRET = os.environ["TIGERGRAPH_SECRET"]
TG_BASE = f"http://{TG_HOST}:{TG_PORT}"
VIGILMON_HEARTBEAT_URL = os.environ["VIGILMON_HEARTBEAT_URL"]
def run_analytics_query(query_name: str) -> None:
# Obtain bearer token
token_resp = requests.post(
f"{TG_BASE}/requesttoken",
json={"secret": TG_SECRET, "lifetime": 3600},
timeout=5,
)
token_resp.raise_for_status()
token = token_resp.json()["results"]["token"]
# Call the installed GSQL query via REST++
resp = requests.get(
f"{TG_BASE}/query/{TG_GRAPH}/{query_name}",
headers={"Authorization": f"Bearer {token}"},
timeout=120, # Analytics queries may take longer
)
resp.raise_for_status()
result = resp.json()
if result.get("error"):
raise RuntimeError(f"Query {query_name} returned error: {result.get('message')}")
print(f"Scheduled query {query_name} completed successfully")
# Ping Vigilmon on successful completion
requests.get(VIGILMON_HEARTBEAT_URL, timeout=5)
if __name__ == "__main__":
run_analytics_query(os.environ["TG_QUERY_NAME"])
If the loading job or analytics query fails and never pings, Vigilmon alerts after the expected interval plus grace period passes.
Step 4: Alert Routing and Response Time Thresholds
Configure alert routing in Vigilmon to match the severity of each failure mode:
| Monitor | Alert Channel | Priority |
|---|---|---|
| TigerGraph primary /health/tigergraph | Slack + PagerDuty | P1 |
| TigerGraph replica endpoints | Slack | P2 |
| Heartbeat: loading job (ETL pipeline) | Slack + email | P2 |
| Heartbeat: scheduled GSQL analytics query | Email | P3 |
| Per-graph health check (multi-graph) | Slack | P2 |
Set response time thresholds as early warnings before full failures occur:
- Alert at
2000msfor the/api/pingresponse — a healthy TigerGraph REST++ server responds in milliseconds; latency above 2 seconds signals resource pressure - Alert at
5000msfor the full health endpoint including the GSQL probe — the lightweight installed query should complete well within this window - Alert at
15000msfor any application-level GSQL query endpoints — sustained high latency on graph traversals signals either missing indices, excessive traversal depth, or saturated parallel execution threads
Use Vigilmon's consecutive failure threshold to avoid false alarms from transient spikes. Setting this to 2 consecutive failures before opening an incident gives TigerGraph's internal recovery mechanisms time to respond to transient pressure without paging on-call engineers.
Summary
TigerGraph failures surface in subtle ways — loading job stalls with partial data imports, GSQL query timeouts under load, replica lag on read-heavy analytics workloads, and per-graph schema failures in multi-graph deployments — long before your users see errors. Vigilmon gives you external visibility across the full failure surface:
| Monitor Type | What It Covers |
|---|---|
| HTTP monitor on /health/tigergraph | REST++ API reachability, ping/version checks, GSQL query execution |
| HTTP monitor per instance (primary/replica) | Role-specific availability and replica health |
| HTTP monitor per graph (multi-graph) | Isolated graph health in multi-graph deployments |
| Heartbeat monitor: loading job | ETL pipeline completion, partial import detection |
| Heartbeat monitor: analytics query | Scheduled GSQL query liveness, computation pipeline health |
Get started free at vigilmon.online — your first TigerGraph monitor is running in under two minutes.