fix: resolve all dialyzer unmatched return and pattern match warnings
Fixed dialyzer warnings across multiple files by properly handling return
values from functions that are called for side effects.
Changes:
- lib/towerops/agents.ex: Explicitly match broadcast and if-expression returns
- lib/towerops/devices.ex: Match worker start function returns in if-expressions
- lib/towerops/workers/agent_latency_evaluator.ex: Match broadcast return
- lib/towerops/workers/device_monitor_worker.ex: Match perform_check and handle_status_change returns, handle schedule_next_check errors
- lib/towerops/workers/device_poller_worker.ex: Match all PubSub broadcast returns, handle schedule_next_poll errors, remove unreachable pattern
- lib/towerops/workers/stale_agent_worker.ex: Match process_stale_agents and broadcast returns
- lib/towerops_web/channels/agent_channel.ex: Match PubSub.subscribe return, improve get_addr pattern matching, remove unreachable format_ip clause
- lib/towerops_web/live/device_live/form.ex: Match enqueue_discovery return, replace compile-time @dev_env with runtime check
Pattern applied:
- PubSub broadcasts: `_ = Phoenix.PubSub.broadcast(...)`
- If-expressions with side effects: `_ = if condition do ... end`
- Critical operations: Added error logging with case statements
All 3625 tests passing. No dialyzer warnings remaining in lib/towerops or lib/towerops_web.
🤖 Generated with Claude Code
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
2e5faf7159
commit
6c1f344b5e
9 changed files with 129 additions and 119 deletions
|
|
@ -1,24 +1,3 @@
|
|||
# Dialyzer warnings to ignore
|
||||
# These are either false positives or intentional design choices
|
||||
[
|
||||
# SnmpKit library warnings (third-party code in lib/snmpkit/)
|
||||
~r/lib\/snmpkit\//,
|
||||
|
||||
# Unmatched return values (intentionally ignored for fire-and-forget operations)
|
||||
{"lib/towerops/agents.ex", :unmatched_return},
|
||||
{"lib/towerops/devices.ex", :unmatched_return},
|
||||
{"lib/towerops/workers/agent_latency_evaluator.ex", :unmatched_return},
|
||||
{"lib/towerops/workers/device_monitor_worker.ex", :unmatched_return},
|
||||
{"lib/towerops/workers/device_poller_worker.ex", :unmatched_return},
|
||||
{"lib/towerops/workers/stale_agent_worker.ex", :unmatched_return},
|
||||
{"lib/towerops_web/channels/agent_channel.ex", :unmatched_return},
|
||||
{"lib/towerops_web/live/device_live/form.ex", :unmatched_return},
|
||||
|
||||
# Pattern match coverage warnings (intentional exhaustive patterns)
|
||||
{"lib/towerops/workers/device_poller_worker.ex", :pattern_match_cov},
|
||||
{"lib/towerops_web/channels/agent_channel.ex", :pattern_match_cov},
|
||||
|
||||
# Guard failures and unused functions in form helpers
|
||||
{"lib/towerops_web/live/device_live/form.ex", :guard_fail},
|
||||
{"lib/towerops_web/live/device_live/form.ex", :unused_fun}
|
||||
]
|
||||
# Dialyzer false positives to ignore
|
||||
# Fix all warnings - do not suppress
|
||||
[]
|
||||
|
|
|
|||
|
|
@ -294,7 +294,7 @@ defmodule Towerops.Agents do
|
|||
|
||||
case result do
|
||||
{:ok, assignment} ->
|
||||
broadcast_assignment_change(agent_token_id, :device_assigned)
|
||||
_ = broadcast_assignment_change(agent_token_id, :device_assigned)
|
||||
{:ok, assignment}
|
||||
|
||||
error ->
|
||||
|
|
@ -321,9 +321,10 @@ defmodule Towerops.Agents do
|
|||
|> Repo.delete_all()
|
||||
|
||||
# Notify the agent that was previously assigned
|
||||
if current_assignment do
|
||||
broadcast_assignment_change(current_assignment.agent_token_id, :device_unassigned)
|
||||
end
|
||||
_ =
|
||||
if current_assignment do
|
||||
broadcast_assignment_change(current_assignment.agent_token_id, :device_unassigned)
|
||||
end
|
||||
|
||||
result
|
||||
end
|
||||
|
|
@ -466,10 +467,11 @@ defmodule Towerops.Agents do
|
|||
case result do
|
||||
{:ok, assignment} ->
|
||||
# Notify both the old and new agents if they're different
|
||||
if old_agent_id != agent_token_id do
|
||||
broadcast_assignment_change(old_agent_id, :device_unassigned)
|
||||
broadcast_assignment_change(agent_token_id, :device_assigned)
|
||||
end
|
||||
_ =
|
||||
if old_agent_id != agent_token_id do
|
||||
_ = broadcast_assignment_change(old_agent_id, :device_unassigned)
|
||||
broadcast_assignment_change(agent_token_id, :device_assigned)
|
||||
end
|
||||
|
||||
{:ok, assignment}
|
||||
|
||||
|
|
|
|||
|
|
@ -259,13 +259,15 @@ defmodule Towerops.Devices do
|
|||
|> Repo.insert() do
|
||||
{:ok, device} = result ->
|
||||
# Start monitoring/polling if enabled
|
||||
if device.monitoring_enabled do
|
||||
DeviceMonitorWorker.start_monitoring(device.id)
|
||||
end
|
||||
_ =
|
||||
if device.monitoring_enabled do
|
||||
DeviceMonitorWorker.start_monitoring(device.id)
|
||||
end
|
||||
|
||||
if device.snmp_enabled do
|
||||
DevicePollerWorker.start_polling(device.id)
|
||||
end
|
||||
_ =
|
||||
if device.snmp_enabled do
|
||||
DevicePollerWorker.start_polling(device.id)
|
||||
end
|
||||
|
||||
result
|
||||
|
||||
|
|
@ -285,8 +287,8 @@ defmodule Towerops.Devices do
|
|||
|> DeviceSchema.changeset(attrs)
|
||||
|> Repo.update() do
|
||||
{:ok, updated_device} = result ->
|
||||
handle_monitoring_changes(updated_device, old_monitoring)
|
||||
handle_snmp_changes(updated_device, old_snmp)
|
||||
_ = handle_monitoring_changes(updated_device, old_monitoring)
|
||||
_ = handle_snmp_changes(updated_device, old_snmp)
|
||||
result
|
||||
|
||||
error ->
|
||||
|
|
|
|||
|
|
@ -80,7 +80,7 @@ defmodule Towerops.Workers.AgentLatencyEvaluator do
|
|||
|
||||
case result do
|
||||
{:ok, _} ->
|
||||
broadcast_reassignment(candidate)
|
||||
_ = broadcast_reassignment(candidate)
|
||||
:ok
|
||||
|
||||
{:error, reason} ->
|
||||
|
|
|
|||
|
|
@ -33,12 +33,21 @@ defmodule Towerops.Workers.DeviceMonitorWorker do
|
|||
:ok
|
||||
|
||||
device ->
|
||||
if device.monitoring_enabled do
|
||||
perform_check(device)
|
||||
end
|
||||
_ =
|
||||
if device.monitoring_enabled do
|
||||
perform_check(device)
|
||||
end
|
||||
|
||||
# Schedule next check
|
||||
schedule_next_check(device_id)
|
||||
case schedule_next_check(device_id) do
|
||||
{:ok, _job} ->
|
||||
:ok
|
||||
|
||||
{:error, changeset} ->
|
||||
Logger.error("Failed to schedule next monitoring check for device #{device_id}: #{inspect(changeset.errors)}")
|
||||
|
||||
:ok
|
||||
end
|
||||
|
||||
:ok
|
||||
end
|
||||
|
|
@ -108,16 +117,18 @@ defmodule Towerops.Workers.DeviceMonitorWorker do
|
|||
|
||||
_ = Devices.update_device_status(device, new_status)
|
||||
|
||||
if old_status != new_status do
|
||||
handle_status_change(device, old_status, new_status)
|
||||
end
|
||||
_ =
|
||||
if old_status != new_status do
|
||||
handle_status_change(device, old_status, new_status)
|
||||
end
|
||||
|
||||
# Broadcast status change via PubSub
|
||||
Phoenix.PubSub.broadcast(
|
||||
Towerops.PubSub,
|
||||
"device:#{device.id}",
|
||||
{:device_status_changed, device.id, new_status, nil}
|
||||
)
|
||||
_ =
|
||||
Phoenix.PubSub.broadcast(
|
||||
Towerops.PubSub,
|
||||
"device:#{device.id}",
|
||||
{:device_status_changed, device.id, new_status, nil}
|
||||
)
|
||||
end
|
||||
|
||||
defp check_device_health(device) do
|
||||
|
|
@ -155,11 +166,12 @@ defmodule Towerops.Workers.DeviceMonitorWorker do
|
|||
message: alert_message
|
||||
})
|
||||
|
||||
Phoenix.PubSub.broadcast(
|
||||
Towerops.PubSub,
|
||||
"alerts:new",
|
||||
{:new_alert, device.id, :device_down}
|
||||
)
|
||||
_ =
|
||||
Phoenix.PubSub.broadcast(
|
||||
Towerops.PubSub,
|
||||
"alerts:new",
|
||||
{:new_alert, device.id, :device_down}
|
||||
)
|
||||
end
|
||||
|
||||
defp get_down_alert_message(device) do
|
||||
|
|
@ -183,11 +195,12 @@ defmodule Towerops.Workers.DeviceMonitorWorker do
|
|||
|
||||
resolve_down_alert(device)
|
||||
|
||||
Phoenix.PubSub.broadcast(
|
||||
Towerops.PubSub,
|
||||
"alerts:resolved",
|
||||
{:alert_resolved, device.id, :device_down}
|
||||
)
|
||||
_ =
|
||||
Phoenix.PubSub.broadcast(
|
||||
Towerops.PubSub,
|
||||
"alerts:resolved",
|
||||
{:alert_resolved, device.id, :device_down}
|
||||
)
|
||||
end
|
||||
|
||||
defp get_recovery_message(device) do
|
||||
|
|
|
|||
|
|
@ -45,7 +45,16 @@ defmodule Towerops.Workers.DevicePollerWorker do
|
|||
|
||||
# Schedule next poll
|
||||
poll_interval = get_poll_interval(device)
|
||||
schedule_next_poll(device_id, poll_interval)
|
||||
|
||||
case schedule_next_poll(device_id, poll_interval) do
|
||||
{:ok, _job} ->
|
||||
:ok
|
||||
|
||||
{:error, changeset} ->
|
||||
Logger.error("Failed to schedule next poll for device #{device_id}: #{inspect(changeset.errors)}")
|
||||
|
||||
:ok
|
||||
end
|
||||
|
||||
:ok
|
||||
end
|
||||
|
|
@ -136,11 +145,12 @@ defmodule Towerops.Workers.DevicePollerWorker do
|
|||
poll_sensors(snmp_device.sensors, client_opts, now)
|
||||
Logger.debug("Polled #{length(snmp_device.sensors)} sensors for #{device.name}")
|
||||
|
||||
Phoenix.PubSub.broadcast(
|
||||
Towerops.PubSub,
|
||||
"device:#{device.id}",
|
||||
{:sensors_updated, device.id}
|
||||
)
|
||||
_ =
|
||||
Phoenix.PubSub.broadcast(
|
||||
Towerops.PubSub,
|
||||
"device:#{device.id}",
|
||||
{:sensors_updated, device.id}
|
||||
)
|
||||
rescue
|
||||
error ->
|
||||
Logger.error("Error polling sensors for #{device.name}: #{inspect(error)}\n#{Exception.format_stacktrace()}")
|
||||
|
|
@ -150,11 +160,12 @@ defmodule Towerops.Workers.DevicePollerWorker do
|
|||
poll_state_sensors(snmp_device.state_sensors, client_opts, now, device.id)
|
||||
Logger.debug("Polled #{length(snmp_device.state_sensors)} state sensors for #{device.name}")
|
||||
|
||||
Phoenix.PubSub.broadcast(
|
||||
Towerops.PubSub,
|
||||
"device:#{device.id}",
|
||||
{:state_sensors_updated, device.id}
|
||||
)
|
||||
_ =
|
||||
Phoenix.PubSub.broadcast(
|
||||
Towerops.PubSub,
|
||||
"device:#{device.id}",
|
||||
{:state_sensors_updated, device.id}
|
||||
)
|
||||
rescue
|
||||
error ->
|
||||
Logger.error("Error polling state sensors for #{device.name}: #{inspect(error)}\n#{Exception.format_stacktrace()}")
|
||||
|
|
@ -164,11 +175,12 @@ defmodule Towerops.Workers.DevicePollerWorker do
|
|||
poll_interfaces(snmp_device.interfaces, client_opts, now)
|
||||
Logger.debug("Polled #{length(snmp_device.interfaces)} interfaces for #{device.name}")
|
||||
|
||||
Phoenix.PubSub.broadcast(
|
||||
Towerops.PubSub,
|
||||
"device:#{device.id}",
|
||||
{:interfaces_updated, device.id}
|
||||
)
|
||||
_ =
|
||||
Phoenix.PubSub.broadcast(
|
||||
Towerops.PubSub,
|
||||
"device:#{device.id}",
|
||||
{:interfaces_updated, device.id}
|
||||
)
|
||||
rescue
|
||||
error ->
|
||||
Logger.error("Error polling interfaces for #{device.name}: #{inspect(error)}\n#{Exception.format_stacktrace()}")
|
||||
|
|
@ -197,11 +209,12 @@ defmodule Towerops.Workers.DevicePollerWorker do
|
|||
|
||||
Logger.debug("Polled and saved #{length(neighbors)} neighbors for #{device.name}")
|
||||
|
||||
Phoenix.PubSub.broadcast(
|
||||
Towerops.PubSub,
|
||||
"device:#{device.id}",
|
||||
{:neighbors_updated, device.id}
|
||||
)
|
||||
_ =
|
||||
Phoenix.PubSub.broadcast(
|
||||
Towerops.PubSub,
|
||||
"device:#{device.id}",
|
||||
{:neighbors_updated, device.id}
|
||||
)
|
||||
rescue
|
||||
error ->
|
||||
Logger.error("Error polling neighbors for #{device.name}: #{inspect(error)}\n#{Exception.format_stacktrace()}")
|
||||
|
|
@ -217,11 +230,12 @@ defmodule Towerops.Workers.DevicePollerWorker do
|
|||
|
||||
Logger.debug("Polled and saved #{length(arp_entries)} ARP entries for #{device.name}")
|
||||
|
||||
Phoenix.PubSub.broadcast(
|
||||
Towerops.PubSub,
|
||||
"device:#{device.id}",
|
||||
{:arp_updated, device.id}
|
||||
)
|
||||
_ =
|
||||
Phoenix.PubSub.broadcast(
|
||||
Towerops.PubSub,
|
||||
"device:#{device.id}",
|
||||
{:arp_updated, device.id}
|
||||
)
|
||||
rescue
|
||||
error ->
|
||||
Logger.error("Error polling ARP table for #{device.name}: #{inspect(error)}\n#{Exception.format_stacktrace()}")
|
||||
|
|
@ -237,11 +251,12 @@ defmodule Towerops.Workers.DevicePollerWorker do
|
|||
|
||||
Logger.debug("Polled and saved #{length(mac_entries)} MAC FDB entries for #{device.name}")
|
||||
|
||||
Phoenix.PubSub.broadcast(
|
||||
Towerops.PubSub,
|
||||
"device:#{device.id}",
|
||||
{:mac_updated, device.id}
|
||||
)
|
||||
_ =
|
||||
Phoenix.PubSub.broadcast(
|
||||
Towerops.PubSub,
|
||||
"device:#{device.id}",
|
||||
{:mac_updated, device.id}
|
||||
)
|
||||
rescue
|
||||
error ->
|
||||
Logger.error("Error polling MAC FDB table for #{device.name}: #{inspect(error)}\n#{Exception.format_stacktrace()}")
|
||||
|
|
@ -254,11 +269,12 @@ defmodule Towerops.Workers.DevicePollerWorker do
|
|||
poll_processors(processors, client_opts, now)
|
||||
Logger.debug("Polled processors for #{device.name}")
|
||||
|
||||
Phoenix.PubSub.broadcast(
|
||||
Towerops.PubSub,
|
||||
"device:#{device.id}",
|
||||
{:processors_updated, device.id}
|
||||
)
|
||||
_ =
|
||||
Phoenix.PubSub.broadcast(
|
||||
Towerops.PubSub,
|
||||
"device:#{device.id}",
|
||||
{:processors_updated, device.id}
|
||||
)
|
||||
end
|
||||
rescue
|
||||
error ->
|
||||
|
|
@ -272,11 +288,12 @@ defmodule Towerops.Workers.DevicePollerWorker do
|
|||
poll_storage(storage_entries, client_opts, now)
|
||||
Logger.debug("Polled #{length(storage_entries)} storage entries for #{device.name}")
|
||||
|
||||
Phoenix.PubSub.broadcast(
|
||||
Towerops.PubSub,
|
||||
"device:#{device.id}",
|
||||
{:storage_updated, device.id}
|
||||
)
|
||||
_ =
|
||||
Phoenix.PubSub.broadcast(
|
||||
Towerops.PubSub,
|
||||
"device:#{device.id}",
|
||||
{:storage_updated, device.id}
|
||||
)
|
||||
end
|
||||
rescue
|
||||
error ->
|
||||
|
|
@ -318,7 +335,6 @@ defmodule Towerops.Workers.DevicePollerWorker do
|
|||
else
|
||||
{:error, reason} -> {:error, reason}
|
||||
false -> {:error, :invalid_values}
|
||||
_ -> {:error, :unknown}
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -31,9 +31,10 @@ defmodule Towerops.Workers.StaleAgentWorker do
|
|||
def perform(%Oban.Job{}) do
|
||||
stale_agents = find_stale_agents()
|
||||
|
||||
if !Enum.empty?(stale_agents) do
|
||||
process_stale_agents(stale_agents)
|
||||
end
|
||||
_ =
|
||||
if !Enum.empty?(stale_agents) do
|
||||
process_stale_agents(stale_agents)
|
||||
end
|
||||
|
||||
:ok
|
||||
end
|
||||
|
|
@ -50,7 +51,7 @@ defmodule Towerops.Workers.StaleAgentWorker do
|
|||
Enum.each(long_term_stale, fn agent -> log_stale_agent(agent, :debug) end)
|
||||
|
||||
# Broadcast all stale agents for UI updates
|
||||
Phoenix.PubSub.broadcast(Towerops.PubSub, "agents:health", {:agents_stale, stale_agents})
|
||||
_ = Phoenix.PubSub.broadcast(Towerops.PubSub, "agents:health", {:agents_stale, stale_agents})
|
||||
end
|
||||
|
||||
defp log_newly_stale_agents([]), do: :ok
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@ defmodule ToweropsWeb.AgentChannel do
|
|||
|> assign(:organization_id, agent_token.organization_id)
|
||||
|
||||
# Subscribe to assignment changes for this agent
|
||||
Phoenix.PubSub.subscribe(Towerops.PubSub, "agent:#{agent_token.id}:assignments")
|
||||
_ = Phoenix.PubSub.subscribe(Towerops.PubSub, "agent:#{agent_token.id}:assignments")
|
||||
|
||||
# Update last_seen_at and IP on join
|
||||
remote_ip = get_remote_ip(socket)
|
||||
|
|
@ -463,7 +463,7 @@ defmodule ToweropsWeb.AgentChannel do
|
|||
|
||||
pid when is_pid(pid) ->
|
||||
case :ranch.get_addr(pid) do
|
||||
{ip, _port} -> format_ip(ip)
|
||||
{ip, _port} when is_tuple(ip) -> format_ip(ip)
|
||||
_ -> nil
|
||||
end
|
||||
end
|
||||
|
|
@ -476,6 +476,4 @@ defmodule ToweropsWeb.AgentChannel do
|
|||
defp format_ip({a, b, c, d, e, f, g, h}),
|
||||
do:
|
||||
"#{Integer.to_string(a, 16)}:#{Integer.to_string(b, 16)}:#{Integer.to_string(c, 16)}:#{Integer.to_string(d, 16)}:#{Integer.to_string(e, 16)}:#{Integer.to_string(f, 16)}:#{Integer.to_string(g, 16)}:#{Integer.to_string(h, 16)}"
|
||||
|
||||
defp format_ip(_), do: nil
|
||||
end
|
||||
|
|
|
|||
|
|
@ -314,9 +314,10 @@ defmodule ToweropsWeb.DeviceLive.Form do
|
|||
"Device created. "
|
||||
end
|
||||
|
||||
if device.snmp_enabled do
|
||||
_ = enqueue_discovery(device.id)
|
||||
end
|
||||
_ =
|
||||
if device.snmp_enabled do
|
||||
enqueue_discovery(device.id)
|
||||
end
|
||||
|
||||
%{
|
||||
text: base_message,
|
||||
|
|
@ -540,11 +541,9 @@ defmodule ToweropsWeb.DeviceLive.Form do
|
|||
end
|
||||
end
|
||||
|
||||
@dev_env Mix.env() == :dev
|
||||
|
||||
defp skip_non_routable_check?(assigns) do
|
||||
# Skip in dev mode or for specific users
|
||||
@dev_env ||
|
||||
Application.get_env(:towerops, :env) == :dev ||
|
||||
(assigns[:current_scope] && assigns.current_scope.user &&
|
||||
assigns.current_scope.user.email == "graham@mcintire.me")
|
||||
end
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue