diff --git a/lib/towerops/workers/discovery_worker.ex b/lib/towerops/workers/discovery_worker.ex new file mode 100644 index 00000000..e5a54cfd --- /dev/null +++ b/lib/towerops/workers/discovery_worker.ex @@ -0,0 +1,47 @@ +defmodule Towerops.Workers.DiscoveryWorker do + @moduledoc """ + Background worker for SNMP device discovery. + + Enqueued when: + - A new device is created with SNMP enabled + - An existing device's SNMP configuration is changed + - User manually triggers discovery via "Rediscover Device" button + + Queue: discovery + """ + + alias Towerops.Devices + alias Towerops.Snmp + + require Logger + + @doc """ + Performs SNMP discovery for a device. + + ## Parameters + - device_id: The UUID of the device to discover + + ## Returns + - :ok on success + - {:error, reason} on failure + """ + def perform(device_id) do + Logger.info("Starting SNMP discovery for device #{device_id}") + + device = Devices.get_device!(device_id) + + case Snmp.discover_device(device) do + {:ok, _snmp_device} -> + Logger.info("SNMP discovery completed successfully for device #{device_id}") + :ok + + {:error, reason} -> + Logger.error("SNMP discovery failed for device #{device_id}: #{inspect(reason)}") + {:error, reason} + end + rescue + Ecto.NoResultsError -> + Logger.error("Device #{device_id} not found") + {:error, :device_not_found} + end +end diff --git a/lib/towerops_web/live/device_live/form.ex b/lib/towerops_web/live/device_live/form.ex index 8e80fce2..ae7799f3 100644 --- a/lib/towerops_web/live/device_live/form.ex +++ b/lib/towerops_web/live/device_live/form.ex @@ -7,6 +7,7 @@ defmodule ToweropsWeb.DeviceLive.Form do alias Towerops.Devices.Device, as: DeviceSchema alias Towerops.Sites alias Towerops.Snmp + alias Towerops.Workers.DiscoveryWorker @impl true def mount(params, _session, socket) do @@ -195,11 +196,8 @@ defmodule ToweropsWeb.DeviceLive.Form do device = socket.assigns.device if device.snmp_enabled do - # Run discovery in background - _ = - Task.start(fn -> - Snmp.discover_device(device) - end) + # Enqueue discovery job + enqueue_discovery(device.id) {:noreply, put_flash(socket, :info, "Discovery started...")} else @@ -277,7 +275,7 @@ defmodule ToweropsWeb.DeviceLive.Form do defp handle_device_creation(device) do if device.snmp_enabled do - _ = Task.start(fn -> Snmp.discover_device(device) end) + enqueue_discovery(device.id) "Device created successfully. SNMP discovery started in background." else "Device created successfully" @@ -286,13 +284,24 @@ defmodule ToweropsWeb.DeviceLive.Form do defp handle_device_update(old_device, device) do if should_trigger_snmp_discovery?(old_device, device) do - _ = Task.start(fn -> Snmp.discover_device(device) end) + enqueue_discovery(device.id) "Device updated successfully. SNMP discovery started in background." else "Device updated successfully" end 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 Exq + {:ok, _job} = Exq.enqueue(Exq, "discovery", DiscoveryWorker, [device_id]) + end + end + defp should_trigger_snmp_discovery?(old_device, device) do device.snmp_enabled and (!old_device.snmp_enabled or