tutorial

How to Monitor LibGraph with Vigilmon

LibGraph is a graph data structure and algorithms library for Elixir. Learn how to monitor graph processing workloads, track algorithm latency, and alert on failures using Vigilmon.

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 libgraph package in your mix.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

  1. Log in to vigilmon.online and click Add Monitor.
  2. Set Type to HTTP / HTTPS.
  3. Enter your health URL: https://myapp.example.com/health.
  4. Set Check interval to 1 minute.
  5. Set Expected HTTP status to 200.
  6. Under Response body, enable Contains keyword and enter "operational".
  7. 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:

  1. In Vigilmon, click Add MonitorCron Heartbeat.
  2. Set Expected ping interval to match your job schedule (e.g. 60 minutes for an hourly rebuild).
  3. 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

  1. Go to Alert Channels in Vigilmon and add Slack, email, or PagerDuty.
  2. Set Consecutive failures before alert to 2 — a single slow algorithm run may be a one-off, but two consecutive failures warrant attention.
  3. 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.

Monitor your app with Vigilmon

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

Start free →