Skip to content
LabTether

Slow UI and Performance

The console feels sluggish, pages take a long time to load, or the hub host is using more CPU and memory than expected.

Slow console

The console loads but interactions feel laggy -- route transitions are slow, tables take a long time to render, or the browser tab itself becomes unresponsive.

Browser DevTools check. Open your browser's developer tools (F12) and switch to the Network tab. Reload the slow page and look for:

  • API requests that take more than a few seconds to complete. These point to a backend bottleneck.
  • A large number of simultaneous requests. Some pages make many parallel calls, and if the hub is under load, they queue up.
  • JavaScript errors in the Console tab. A frontend error can cause rendering to stall even if the data loads fine.

Large dataset pages. Pages that display large inventories (hundreds of nodes, thousands of log entries) are naturally slower than pages with a handful of items. If the slow page is the Devices list or the Logs view:

  • Use filters and time ranges to reduce the result set.
  • On the Devices page, pause briefly while typing search text. The search is debounced, so rapid typing should not fire queries on every keystroke -- but if it does, you may be on an older console build.
  • On the Logs page, narrow the time window. Querying all-time logs on a busy system is expensive.

Asset count scaling. If you have recently added a large number of nodes or connectors, the hub's status aggregation may be doing more work per poll cycle. This is expected, but if the console was fast before and slow after a big inventory expansion, it may be worth checking hub resource usage (next section).

Tip: If only one browser tab is slow but other tabs load the console fine, the slow tab may have accumulated stale WebSocket state. Reload the tab before investigating further.

High hub resource usage

The hub containers are using more CPU or memory than expected, and the console reflects this as slow API responses.

Docker stats. Check real-time resource usage for hub containers:

docker stats --no-stream

Look at CPU percentage and memory usage for the hub and database containers. If the database container is using significantly more resources than usual, the problem is likely query performance.

Postgres performance. The hub's /worker/stats endpoint exposes database query performance data:

curl -s https://<hub-host>:8443/worker/stats \
  -H "Authorization: Bearer <token>" | jq '.performance'

Check performance.pg_stat_statements_enabled -- if it is true, the response includes performance.top_queries which shows the most expensive SQL queries by total time. This tells you exactly where the database is spending its effort.

Common expensive patterns:

  • Log event queries without time-window filters (scanning the entire log_events table)
  • Status aggregation queries that materialize large result sets
  • Telemetry snapshot queries across many assets

Connector sync load. If multiple connectors are syncing simultaneously, they can spike hub CPU and database load. Check whether the performance dip correlates with sync schedules. If it does, stagger connector sync intervals so they do not all fire at the same time.

Docker resource limits. If the hub container is hitting its memory limit, it may be getting OOM-killed and restarting. Check for OOM events:

docker inspect <hub-container> | jq '.[0].State.OOMKilled'
dmesg | grep -i oom

If the hub is consistently bumping against its memory limit, increase the container's memory allocation in your Docker Compose configuration.

Diagnosis steps

When the above checks do not immediately reveal the problem, use these steps to narrow it down systematically.

1. Check hub logs for errors.

docker compose logs hub --tail 100 --since 5m

Look for repeated errors, timeouts, or database connection failures. A single log line that repeats hundreds of times is a strong signal.

2. Check Postgres directly.

If you have access to the database, check for long-running queries and lock contention:

-- Active queries running longer than 5 seconds
SELECT pid, now() - pg_stat_activity.query_start AS duration, query
FROM pg_stat_activity
WHERE state = 'active' AND (now() - pg_stat_activity.query_start) > interval '5 seconds';

-- Lock waits
SELECT * FROM pg_locks WHERE NOT granted;

3. Check Docker resource limits.

Compare actual resource usage against configured limits:

# What limits are set
docker inspect <hub-container> | jq '.[0].HostConfig.Memory, .[0].HostConfig.NanoCpus'

# What is actually being used
docker stats --no-stream --format "table {{.Name}}\t{{.CPUPerc}}\t{{.MemUsage}}"

If the hub is consistently using 90%+ of its allocated resources, the limits may simply be too low for your inventory size.

4. Profile backend hotspots.

For deeper investigation, the hub exposes Go pprof endpoints:

# 30-second CPU profile
curl -s https://<hub-host>:8443/debug/pprof/profile?seconds=30 -o cpu.prof

# Heap snapshot
curl -s https://<hub-host>:8443/debug/pprof/heap -o heap.prof

# Analyze with go tool
go tool pprof cpu.prof

These require authentication. The CPU profile will show exactly which code paths are consuming the most time, and the heap profile shows where memory is being allocated.

Tip: Capture a /worker/stats snapshot before and after a 2-3 minute console browsing session. Comparing the two snapshots shows you which queries grew the most during that window, making it easy to identify the specific bottleneck.