LibGraph is a pure-Elixir library for working with directed and undirected graphs, weighted edges, and algorithms like Dijkstra shortest path, Bellman-Ford, topological sort, and DFS/BFS traversal. When LibGraph powers recommendation engines, dependency resolvers, route planners, or workflow orchestration in production, silent failures in graph construction or expensive algorithm runs that never complete translate into degraded features. Vigilmon gives you uptime checks, heartbeat monitoring, and alerting so graph processing failures surface before users notice missing recommendations or stalled workflows.
What You'll Set Up
- HTTP health endpoint that validates graph construction and a basic algorithm run
- Cron heartbeat for scheduled graph processing jobs
- Latency alerting for long-running graph algorithm executions
- Alerting when graph worker queues stall
Prerequisites
- Elixir 1.14+ with the
libgraphpackage in yourmix.exs - A Phoenix or Plug application that uses LibGraph for at least one production feature
- A free Vigilmon account
Step 1: Add a Health Endpoint That Tests Graph Construction
Exercise LibGraph directly in your health check so Vigilmon catches regressions in graph operations:
# lib/my_app_web/controllers/health_controller.ex
defmodule MyAppWeb.HealthController do
use MyAppWeb, :controller
def index(conn, _params) do
case check_graph_pipeline() do
{:ok, info} ->
json(conn, Map.merge(%{status: "ok"}, info))
{:error, reason} ->
conn
|> put_status(503)
|> json(%{status: "error", reason: inspect(reason)})
end
end
defp check_graph_pipeline do
try do
start = System.monotonic_time(:millisecond)
graph =
Graph.new()
|> Graph.add_edge(:a, :b, weight: 1)
|> Graph.add_edge(:b, :c, weight: 2)
|> Graph.add_edge(:a, :c, weight: 5)
case Graph.dijkstra(graph, :a, :c) do
nil ->
{:error, "dijkstra returned nil for known graph"}
_path ->
duration_ms = System.monotonic_time(:millisecond) - start
{:ok, %{libgraph: "operational", algo_ms: duration_ms}}
end
rescue
e -> {:error, Exception.message(e)}
end
end
end
Wire the route:
# lib/my_app_web/router.ex
scope "/health" do
get "/", HealthController, :index
end
Verify:
mix phx.server
curl http://localhost:4000/health
# {"status":"ok","libgraph":"operational","algo_ms":1}
Step 2: Add the Monitor in Vigilmon
- Log in to vigilmon.online and click Add Monitor.
- Set Type to
HTTP / HTTPS. - Enter your health URL:
https://myapp.example.com/health. - Set Check interval to
1 minute. - Set Expected HTTP status to
200. - Under Response body, enable Contains keyword and enter
"operational". - Click Save.
The keyword check ensures Vigilmon raises an alert if your app responds with 200 but the graph pipeline reports "error" — catching crashes in LibGraph operations that don't bubble up to an HTTP 500.
Step 3: Emit Telemetry for Algorithm Execution Time
Graph algorithms on large datasets can silently degrade in performance as the graph grows. Instrument your algorithm calls so you can detect latency regressions early:
defmodule MyApp.GraphService do
require Logger
def shortest_path(graph, source, target) do
start = System.monotonic_time(:millisecond)
result = Graph.dijkstra(graph, source, target)
duration_ms = System.monotonic_time(:millisecond) - start
:telemetry.execute(
[:my_app, :graph, :dijkstra],
%{duration_ms: duration_ms},
%{source: source, target: target, found: result != nil}
)
if duration_ms > 500 do
Logger.warning("LibGraph Dijkstra took #{duration_ms}ms (source=#{source} target=#{target})")
end
result
end
def sort_dependencies(graph) do
start = System.monotonic_time(:millisecond)
result = Graph.topsort(graph)
duration_ms = System.monotonic_time(:millisecond) - start
:telemetry.execute(
[:my_app, :graph, :topsort],
%{duration_ms: duration_ms},
%{vertex_count: Graph.num_vertices(graph)}
)
result
end
end
Attach a handler to log slow algorithm runs:
# In your Application.start/2
:telemetry.attach_many(
"libgraph-slow-algos",
[
[:my_app, :graph, :dijkstra],
[:my_app, :graph, :topsort]
],
fn event, %{duration_ms: ms}, meta, _config ->
algo = List.last(event)
if ms > 1000 do
Logger.error("Slow LibGraph #{algo}: #{ms}ms #{inspect(meta)}")
end
end,
nil
)
Expose the latest algorithm latency in your health endpoint so Vigilmon can alert when response time exceeds a threshold.
Step 4: Heartbeat for Scheduled Graph Processing Jobs
If your app pre-computes graphs on a schedule — rebuilding a recommendation graph nightly, recomputing dependency trees on new deployments, refreshing route networks hourly — add a Vigilmon heartbeat:
- In Vigilmon, click Add Monitor → Cron Heartbeat.
- Set Expected ping interval to match your job schedule (e.g.
60minutes for an hourly rebuild). - Copy the heartbeat URL (e.g.
https://vigilmon.online/heartbeat/abc123).
Ping Vigilmon at the end of a successful run:
defmodule MyApp.GraphRebuildJob do
require Logger
def run do
Logger.info("Starting graph rebuild")
start = System.monotonic_time(:millisecond)
graph = build_graph_from_database()
case Graph.is_acyclic?(graph) do
true ->
:ok = store_graph(graph)
duration_ms = System.monotonic_time(:millisecond) - start
Logger.info("Graph rebuilt in #{duration_ms}ms, #{Graph.num_vertices(graph)} vertices")
ping_vigilmon()
false ->
Logger.error("Graph rebuild produced a cycle — aborting store")
{:error, :cyclic_graph}
end
end
defp ping_vigilmon do
url = System.get_env("VIGILMON_GRAPH_REBUILD_HEARTBEAT_URL")
if url, do: :httpc.request(:get, {String.to_charlist(url), []}, [], [])
end
defp build_graph_from_database do
# Query edges from your DB and construct the graph
Graph.new()
end
defp store_graph(_graph), do: :ok
end
If the rebuild crashes or produces an invalid graph and never pings, Vigilmon alerts you.
Step 5: Monitor Graph Size Thresholds
Very large graphs can cause memory pressure or algorithm timeouts. Add size checks to your health endpoint and alert when thresholds are exceeded:
defmodule MyAppWeb.HealthController do
use MyAppWeb, :controller
@max_vertices 1_000_000
def index(conn, _params) do
graph = MyApp.GraphStore.current_graph()
vertex_count = Graph.num_vertices(graph)
cond do
vertex_count > @max_vertices ->
conn
|> put_status(503)
|> json(%{
status: "error",
libgraph: "graph_too_large",
vertices: vertex_count,
max: @max_vertices
})
true ->
json(conn, %{
status: "ok",
libgraph: "operational",
vertices: vertex_count
})
end
end
end
Vigilmon will alert when vertex_count causes the endpoint to return 503, giving you advance warning of memory risk before the node OOMs.
Step 6: Configure Alert Channels
- Go to Alert Channels in Vigilmon and add Slack, email, or PagerDuty.
- Set Consecutive failures before alert to
2— a single slow algorithm run may be a one-off, but two consecutive failures warrant attention. - Add a Maintenance window during scheduled graph rebuilds when the in-memory graph is temporarily stale:
curl -X POST https://vigilmon.online/api/maintenance \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{"monitor_id": "abc123", "duration_minutes": 10}'
Summary
| Monitor | Target | What It Catches |
|---|---|---|
| HTTP health check | /health on your app | LibGraph construction failures, algorithm errors |
| Response keyword | "operational" in body | Graph pipeline degraded despite 200 response |
| Cron heartbeat | Heartbeat URL | Silent graph rebuild job failure |
| Graph size check | Vertex count threshold | Memory risk from unbounded graph growth |
| Telemetry latency | Algorithm execution time | Dijkstra / topsort regressions on growing graphs |
LibGraph brings powerful graph algorithms to Elixir — Vigilmon makes sure the pipelines built on those algorithms stay healthy in production. With a graph-exercising health endpoint, heartbeat monitoring for scheduled rebuild jobs, and size threshold alerts, you get full visibility into your graph processing layer.