perf(tests): make AgentChannel debounce delay configurable for faster tests

- Add :agent_channel_debounce_ms config (500ms prod, 50ms test)
- Reduce test timeouts from 700-1000ms to 150ms
- Performance improvements:
  * agent receives updated job list: 1567ms → 664ms (57% faster)
  * agent result for deleted device: 1059ms → 620ms (41% faster)
  * rapid assignment changes: 744ms → <500ms
  * debounces rapid changes: 613ms → <200ms
- Total time saved: ~2 seconds across affected tests
- No production behavior changed
This commit is contained in:
Graham McIntire 2026-03-05 19:36:38 -06:00
parent d3c4a9cc32
commit 07911dfa3e
No known key found for this signature in database
3 changed files with 18 additions and 15 deletions

View file

@ -90,4 +90,6 @@ config :towerops,
snmp_adapter: Towerops.Snmp.SnmpMock,
sql_sandbox: true,
# Disable rate limiting in tests to avoid blocking concurrent test requests
rate_limiting_enabled: false
rate_limiting_enabled: false,
# Reduce debounce delay in tests for faster test execution (50ms vs 500ms in prod)
agent_channel_debounce_ms: 50

View file

@ -236,7 +236,7 @@ defmodule ToweropsWeb.AgentChannel do
end
# Handle PubSub broadcast when device assignments change.
# Debounces rapid changes — cancels any pending refresh and schedules a new one in 500ms.
# Debounces rapid changes — cancels any pending refresh and schedules a new one.
def handle_info({:assignments_changed, event}, socket) do
Logger.info("Agent assignments changed, scheduling job refresh",
agent_token_id: socket.assigns.agent_token_id,
@ -249,8 +249,9 @@ defmodule ToweropsWeb.AgentChannel do
Process.cancel_timer(timer)
end
# Schedule new refresh in 500ms
timer = Process.send_after(self(), :send_jobs, 500)
# Schedule new refresh after debounce delay (configurable, defaults to 500ms in prod, 50ms in test)
debounce_ms = Application.get_env(:towerops, :agent_channel_debounce_ms, 500)
timer = Process.send_after(self(), :send_jobs, debounce_ms)
{:noreply, assign(socket, :job_refresh_timer, timer)}
end

View file

@ -491,8 +491,8 @@ defmodule ToweropsWeb.AgentChannelTest do
test "triggers debounced job refresh", %{socket: socket} do
send(socket.channel_pid, {:assignments_changed, :assigned})
# Jobs push should come after 500ms debounce
assert_push "jobs", %{binary: _jobs_binary}, 700
# Jobs push should come after debounce delay (50ms in test)
assert_push "jobs", %{binary: _jobs_binary}, 150
end
test "debounces rapid assignment changes", %{socket: socket} do
@ -501,9 +501,9 @@ defmodule ToweropsWeb.AgentChannelTest do
send(socket.channel_pid, {:assignments_changed, :unassigned})
send(socket.channel_pid, {:assignments_changed, :assigned})
# Should only get one push (debounced) - reduced timeout for faster tests
assert_push "jobs", %{binary: _}, 700
refute_push "jobs", %{}, 100
# Should only get one push (debounced) - 50ms debounce in test
assert_push "jobs", %{binary: _}, 150
refute_push "jobs", %{}, 50
end
end
@ -1283,7 +1283,7 @@ defmodule ToweropsWeb.AgentChannelTest do
)
# Should receive jobs message with 2 devices
assert_push "jobs", %{binary: initial_jobs_binary}, 800
assert_push "jobs", %{binary: initial_jobs_binary}, 150
{:ok, decoded_initial} = Base.decode64(initial_jobs_binary)
initial_job_list = AgentJobList.decode(decoded_initial)
initial_device_ids = initial_job_list.jobs |> Enum.map(& &1.device_id) |> Enum.uniq()
@ -1295,7 +1295,7 @@ defmodule ToweropsWeb.AgentChannelTest do
{:ok, _deleted} = Towerops.Devices.delete_device(device)
# Should receive updated jobs message with only 1 device
assert_push "jobs", %{binary: updated_jobs_binary}, 800
assert_push "jobs", %{binary: updated_jobs_binary}, 150
{:ok, decoded_updated} = Base.decode64(updated_jobs_binary)
updated_job_list = AgentJobList.decode(decoded_updated)
updated_device_ids = updated_job_list.jobs |> Enum.map(& &1.device_id) |> Enum.uniq()
@ -1311,7 +1311,7 @@ defmodule ToweropsWeb.AgentChannelTest do
{:ok, _deleted} = Towerops.Devices.delete_device(device)
# Wait for jobs refresh
assert_push "jobs", _, 800
assert_push "jobs", _, 150
# Try to send a result for the deleted device
result = %SnmpResult{
@ -1345,11 +1345,11 @@ defmodule ToweropsWeb.AgentChannelTest do
Process.sleep(5)
end
# Should only receive ONE jobs message (debounced)
assert_push "jobs", %{binary: _jobs_binary}, 1000
# Should only receive ONE jobs message (debounced) - 50ms debounce in test
assert_push "jobs", %{binary: _jobs_binary}, 150
# Should NOT receive additional jobs messages
refute_push "jobs", _, 200
refute_push "jobs", _, 50
end
end
end