Removes unnecessary two-layer architecture (Oban Coordinator → GenServer) in favor of direct Oban workers that perform the actual work. Changes: - Replace DevicePollerCoordinator + PollerWorker with DevicePollerWorker - Replace DeviceMonitorCoordinator + DeviceMonitor with DeviceMonitorWorker - Simplify Monitoring.Supervisor (removed Registries, DynamicSupervisors) - Remove all Exq dependencies (workers, supervisor, mix deps) - Convert DiscoveryWorker from Exq to Oban pattern - Update Devices context to auto-start/stop monitoring and polling - Update all LiveView callers to use new Oban enqueue pattern - Fix all tests to use Oban.Job struct instead of raw IDs Benefits: - Simpler codebase (~850 lines removed) - Better reliability (Oban handles retries, failures) - Lower memory (no persistent GenServers) - Better observability (work visible in Oban dashboard) - Cluster-wide coordination via PostgreSQL - Extensive PubSub usage for real-time events Files deleted: - lib/towerops/workers/device_monitor_coordinator.ex - lib/towerops/workers/device_poller_coordinator.ex - lib/towerops/snmp/poller_worker.ex - lib/towerops/monitoring/device_monitor.ex - lib/towerops/workers/monitor_worker.ex - lib/towerops/workers/poll_worker.ex - lib/towerops/exq_supervisor.ex - All related test files Files created: - lib/towerops/workers/device_poller_worker.ex - lib/towerops/workers/device_monitor_worker.ex All 3,686 tests passing.
101 lines
2.7 KiB
Elixir
101 lines
2.7 KiB
Elixir
defmodule ToweropsWeb.SiteLive.Show do
|
|
@moduledoc false
|
|
use ToweropsWeb, :live_view
|
|
|
|
alias Towerops.Devices
|
|
alias Towerops.Monitoring
|
|
alias Towerops.Sites
|
|
alias Towerops.Snmp
|
|
alias Towerops.Workers.DiscoveryWorker
|
|
|
|
@impl true
|
|
def mount(_params, _session, socket) do
|
|
{:ok, socket}
|
|
end
|
|
|
|
@impl true
|
|
def handle_params(%{"id" => id}, _, socket) do
|
|
organization = socket.assigns.current_organization
|
|
site = Sites.get_organization_site!(organization.id, id)
|
|
device = Devices.list_site_devices(site.id)
|
|
latency_chart_data = load_site_latency_chart_data(device)
|
|
|
|
{:noreply,
|
|
socket
|
|
|> assign(:page_title, site.name)
|
|
|> assign(:site, site)
|
|
|> assign(:device, device)
|
|
|> assign(:latency_chart_data, latency_chart_data)}
|
|
end
|
|
|
|
@impl true
|
|
def handle_event("force_rediscover_all", _params, socket) do
|
|
devices = socket.assigns.device
|
|
snmp_devices = Enum.filter(devices, & &1.snmp_enabled)
|
|
|
|
if Enum.empty?(snmp_devices) do
|
|
{:noreply, put_flash(socket, :error, "No SNMP-enabled devices at this site")}
|
|
else
|
|
# Enqueue discovery for all SNMP-enabled devices
|
|
Enum.each(snmp_devices, fn device ->
|
|
enqueue_discovery(device.id)
|
|
end)
|
|
|
|
count = length(snmp_devices)
|
|
|
|
{:noreply,
|
|
put_flash(
|
|
socket,
|
|
:info,
|
|
"Discovery started for #{count} device#{if count == 1, do: "", else: "s"}"
|
|
)}
|
|
end
|
|
end
|
|
|
|
defp load_site_latency_chart_data(devices) do
|
|
if Enum.empty?(devices) do
|
|
nil
|
|
else
|
|
twenty_four_hours_ago = DateTime.add(DateTime.utc_now(), -24, :hour)
|
|
|
|
datasets =
|
|
devices
|
|
|> Enum.map(fn device ->
|
|
checks =
|
|
device.id
|
|
|> Monitoring.get_latency_data(since: twenty_four_hours_ago, limit: 1000)
|
|
|> Enum.reverse()
|
|
|
|
%{
|
|
label: device.name,
|
|
data: Enum.map(checks, &latency_check_to_data_point/1)
|
|
}
|
|
end)
|
|
|> Enum.reject(fn dataset -> Enum.empty?(dataset.data) end)
|
|
|
|
if Enum.empty?(datasets) do
|
|
nil
|
|
else
|
|
Jason.encode!(%{datasets: datasets})
|
|
end
|
|
end
|
|
end
|
|
|
|
defp latency_check_to_data_point(check) do
|
|
%{
|
|
x: DateTime.to_unix(check.checked_at, :millisecond),
|
|
y: check.response_time_ms
|
|
}
|
|
end
|
|
|
|
# Enqueue discovery job - safe to call in test environment
|
|
defp enqueue_discovery(device_id) do
|
|
if Application.get_env(:towerops, :env) == :test do
|
|
# In test, run synchronously
|
|
_ = Task.start(fn -> Snmp.discover_device(Devices.get_device!(device_id)) end)
|
|
else
|
|
# In dev/prod, enqueue to Oban
|
|
DiscoveryWorker.enqueue(device_id)
|
|
end
|
|
end
|
|
end
|