dialyzer: fix all unmatched_return warnings (154 → 0)

Prefix fire-and-forget calls (PubSub.broadcast, Oban enqueue, Logger,
update_*, etc.) with `_ =` so dialyzer knows the return value is
intentionally discarded. Wrap a few if/case expressions whose
branches produce mixed types the same way.

No behavior changes — only explicit acknowledgement of discarded
returns.

Warnings: 242 → 88.
This commit is contained in:
Graham McIntire 2026-04-21 10:03:38 -05:00
parent 2d6c7d28e2
commit 91e3181bbc
62 changed files with 470 additions and 406 deletions

View file

@ -364,7 +364,7 @@ defmodule Towerops.Agents do
case ReleaseChecker.asset_for_arch(assets, arch) do
{:ok, asset} ->
update_agent(agent.id, asset.url, asset.checksum)
_ = update_agent(agent.id, asset.url, asset.checksum)
{notified + 1, skipped}
{:error, :no_matching_asset} ->
@ -470,11 +470,12 @@ defmodule Towerops.Agents do
# 5. Disconnect any active agent channel AFTER successful deletion (inside transaction)
# This ensures we only broadcast if the deletion actually succeeds
Phoenix.PubSub.broadcast(
Towerops.PubSub,
"agent:#{id}:lifecycle",
:token_disabled
)
_ =
Phoenix.PubSub.broadcast(
Towerops.PubSub,
"agent:#{id}:lifecycle",
:token_disabled
)
agent_token
end)
@ -774,7 +775,7 @@ defmodule Towerops.Agents do
{:ok, AgentAssignment.t() | nil} | {:error, Ecto.Changeset.t()}
def update_device_assignment(device_id, nil) do
# Remove assignment if setting to nil
unassign_device(device_id)
_ = unassign_device(device_id)
{:ok, nil}
end

View file

@ -85,7 +85,7 @@ defmodule Towerops.Agents.AgentCache do
@impl GenServer
def init(_opts) do
table = :ets.new(@table, [:named_table, :public, :set, read_concurrency: true])
refresh_global_default()
_ = refresh_global_default()
schedule_cleanup()
{:ok, %{table: table}}
end

View file

@ -37,8 +37,8 @@ defmodule Towerops.Alerts do
|> enrich_with_organization_id()
with {:ok, alert} <- Repo.insert(Alert.changeset(%Alert{}, attrs)) do
maybe_compute_gaiia_impact(alert)
broadcast_alert_change(alert)
_ = maybe_compute_gaiia_impact(alert)
_ = broadcast_alert_change(alert)
Subscriptions.publish_alert_event(alert, "created")
{:ok, alert}
end
@ -283,7 +283,7 @@ defmodule Towerops.Alerts do
def acknowledge_alert(alert, user_id) do
case do_acknowledge_alert(alert, user_id) do
{:ok, updated_alert} ->
AlertNotificationWorker.enqueue_acknowledge(updated_alert.id)
_ = AlertNotificationWorker.enqueue_acknowledge(updated_alert.id)
Subscriptions.publish_alert_event(updated_alert, "acknowledged")
{:ok, updated_alert}
@ -298,8 +298,8 @@ defmodule Towerops.Alerts do
def resolve_alert(alert) do
case do_resolve_alert(alert) do
{:ok, updated_alert} ->
AlertNotificationWorker.enqueue_resolve(updated_alert.id)
broadcast_alert_change(updated_alert)
_ = AlertNotificationWorker.enqueue_resolve(updated_alert.id)
_ = broadcast_alert_change(updated_alert)
Subscriptions.publish_alert_event(updated_alert, "resolved")
{:ok, updated_alert}
@ -314,7 +314,7 @@ defmodule Towerops.Alerts do
def resolve_alert_silent(alert) do
case do_resolve_alert(alert) do
{:ok, updated_alert} ->
broadcast_alert_change(updated_alert)
_ = broadcast_alert_change(updated_alert)
{:ok, updated_alert}
error ->

View file

@ -244,11 +244,12 @@ defmodule Towerops.Alerts.StormDetector do
now = Towerops.Time.now()
# Check maintenance window for the site (single check instead of N)
if Maintenance.site_in_maintenance?(site_id) do
Logger.info("Site #{site_id} outage (#{device_count} devices) suppressed — in maintenance window")
else
do_create_site_outage_alert(site_id, devices, device_names, device_count, storm_mode, now)
end
_ =
if Maintenance.site_in_maintenance?(site_id) do
Logger.info("Site #{site_id} outage (#{device_count} devices) suppressed — in maintenance window")
else
do_create_site_outage_alert(site_id, devices, device_names, device_count, storm_mode, now)
end
# Also mark each individual device as down (status update only, no individual alerts)
Enum.each(devices, fn device ->
@ -307,9 +308,10 @@ defmodule Towerops.Alerts.StormDetector do
storm_suppressed: false
}) do
{:ok, alert} ->
if !storm_mode do
AlertNotificationWorker.enqueue_trigger(alert.id)
end
_ =
if !storm_mode do
_ = AlertNotificationWorker.enqueue_trigger(alert.id)
end
_ =
Phoenix.PubSub.broadcast(
@ -386,9 +388,10 @@ defmodule Towerops.Alerts.StormDetector do
message: alert_message
}) do
{:ok, alert} ->
if !storm_mode do
AlertNotificationWorker.enqueue_trigger(alert.id)
end
_ =
if !storm_mode do
_ = AlertNotificationWorker.enqueue_trigger(alert.id)
end
_ =
Phoenix.PubSub.broadcast(

View file

@ -122,7 +122,7 @@ defmodule Towerops.ApiTokens do
{:error, :invalid_token}
else
# Update last_used_at
update_last_used(token)
_ = update_last_used(token)
# Load user if present
token = Repo.preload(token, :user)

View file

@ -147,11 +147,12 @@ defmodule Towerops.Application do
# Run post-startup cleanup tasks (production only)
# This ensures all polling jobs use the latest worker code after deployment
Task.start(fn ->
# Wait for supervisor to fully initialize
Process.sleep(2000)
JobCleanupTask.run()
end)
_ =
Task.start(fn ->
# Wait for supervisor to fully initialize
Process.sleep(2000)
JobCleanupTask.run()
end)
result
end

View file

@ -576,7 +576,7 @@ defmodule Towerops.Devices do
Logger.warning("Failed to create ping check for device #{device.id}: #{Exception.message(e)}")
end
broadcast_device_change(device.organization_id, :device_created)
_ = broadcast_device_change(device.organization_id, :device_created)
{:ok, device}
@ -699,7 +699,7 @@ defmodule Towerops.Devices do
_ = Monitoring.ensure_default_ping_check(updated_device)
end
broadcast_device_change(updated_device.organization_id, :device_updated)
_ = broadcast_device_change(updated_device.organization_id, :device_updated)
result
error ->
@ -885,21 +885,22 @@ defmodule Towerops.Devices do
# Delete the device (cascades to SNMP device, sensors, interfaces, etc.)
result = Repo.delete(device)
case result do
{:ok, _} ->
# Notify agent to stop processing jobs for this device
if agent_token_id do
Agents.broadcast_assignment_change(agent_token_id, :device_deleted)
end
_ =
case result do
{:ok, _} ->
# Notify agent to stop processing jobs for this device
if agent_token_id do
Agents.broadcast_assignment_change(agent_token_id, :device_deleted)
end
broadcast_device_change(organization_id, :device_deleted)
broadcast_device_change(organization_id, :device_deleted)
_ ->
# Notify agent even on failure (preserves original behavior)
if agent_token_id do
Agents.broadcast_assignment_change(agent_token_id, :device_deleted)
end
end
_ ->
# Notify agent even on failure (preserves original behavior)
if agent_token_id do
Agents.broadcast_assignment_change(agent_token_id, :device_deleted)
end
end
result
end
@ -932,11 +933,12 @@ defmodule Towerops.Devices do
case device |> Ecto.Changeset.change(changes) |> Repo.update() do
{:ok, updated_device} = result ->
if status_changed do
broadcast_device_change(updated_device.organization_id, :device_status_changed)
else
broadcast_device_change(updated_device.organization_id, :device_updated)
end
_ =
if status_changed do
broadcast_device_change(updated_device.organization_id, :device_status_changed)
else
broadcast_device_change(updated_device.organization_id, :device_updated)
end
result

View file

@ -124,11 +124,12 @@ defmodule Towerops.Devices.Firmware do
new_version: new_version
)
Phoenix.PubSub.broadcast(
Towerops.PubSub,
"device:#{snmp_device_id}",
{:firmware_changed, snmp_device_id, old_version, new_version}
)
_ =
Phoenix.PubSub.broadcast(
Towerops.PubSub,
"device:#{snmp_device_id}",
{:firmware_changed, snmp_device_id, old_version, new_version}
)
result

View file

@ -73,8 +73,8 @@ defmodule Towerops.Devices.MikrotikBackups.Differ do
error ->
{:error, "Failed to generate diff: #{inspect(error)}"}
after
File.rm(tmp_a)
File.rm(tmp_b)
_ = File.rm(tmp_a)
_ = File.rm(tmp_b)
end
end

View file

@ -185,10 +185,11 @@ defmodule Towerops.Monitoring do
|> Repo.insert()
end
case result do
{:ok, check} -> broadcast_check_change(check)
_ -> :ok
end
_ =
case result do
{:ok, check} -> broadcast_check_change(check)
_ -> :ok
end
result
end
@ -202,10 +203,11 @@ defmodule Towerops.Monitoring do
|> Check.changeset(attrs)
|> Repo.update()
case result do
{:ok, updated} -> broadcast_check_change(updated)
_ -> :ok
end
_ =
case result do
{:ok, updated} -> broadcast_check_change(updated)
_ -> :ok
end
result
end
@ -216,10 +218,11 @@ defmodule Towerops.Monitoring do
def delete_check(%Check{} = check) do
result = Repo.delete(check)
case result do
{:ok, deleted} -> broadcast_check_change(deleted)
_ -> :ok
end
_ =
case result do
{:ok, deleted} -> broadcast_check_change(deleted)
_ -> :ok
end
result
end
@ -429,10 +432,11 @@ defmodule Towerops.Monitoring do
|> Check.state_changeset(attrs)
|> Repo.update()
case result do
{:ok, updated} -> broadcast_check_change(updated)
_ -> :ok
end
_ =
case result do
{:ok, updated} -> broadcast_check_change(updated)
_ -> :ok
end
result
end

View file

@ -83,7 +83,7 @@ defmodule Towerops.Monitoring.Executors.PingExecutor do
end
nil ->
Task.shutdown(task, :brutal_kill)
_ = Task.shutdown(task, :brutal_kill)
{:error, "Ping command timed out"}
end
end

View file

@ -48,8 +48,8 @@ defmodule Towerops.OnCall.Escalation do
}
with {:ok, incident} <- create_incident(attrs) do
execute_current_rule(incident, policy)
schedule_escalation_check(incident, policy)
_ = execute_current_rule(incident, policy)
_ = schedule_escalation_check(incident, policy)
{:ok, incident}
end
end
@ -131,8 +131,8 @@ defmodule Towerops.OnCall.Escalation do
users = resolve_targets(rule.targets)
Enum.each(users, fn user ->
Notifier.notify(user, incident)
log_notification(incident, user)
_ = Notifier.notify(user, incident)
_ = log_notification(incident, user)
end)
end
end

View file

@ -28,7 +28,7 @@ defmodule Towerops.Preseem.Baseline do
metrics = get_metrics_in_window(ap.id, cutoff)
if length(metrics) >= 3 do
compute_and_upsert_baselines(ap.id, metrics, now)
_ = compute_and_upsert_baselines(ap.id, metrics, now)
acc + 1
else
acc

View file

@ -70,14 +70,15 @@ defmodule Towerops.Security.BruteForce do
|> IpWhitelist.changeset(attrs)
|> Repo.insert()
case result do
{:ok, _} ->
clear_whitelist_cache()
PubSub.broadcast(Towerops.PubSub, "security:whitelist", :whitelist_updated)
_ =
case result do
{:ok, _} ->
clear_whitelist_cache()
PubSub.broadcast(Towerops.PubSub, "security:whitelist", :whitelist_updated)
{:error, _} ->
:ok
end
{:error, _} ->
:ok
end
result
end
@ -93,7 +94,7 @@ defmodule Towerops.Security.BruteForce do
entry ->
Repo.delete(entry)
clear_whitelist_cache()
PubSub.broadcast(Towerops.PubSub, "security:whitelist", :whitelist_updated)
_ = PubSub.broadcast(Towerops.PubSub, "security:whitelist", :whitelist_updated)
:ok
end
end
@ -167,7 +168,7 @@ defmodule Towerops.Security.BruteForce do
# Delete the block record entirely
Repo.delete(block)
Logger.info("Manually unblocked IP: #{ip_address}")
PubSub.broadcast(Towerops.PubSub, "security:blocks", :blocks_updated)
_ = PubSub.broadcast(Towerops.PubSub, "security:blocks", :blocks_updated)
{:ok, block}
end
end
@ -232,10 +233,11 @@ defmodule Towerops.Security.BruteForce do
)
)
if count > 0 do
Logger.info("Deleted #{count} expired ban(s)")
PubSub.broadcast(Towerops.PubSub, "security:blocks", :blocks_updated)
end
_ =
if count > 0 do
Logger.info("Deleted #{count} expired ban(s)")
PubSub.broadcast(Towerops.PubSub, "security:blocks", :blocks_updated)
end
:ok
end
@ -281,7 +283,7 @@ defmodule Towerops.Security.BruteForce do
case result do
{:ok, block} ->
Logger.warning("IP banned (offense #{offense_count}): #{ip_address} until #{banned_until}")
PubSub.broadcast(Towerops.PubSub, "security:blocks", :blocks_updated)
_ = PubSub.broadcast(Towerops.PubSub, "security:blocks", :blocks_updated)
{:ok, block}
error ->
@ -305,7 +307,7 @@ defmodule Towerops.Security.BruteForce do
case result do
{:ok, updated} ->
Logger.warning("IP ban reset (offense #{offense_count}): #{block.ip_address} until #{banned_until}")
PubSub.broadcast(Towerops.PubSub, "security:blocks", :blocks_updated)
_ = PubSub.broadcast(Towerops.PubSub, "security:blocks", :blocks_updated)
{:ok, updated}
error ->
@ -342,12 +344,13 @@ defmodule Towerops.Security.BruteForce do
case result do
{:ok, updated} ->
Logger.warning("IP ban escalated to #{log_msg} (offense #{new_count}): #{block.ip_address}")
PubSub.broadcast(Towerops.PubSub, "security:blocks", :blocks_updated)
_ = PubSub.broadcast(Towerops.PubSub, "security:blocks", :blocks_updated)
# Push to Cloudflare for permanent bans
if new_count >= 3 do
CloudflareBanWorker.enqueue(block.ip_address)
end
_ =
if new_count >= 3 do
CloudflareBanWorker.enqueue(block.ip_address)
end
{:ok, updated}
@ -362,7 +365,7 @@ defmodule Towerops.Security.BruteForce do
defp get_cached_whitelist do
case :ets.whereis(@whitelist_cache_table) do
:undefined ->
create_cache_table()
_ = create_cache_table()
load_whitelist()
_ ->
@ -373,7 +376,7 @@ defmodule Towerops.Security.BruteForce do
end
rescue
ArgumentError ->
create_cache_table()
_ = create_cache_table()
load_whitelist()
end
end

View file

@ -25,9 +25,9 @@ defmodule Towerops.Security.FourOhFourTracker do
try do
# Add path to set
Redix.command(conn, ["SADD", key, path])
_ = Redix.command(conn, ["SADD", key, path])
# Set TTL if this is the first path
Redix.command(conn, ["EXPIRE", key, @window_seconds])
_ = Redix.command(conn, ["EXPIRE", key, @window_seconds])
# Get unique count
case Redix.command(conn, ["SCARD", key]) do

View file

@ -189,7 +189,7 @@ defmodule Towerops.Snmp do
case Monitoring.create_check(attrs) do
{:ok, check} ->
# Schedule first execution
Monitoring.schedule_check(check)
_ = Monitoring.schedule_check(check)
{:ok, check}
error ->
@ -219,7 +219,7 @@ defmodule Towerops.Snmp do
case Monitoring.create_check(attrs) do
{:ok, check} ->
Monitoring.schedule_check(check)
_ = Monitoring.schedule_check(check)
{:ok, check}
error ->
@ -247,7 +247,7 @@ defmodule Towerops.Snmp do
case Monitoring.create_check(attrs) do
{:ok, check} ->
Monitoring.schedule_check(check)
_ = Monitoring.schedule_check(check)
{:ok, check}
error ->
@ -277,7 +277,7 @@ defmodule Towerops.Snmp do
case Monitoring.create_check(attrs) do
{:ok, check} ->
Monitoring.schedule_check(check)
_ = Monitoring.schedule_check(check)
{:ok, check}
error ->

View file

@ -1767,18 +1767,22 @@ defmodule Towerops.Snmp.Discovery do
}
# Publish event for EventLogger to persist
Phoenix.PubSub.broadcast(
Towerops.PubSub,
"device:events",
{:device_event, event_attrs}
)
_ =
Phoenix.PubSub.broadcast(
Towerops.PubSub,
"device:events",
{:device_event, event_attrs}
)
# Also publish to org-scoped topic for targeted LiveView subscriptions
Phoenix.PubSub.broadcast(
Towerops.PubSub,
"device_events:org:#{device.organization_id}",
{:device_event, event_attrs}
)
_ =
Phoenix.PubSub.broadcast(
Towerops.PubSub,
"device_events:org:#{device.organization_id}",
{:device_event, event_attrs}
)
:ok
end
# Sanitizes data structures to ensure they are JSON-encodable

View file

@ -294,14 +294,15 @@ defmodule Towerops.Snmp.SensorChangeDetector do
_ = Phoenix.PubSub.broadcast(Towerops.PubSub, "device:#{event.device_id}", {:device_event, event})
_ = Phoenix.PubSub.broadcast(Towerops.PubSub, "device:events", {:device_event, event})
case get_org_id_from_device(event.device_id) do
nil ->
:ok
_ =
case get_org_id_from_device(event.device_id) do
nil ->
:ok
org_id ->
event_with_org = Map.put(event, :org_id, org_id)
_ = Phoenix.PubSub.broadcast(Towerops.PubSub, "device_events:org:#{org_id}", {:device_event, event_with_org})
end
org_id ->
event_with_org = Map.put(event, :org_id, org_id)
_ = Phoenix.PubSub.broadcast(Towerops.PubSub, "device_events:org:#{org_id}", {:device_event, event_with_org})
end
Logger.debug("Sensor event: #{event.message}")
end)

View file

@ -386,11 +386,12 @@ defmodule Towerops.Topology do
# maybe_update_device_role(device)
if has_changes do
Phoenix.PubSub.broadcast(
Towerops.PubSub,
"topology:#{organization_id}",
{:topology_updated, organization_id}
)
_ =
Phoenix.PubSub.broadcast(
Towerops.PubSub,
"topology:#{organization_id}",
{:topology_updated, organization_id}
)
{:ok, :changed}
else

View file

@ -203,7 +203,7 @@ defmodule Towerops.Workers.AlertNotificationWorker do
defp should_suppress_for_user?(user_id, org_id, alert_id) do
case NotificationRateLimiter.check_rate(user_id, org_id, alert_id) do
:suppress ->
AlertDigestWorker.enqueue(user_id)
_ = AlertDigestWorker.enqueue(user_id)
true
:allow ->

View file

@ -47,7 +47,7 @@ defmodule Towerops.Workers.CheckExecutorWorker do
:ok
check ->
execute_or_skip(check)
_ = execute_or_skip(check)
:ok
end
end

View file

@ -35,11 +35,12 @@ defmodule Towerops.Workers.CloudLatencyProbeWorker do
)
for poller <- cloud_pollers do
Phoenix.PubSub.broadcast(
Towerops.PubSub,
"agent:#{poller.id}:latency_probe",
{:latency_probe_jobs, devices}
)
_ =
Phoenix.PubSub.broadcast(
Towerops.PubSub,
"agent:#{poller.id}:latency_probe",
{:latency_probe_jobs, devices}
)
end
:ok

View file

@ -46,7 +46,7 @@ defmodule Towerops.Workers.DeviceMonitorWorker do
device ->
# Only reschedule if device still has monitoring enabled
if should_continue_monitoring?(device) do
maybe_perform_check(device)
_ = maybe_perform_check(device)
schedule_next_check_with_error_handling(device_id)
else
Logger.debug("Device #{device_id} monitoring disabled, not rescheduling",
@ -213,7 +213,7 @@ defmodule Towerops.Workers.DeviceMonitorWorker do
}) do
{:ok, alert} ->
# Enqueue notification job - Oban handles retries and persistence
AlertNotificationWorker.enqueue_trigger(alert.id)
_ = AlertNotificationWorker.enqueue_trigger(alert.id)
resolve_down_alert(device)

View file

@ -45,7 +45,7 @@ defmodule Towerops.Workers.DevicePollerWorker do
@impl Oban.Worker
@spec perform(Oban.Job.t()) :: :ok
def perform(%Oban.Job{args: %{"device_id" => device_id}} = job) do
Events.broadcast_job_event(job, :started)
_ = Events.broadcast_job_event(job, :started)
start_time = System.monotonic_time(:second)
result =
@ -71,7 +71,7 @@ defmodule Towerops.Workers.DevicePollerWorker do
duration = System.monotonic_time(:second) - start_time
Events.broadcast_job_event(job, :completed, %{duration: duration})
_ = Events.broadcast_job_event(job, :completed, %{duration: duration})
result
end
@ -232,7 +232,7 @@ defmodule Towerops.Workers.DevicePollerWorker do
)
nil ->
Task.shutdown(task, :brutal_kill)
_ = Task.shutdown(task, :brutal_kill)
Logger.warning("Polling task '#{name}' timed out for #{device.name}",
device_id: device.id,
@ -305,7 +305,7 @@ defmodule Towerops.Workers.DevicePollerWorker do
end
defp poll_device_interfaces(device, snmp_device, client_opts, now) do
poll_interfaces(snmp_device.interfaces, client_opts, now, snmp_device)
_ = poll_interfaces(snmp_device.interfaces, client_opts, now, snmp_device)
Logger.debug("Polled #{length(snmp_device.interfaces)} interfaces for #{device.name}")
_ =
@ -600,7 +600,7 @@ defmodule Towerops.Workers.DevicePollerWorker do
[]
end)
Snmp.create_storage_readings_batch(reading_entries)
_ = Snmp.create_storage_readings_batch(reading_entries)
# Process metadata updates individually
Enum.each(poll_results, fn
@ -660,7 +660,7 @@ defmodule Towerops.Workers.DevicePollerWorker do
build_processor_reading_entry(processor, result, timestamp)
end)
Snmp.create_processor_readings_batch(reading_entries)
_ = Snmp.create_processor_readings_batch(reading_entries)
# Process metadata updates individually
Enum.each(poll_results, fn {processor, result} ->
@ -785,7 +785,7 @@ defmodule Towerops.Workers.DevicePollerWorker do
[]
end)
Snmp.create_mempool_readings_batch(reading_entries)
_ = Snmp.create_mempool_readings_batch(reading_entries)
# Process metadata updates individually
Enum.each(poll_results, fn
@ -991,9 +991,10 @@ defmodule Towerops.Workers.DevicePollerWorker do
_ = Phoenix.PubSub.broadcast(Towerops.PubSub, "device:#{device_id}", {:device_event, event})
_ = Phoenix.PubSub.broadcast(Towerops.PubSub, "device:events", {:device_event, event})
if org_id do
_ = Phoenix.PubSub.broadcast(Towerops.PubSub, "device_events:org:#{org_id}", {:device_event, event})
end
_ =
if org_id do
_ = Phoenix.PubSub.broadcast(Towerops.PubSub, "device_events:org:#{org_id}", {:device_event, event})
end
Logger.info("State sensor change: #{event.message}")
end
@ -1489,14 +1490,15 @@ defmodule Towerops.Workers.DevicePollerWorker do
{:device_event, event_with_org}
)
if org_id do
_ =
Phoenix.PubSub.broadcast(
Towerops.PubSub,
"device_events:org:#{org_id}",
{:device_event, event_with_org}
)
end
_ =
if org_id do
_ =
Phoenix.PubSub.broadcast(
Towerops.PubSub,
"device_events:org:#{org_id}",
{:device_event, event_with_org}
)
end
Logger.debug("Broadcast event: #{event_attrs.message}")
end)
@ -1727,13 +1729,14 @@ defmodule Towerops.Workers.DevicePollerWorker do
end)
# Insert readings (even if some metrics are nil)
case reading_entries do
[] ->
:ok
_ =
case reading_entries do
[] ->
:ok
entries ->
Snmp.create_transceiver_readings_batch(entries)
end
entries ->
Snmp.create_transceiver_readings_batch(entries)
end
:ok
end
@ -1826,13 +1829,14 @@ defmodule Towerops.Workers.DevicePollerWorker do
end)
# Insert readings (even if some statuses are nil)
case reading_entries do
[] ->
:ok
_ =
case reading_entries do
[] ->
:ok
entries ->
Snmp.create_entity_physical_readings_batch(entries)
end
entries ->
Snmp.create_entity_physical_readings_batch(entries)
end
:ok
end

View file

@ -41,7 +41,7 @@ defmodule Towerops.Workers.DiscoveryWorker do
@impl Oban.Worker
@spec perform(Oban.Job.t()) :: :ok | :discard | {:error, term()}
def perform(%Oban.Job{args: %{"device_id" => device_id}} = job) do
Events.broadcast_job_event(job, :started)
_ = Events.broadcast_job_event(job, :started)
start_time = System.monotonic_time(:second)
try do
@ -57,19 +57,20 @@ defmodule Towerops.Workers.DiscoveryWorker do
duration = System.monotonic_time(:second) - start_time
case result do
:ok ->
Events.broadcast_job_event(job, :completed, %{duration: duration})
_ =
case result do
:ok ->
Events.broadcast_job_event(job, :completed, %{duration: duration})
:discard ->
Events.broadcast_job_event(job, :completed, %{duration: duration})
:discard ->
Events.broadcast_job_event(job, :completed, %{duration: duration})
{:error, reason} ->
Events.broadcast_job_event(job, :failed, %{
error: inspect(reason),
duration: duration
})
end
{:error, reason} ->
Events.broadcast_job_event(job, :failed, %{
error: inspect(reason),
duration: duration
})
end
result
rescue
@ -83,10 +84,11 @@ defmodule Towerops.Workers.DiscoveryWorker do
error: error_string
)
Events.broadcast_job_event(job, :failed, %{
error: error_string,
duration: duration
})
_ =
Events.broadcast_job_event(job, :failed, %{
error: error_string,
duration: duration
})
# Crashes are not retryable - they indicate a code bug, not a transient issue
:discard

View file

@ -12,7 +12,7 @@ defmodule Towerops.Workers.EscalationCheckWorker do
@impl Oban.Worker
def perform(%Oban.Job{args: %{"incident_id" => incident_id}}) do
Escalation.check_and_escalate(incident_id)
_ = Escalation.check_and_escalate(incident_id)
:ok
end
end

View file

@ -31,8 +31,8 @@ defmodule Towerops.Workers.GaiiaInsightWorker do
maybe_dismiss_resolved_insights(organization_id, "ghost", result.ghost_devices)
maybe_dismiss_resolved_insights(organization_id, "mismatch", result.data_mismatches)
generate_untracked_insights(organization_id, result.untracked_devices)
generate_ghost_insights(organization_id, result.ghost_devices)
_ = generate_untracked_insights(organization_id, result.untracked_devices)
_ = generate_ghost_insights(organization_id, result.ghost_devices)
generate_mismatch_insights(organization_id, result.data_mismatches)
end

View file

@ -122,11 +122,12 @@ defmodule Towerops.Workers.MikrotikBackupWorker do
case BackupRequests.create_request(device.id, job_id) do
{:ok, _request} ->
# Broadcast to agent via PubSub
Phoenix.PubSub.broadcast(
Towerops.PubSub,
"agent:#{agent_token_id}:backup",
{:backup_requested, job}
)
_ =
Phoenix.PubSub.broadcast(
Towerops.PubSub,
"agent:#{agent_token_id}:backup",
{:backup_requested, job}
)
Logger.info("Backup job sent to agent",
device_id: device.id,

View file

@ -25,8 +25,8 @@ defmodule Towerops.Workers.WeatherSyncWorker do
:ok
else
sync_all_sites()
Weather.cleanup_old_observations(30)
schedule_next()
_ = Weather.cleanup_old_observations(30)
_ = schedule_next()
:ok
end
end

View file

@ -21,7 +21,7 @@ defmodule Towerops.Workers.WelcomeEmailWorker do
:ok
user ->
UserNotifier.deliver_welcome_email(user)
_ = UserNotifier.deliver_welcome_email(user)
:ok
end
end

View file

@ -117,9 +117,10 @@ defmodule ToweropsWeb.AgentChannel do
_ = Phoenix.PubSub.subscribe(Towerops.PubSub, "agent:#{agent_token.id}:lifecycle")
# Subscribe to latency probe requests (cloud pollers only)
if agent_token.is_cloud_poller do
_ = Phoenix.PubSub.subscribe(Towerops.PubSub, "agent:#{agent_token.id}:latency_probe")
end
_ =
if agent_token.is_cloud_poller do
_ = Phoenix.PubSub.subscribe(Towerops.PubSub, "agent:#{agent_token.id}:latency_probe")
end
# Update last_seen_at and IP on join
now = DateTime.utc_now()
@ -160,14 +161,15 @@ defmodule ToweropsWeb.AgentChannel do
@impl true
def terminate(_reason, socket) do
# Broadcast agent disconnection for real-time UI updates
if Map.has_key?(socket.assigns, :agent_token_id) do
_ =
Phoenix.PubSub.broadcast(
Towerops.PubSub,
"agents:health",
{:agent_disconnected, socket.assigns.agent_token_id, socket.assigns.organization_id}
)
end
_ =
if Map.has_key?(socket.assigns, :agent_token_id) do
_ =
Phoenix.PubSub.broadcast(
Towerops.PubSub,
"agents:health",
{:agent_disconnected, socket.assigns.agent_token_id, socket.assigns.organization_id}
)
end
:ok
end
@ -175,7 +177,7 @@ defmodule ToweropsWeb.AgentChannel do
@impl true
@spec handle_info(:send_jobs, Phoenix.Socket.t()) :: {:noreply, Phoenix.Socket.t()}
def handle_info(:send_jobs, socket) do
cancel_poll_timer(socket)
_ = cancel_poll_timer(socket)
updated_socket = build_and_push_jobs(socket)
build_and_push_check_jobs(updated_socket)
@ -281,7 +283,7 @@ defmodule ToweropsWeb.AgentChannel do
)
# Cancel any existing poll timer (regular cycle or pending debounce)
cancel_poll_timer(socket)
_ = cancel_poll_timer(socket)
# 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)
@ -403,11 +405,12 @@ defmodule ToweropsWeb.AgentChannel do
def handle_info({:live_poll_timeout, reply_topic}, socket) do
Logger.warning("Live poll timed out", reply_topic: reply_topic)
Phoenix.PubSub.broadcast(
Towerops.PubSub,
reply_topic,
{:live_poll_error, :timeout}
)
_ =
Phoenix.PubSub.broadcast(
Towerops.PubSub,
reply_topic,
{:live_poll_error, :timeout}
)
{:noreply, socket}
end
@ -550,11 +553,12 @@ defmodule ToweropsWeb.AgentChannel do
# Broadcast result to the requesting LiveView via PubSub
# The test_id contains the device_id, so we can broadcast to that topic
Phoenix.PubSub.broadcast(
Towerops.PubSub,
"credential_test:#{result.test_id}",
{:credential_test_result, result}
)
_ =
Phoenix.PubSub.broadcast(
Towerops.PubSub,
"credential_test:#{result.test_id}",
{:credential_test_result, result}
)
{:noreply, socket}
else
@ -746,11 +750,12 @@ defmodule ToweropsWeb.AgentChannel do
)
# Check if this is a live poll result
if String.starts_with?(result.job_id, "live_poll:") do
handle_live_poll_result(result, socket)
else
process_and_log_snmp_result(socket, result)
end
_ =
if String.starts_with?(result.job_id, "live_poll:") do
handle_live_poll_result(result, socket)
else
process_and_log_snmp_result(socket, result)
end
{:noreply, socket}
else
@ -1477,7 +1482,7 @@ defmodule ToweropsWeb.AgentChannel do
with {:ok, device} <- fetch_device(result.device_id),
:ok <- verify_device_organization(device, organization_id),
:ok <- verify_device_assignment(device, socket.assigns.agent_token_id) do
process_job_result(device, result, socket)
_ = process_job_result(device, result, socket)
:ok
else
{:error, :device_not_found} = error ->
@ -1598,7 +1603,7 @@ defmodule ToweropsWeb.AgentChannel do
old_state = check.current_state
{:ok, updated_check} = Monitoring.update_check_state(check, result.status, result.output)
handle_check_state_change(old_state, updated_check, result.output)
broadcast_check_update(check.device_id)
_ = broadcast_check_update(check.device_id)
:ok
{:error, changeset} ->
@ -1623,9 +1628,10 @@ defmodule ToweropsWeb.AgentChannel do
defp handle_check_state_change(old_state, check, output) do
# State changed from OK to problem and is now hard state
if old_state == 0 and check.current_state in [1, 2] and check.current_state_type == "hard" do
maybe_create_check_alert(check, output)
end
_ =
if old_state == 0 and check.current_state in [1, 2] and check.current_state_type == "hard" do
maybe_create_check_alert(check, output)
end
# State changed from problem to OK
if old_state in [1, 2] and check.current_state == 0 do
@ -1680,15 +1686,17 @@ defmodule ToweropsWeb.AgentChannel do
Devices.update_device_status(device, new_status)
if old_status != new_status do
handle_agent_status_change(device, old_status, new_status)
end
_ =
if old_status != new_status do
handle_agent_status_change(device, old_status, new_status)
end
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}
)
Subscriptions.publish_device_status(
device.id,
@ -1706,12 +1714,13 @@ defmodule ToweropsWeb.AgentChannel do
do: "Device is not responding to SNMP",
else: "Device is not responding to ping"
Alerts.create_alert(%{
device_id: device.id,
alert_type: :device_down,
triggered_at: now,
message: message
})
_ =
Alerts.create_alert(%{
device_id: device.id,
alert_type: :device_down,
triggered_at: now,
message: message
})
Phoenix.PubSub.broadcast(
Towerops.PubSub,
@ -1729,13 +1738,14 @@ defmodule ToweropsWeb.AgentChannel do
do: "Device is now responding to SNMP",
else: "Device is now responding to ping"
Alerts.create_alert(%{
device_id: device.id,
alert_type: :device_up,
triggered_at: now,
resolved_at: now,
message: message
})
_ =
Alerts.create_alert(%{
device_id: device.id,
alert_type: :device_up,
triggered_at: now,
resolved_at: now,
message: message
})
case Alerts.get_active_alert(device.id, :device_down) do
nil -> :ok
@ -1755,40 +1765,42 @@ defmodule ToweropsWeb.AgentChannel do
now = Towerops.Time.now()
# Resolve stuck device_down alerts
case Alerts.get_active_alert(device.id, :device_down) do
nil ->
:ok
_ =
case Alerts.get_active_alert(device.id, :device_down) do
nil ->
:ok
alert ->
Logger.info(
"Resolving stuck device_down alert for #{device.name} - device is UP but alert was not resolved",
device_id: device.id,
alert_id: alert.id
)
alert ->
Logger.info(
"Resolving stuck device_down alert for #{device.name} - device is UP but alert was not resolved",
device_id: device.id,
alert_id: alert.id
)
# Create device_up alert (informational)
message =
if device.snmp_enabled,
do: "Device is now responding to SNMP",
else: "Device is now responding to ping"
# Create device_up alert (informational)
message =
if device.snmp_enabled,
do: "Device is now responding to SNMP",
else: "Device is now responding to ping"
Alerts.create_alert(%{
device_id: device.id,
alert_type: :device_up,
triggered_at: now,
resolved_at: now,
message: message
})
_ =
Alerts.create_alert(%{
device_id: device.id,
alert_type: :device_up,
triggered_at: now,
resolved_at: now,
message: message
})
# Resolve the stuck alert
Alerts.resolve_alert(alert)
# Resolve the stuck alert
Alerts.resolve_alert(alert)
Phoenix.PubSub.broadcast(
Towerops.PubSub,
"alerts:org:#{device.organization_id}:resolved",
{:alert_resolved, device.id, :device_down}
)
end
Phoenix.PubSub.broadcast(
Towerops.PubSub,
"alerts:org:#{device.organization_id}:resolved",
{:alert_resolved, device.id, :device_down}
)
end
# Also resolve any stuck device_up alerts (should have been created with resolved_at)
case Alerts.get_active_alert(device.id, :device_up) do
@ -1937,11 +1949,12 @@ defmodule ToweropsWeb.AgentChannel do
if old_status != new_status do
Devices.update_device_status(device, new_status)
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}
)
Subscriptions.publish_device_status(
device.id,
@ -1970,13 +1983,14 @@ defmodule ToweropsWeb.AgentChannel do
publish_sensor_readings_to_graphql(device, snmp_device.sensors, oid_values, timestamp)
# Batch insert interface stats
process_interface_stats_batch(snmp_device.interfaces, oid_values, timestamp)
_ = process_interface_stats_batch(snmp_device.interfaces, oid_values, timestamp)
# Process complex SNMP data (neighbors, ARP, MAC, IP addresses, processors, storage)
# using Replay adapter to reuse existing parsing logic
if map_size(oid_values) > length(snmp_device.sensors) + length(snmp_device.interfaces) * 6 do
process_additional_polling_data(device, oid_values)
end
_ =
if map_size(oid_values) > length(snmp_device.sensors) + length(snmp_device.interfaces) * 6 do
process_additional_polling_data(device, oid_values)
end
# Notify LiveViews that new sensor/interface data is available for graphing
Phoenix.PubSub.broadcast(
@ -2021,7 +2035,7 @@ defmodule ToweropsWeb.AgentChannel do
process_arp_entries(client_opts, device_id, interfaces)
# Process MAC addresses
process_mac_addresses(client_opts, device_id, interfaces)
_ = process_mac_addresses(client_opts, device_id, interfaces)
# Process IP addresses
process_ip_addresses(client_opts, device_id, interfaces)
@ -2142,7 +2156,7 @@ defmodule ToweropsWeb.AgentChannel do
end)
# Batch insert all sensor readings in one SQL statement
Snmp.create_sensor_readings_batch(reading_entries)
_ = Snmp.create_sensor_readings_batch(reading_entries)
# Process change detection and metadata updates individually
Enum.each(sensor_updates, fn {sensor, final_value} ->
@ -2279,7 +2293,7 @@ defmodule ToweropsWeb.AgentChannel do
{:error, :backup_request_not_found}
request ->
handle_backup_request(request, result)
_ = handle_backup_request(request, result)
:ok
end
end

View file

@ -17,8 +17,8 @@ defmodule ToweropsWeb.MobileChannel do
user_id = socket.assigns.user_id
if Organizations.user_has_access?(user_id, org_id) do
Phoenix.PubSub.subscribe(Towerops.PubSub, "organization:#{org_id}:alerts")
Phoenix.PubSub.subscribe(Towerops.PubSub, "devices:org:#{org_id}")
_ = Phoenix.PubSub.subscribe(Towerops.PubSub, "organization:#{org_id}:alerts")
_ = Phoenix.PubSub.subscribe(Towerops.PubSub, "devices:org:#{org_id}")
{:ok, socket}
else
@ -35,7 +35,7 @@ defmodule ToweropsWeb.MobileChannel do
device ->
if Organizations.user_has_access?(user_id, device.organization_id) do
Phoenix.PubSub.subscribe(Towerops.PubSub, "device:#{device_id}")
_ = Phoenix.PubSub.subscribe(Towerops.PubSub, "device:#{device_id}")
{:ok, socket}
else
{:error, %{reason: "unauthorized"}}

View file

@ -27,7 +27,7 @@ defmodule ToweropsWeb.MobileSocket do
session ->
session = Towerops.Repo.preload(session, :user)
Task.start(fn -> MobileSessions.touch_session(session) end)
_ = Task.start(fn -> MobileSessions.touch_session(session) end)
socket =
socket

View file

@ -17,12 +17,13 @@ defmodule ToweropsWeb.Api.AccountDataController do
user = conn.assigns.current_scope.user
# Verify user account is confirmed before allowing data export
if !user.confirmed_at do
conn
|> put_status(:forbidden)
|> json(%{error: "Email address must be confirmed before exporting account data"})
|> halt()
end
_ =
if !user.confirmed_at do
conn
|> put_status(:forbidden)
|> json(%{error: "Email address must be confirmed before exporting account data"})
|> halt()
end
# Log the data export for audit trail
AuditLogger.log_user_data_exported(conn, user.id)

View file

@ -68,7 +68,7 @@ defmodule ToweropsWeb.Api.V1.ChecksController do
defp create_and_respond(conn, attrs) do
case Monitoring.create_check(attrs) do
{:ok, check} ->
if check.enabled, do: Monitoring.schedule_check(check)
_ = if check.enabled, do: Monitoring.schedule_check(check)
conn
|> put_status(:created)

View file

@ -252,7 +252,7 @@ defmodule ToweropsWeb.Api.V1.DevicesController do
case Devices.create_device(device_params, opts) do
{:ok, device} ->
maybe_enqueue_discovery(device)
_ = maybe_enqueue_discovery(device)
conn
|> put_status(:created)

View file

@ -208,7 +208,7 @@ defmodule ToweropsWeb.Api.V1.MibController do
:ok ->
# Safe to copy to vendor directory - vendor_dir constructed from validated vendor name
# and all paths in temp_dir have been validated by validate_extracted_paths/1
File.cp_r!(temp_dir, vendor_dir)
_ = File.cp_r!(temp_dir, vendor_dir)
files_count = count_files(vendor_dir)
Logger.info("Extracted #{files_count} MIB files for vendor: #{vendor}")
@ -255,7 +255,7 @@ defmodule ToweropsWeb.Api.V1.MibController do
:ok ->
# Safe to copy to vendor directory - vendor_dir constructed from validated vendor name
# and all paths in temp_dir have been validated by validate_extracted_paths/1
File.cp_r!(temp_dir, vendor_dir)
_ = File.cp_r!(temp_dir, vendor_dir)
files_count = count_files(vendor_dir)
Logger.info("Extracted #{files_count} MIB files for vendor: #{vendor}")

View file

@ -8,14 +8,15 @@ defmodule ToweropsWeb.UserConfirmationController do
end
def create(conn, %{"user" => %{"email" => email}}) do
if user = Accounts.get_user_by_email(email) do
if is_nil(user.confirmed_at) do
Accounts.deliver_user_confirmation_instructions(
user,
&url(~p"/users/confirm/#{&1}")
)
_ =
if user = Accounts.get_user_by_email(email) do
if is_nil(user.confirmed_at) do
Accounts.deliver_user_confirmation_instructions(
user,
&url(~p"/users/confirm/#{&1}")
)
end
end
end
# Always show success to prevent email enumeration
conn

View file

@ -38,7 +38,7 @@ defmodule ToweropsWeb.UserRegistrationController do
defp create_with_organization(conn, user_params) do
case Accounts.register_user_with_organization(user_params) do
{:ok, user} ->
WelcomeEmailWorker.enqueue(user.id)
_ = WelcomeEmailWorker.enqueue(user.id)
conn
|> put_flash(:info, t("Account created successfully."))
@ -57,7 +57,7 @@ defmodule ToweropsWeb.UserRegistrationController do
with {:ok, invitation} <- get_valid_invitation(invitation_token),
{:ok, user} <- Accounts.register_user(user_params),
{:ok, _membership} <- Organizations.accept_invitation(invitation, user.id) do
WelcomeEmailWorker.enqueue(user.id)
_ = WelcomeEmailWorker.enqueue(user.id)
conn
|> put_flash(:info, t("Account created successfully. Welcome to %{org}!", org: invitation.organization.name))

View file

@ -74,7 +74,7 @@ defmodule ToweropsWeb.GraphQL.Resolvers.Check do
defp create_and_schedule_check(attrs) do
case Monitoring.create_check(attrs) do
{:ok, check} ->
if check.enabled, do: Monitoring.schedule_check(check)
_ = if check.enabled, do: Monitoring.schedule_check(check)
{:ok, check}
{:error, changeset} ->

View file

@ -18,12 +18,12 @@ defmodule ToweropsWeb.ActivityFeedLive do
timer_ref =
if connected?(socket) do
# Subscribe to all relevant PubSub topics for real-time updates
Phoenix.PubSub.subscribe(Towerops.PubSub, "alerts:org:#{organization.id}:new")
Phoenix.PubSub.subscribe(Towerops.PubSub, "alerts:org:#{organization.id}:resolved")
Phoenix.PubSub.subscribe(Towerops.PubSub, "devices:org:#{organization.id}")
Phoenix.PubSub.subscribe(Towerops.PubSub, "config:org:#{organization.id}")
Phoenix.PubSub.subscribe(Towerops.PubSub, "sync:org:#{organization.id}")
Phoenix.PubSub.subscribe(Towerops.PubSub, "device_events:org:#{organization.id}")
_ = Phoenix.PubSub.subscribe(Towerops.PubSub, "alerts:org:#{organization.id}:new")
_ = Phoenix.PubSub.subscribe(Towerops.PubSub, "alerts:org:#{organization.id}:resolved")
_ = Phoenix.PubSub.subscribe(Towerops.PubSub, "devices:org:#{organization.id}")
_ = Phoenix.PubSub.subscribe(Towerops.PubSub, "config:org:#{organization.id}")
_ = Phoenix.PubSub.subscribe(Towerops.PubSub, "sync:org:#{organization.id}")
_ = Phoenix.PubSub.subscribe(Towerops.PubSub, "device_events:org:#{organization.id}")
# Timer for relative timestamp refresh
{:ok, ref} = :timer.send_interval(@tick_interval_ms, self(), :tick)
@ -143,9 +143,10 @@ defmodule ToweropsWeb.ActivityFeedLive do
@impl true
def terminate(_reason, socket) do
if timer_ref = socket.assigns[:timer_ref] do
:timer.cancel(timer_ref)
end
_ =
if timer_ref = socket.assigns[:timer_ref] do
:timer.cancel(timer_ref)
end
:ok
end

View file

@ -10,8 +10,8 @@ defmodule ToweropsWeb.Admin.AgentLive.Index do
def mount(_params, _session, socket) do
timer_ref =
if connected?(socket) do
Phoenix.PubSub.subscribe(Towerops.PubSub, "agents:health")
Phoenix.PubSub.subscribe(Towerops.PubSub, "admin:agents")
_ = Phoenix.PubSub.subscribe(Towerops.PubSub, "agents:health")
_ = Phoenix.PubSub.subscribe(Towerops.PubSub, "admin:agents")
{:ok, ref} = :timer.send_interval(1000, :tick)
ref
end
@ -110,9 +110,10 @@ defmodule ToweropsWeb.Admin.AgentLive.Index do
@impl true
def terminate(_reason, socket) do
if timer_ref = socket.assigns[:timer_ref] do
:timer.cancel(timer_ref)
end
_ =
if timer_ref = socket.assigns[:timer_ref] do
:timer.cancel(timer_ref)
end
:ok
end

View file

@ -18,9 +18,10 @@ defmodule ToweropsWeb.Admin.MonitoringLive do
@impl Phoenix.LiveView
def mount(_params, _session, socket) do
if connected?(socket) do
Phoenix.PubSub.subscribe(Towerops.PubSub, @topic)
end
_ =
if connected?(socket) do
_ = Phoenix.PubSub.subscribe(Towerops.PubSub, @topic)
end
socket =
socket

View file

@ -12,10 +12,11 @@ defmodule ToweropsWeb.Admin.SecurityLive.Index do
@impl true
def mount(_params, _session, socket) do
if connected?(socket) do
Phoenix.PubSub.subscribe(Towerops.PubSub, "security:whitelist")
Phoenix.PubSub.subscribe(Towerops.PubSub, "security:blocks")
end
_ =
if connected?(socket) do
_ = Phoenix.PubSub.subscribe(Towerops.PubSub, "security:whitelist")
_ = Phoenix.PubSub.subscribe(Towerops.PubSub, "security:blocks")
end
{:ok,
socket

View file

@ -491,9 +491,10 @@ defmodule ToweropsWeb.AgentLive.Index do
@impl true
def terminate(_reason, socket) do
if timer_ref = socket.assigns[:timer_ref] do
:timer.cancel(timer_ref)
end
_ =
if timer_ref = socket.assigns[:timer_ref] do
_ = :timer.cancel(timer_ref)
end
:ok
end

View file

@ -50,7 +50,7 @@ defmodule ToweropsWeb.AgentLive.Show do
def handle_event("restart_agent", _params, socket) do
if socket.assigns.current_scope.user.is_superuser do
Agents.restart_agent(socket.assigns.agent_token.id)
_ = Agents.restart_agent(socket.assigns.agent_token.id)
{:noreply, put_flash(socket, :info, t("Restart command sent to agent"))}
else
@ -72,7 +72,7 @@ defmodule ToweropsWeb.AgentLive.Show do
defp send_update_command(socket, agent_token, arch) do
with {:ok, release} <- ReleaseChecker.get_latest_release(),
{:ok, asset} <- ReleaseChecker.asset_for_arch(release.assets, arch) do
Agents.update_agent(agent_token.id, asset.url, asset.checksum)
_ = Agents.update_agent(agent_token.id, asset.url, asset.checksum)
put_flash(socket, :info, t("Update command sent to agent (v%{version})", version: release.version))
else
{:error, :no_matching_asset} ->

View file

@ -389,7 +389,7 @@ defmodule ToweropsWeb.CheckLive.FormComponent do
case Monitoring.create_check(check_params) do
{:ok, check} ->
Monitoring.schedule_check(check)
_ = Monitoring.schedule_check(check)
notify_parent({:check_created, check})
{:noreply, socket}

View file

@ -15,10 +15,11 @@ defmodule ToweropsWeb.DashboardLive do
def mount(_params, _session, socket) do
organization = socket.assigns.current_scope.organization
if connected?(socket) do
Phoenix.PubSub.subscribe(Towerops.PubSub, "alerts:org:#{organization.id}:new")
Phoenix.PubSub.subscribe(Towerops.PubSub, "alerts:org:#{organization.id}:resolved")
end
_ =
if connected?(socket) do
_ = Phoenix.PubSub.subscribe(Towerops.PubSub, "alerts:org:#{organization.id}:new")
Phoenix.PubSub.subscribe(Towerops.PubSub, "alerts:org:#{organization.id}:resolved")
end
status_counts = Devices.get_device_status_counts(organization.id)
device_count = status_counts |> Map.values() |> Enum.sum()
@ -99,9 +100,10 @@ defmodule ToweropsWeb.DashboardLive do
@dashboard_debounce_ms 1_500
defp schedule_debounced_dashboard_reload(socket) do
if ref = socket.assigns.pending_dashboard_reload_ref do
Process.cancel_timer(ref)
end
_ =
if ref = socket.assigns.pending_dashboard_reload_ref do
_ = Process.cancel_timer(ref)
end
ref = Process.send_after(self(), :debounced_dashboard_reload, @dashboard_debounce_ms)
assign(socket, :pending_dashboard_reload_ref, ref)

View file

@ -436,7 +436,7 @@ defmodule ToweropsWeb.DeviceLive.Form do
case send_credential_test_to_agent(effective_agent_id, device_map, test_id) do
:ok ->
Phoenix.PubSub.subscribe(Towerops.PubSub, "credential_test:#{test_id}")
_ = Phoenix.PubSub.subscribe(Towerops.PubSub, "credential_test:#{test_id}")
{:noreply,
socket
@ -472,7 +472,7 @@ defmodule ToweropsWeb.DeviceLive.Form do
AuditLogger.log_device_created(nil, user.id, device.id, device.name)
# Handle agent assignment after device creation
handle_agent_assignment(device.id, agent_token_id)
_ = handle_agent_assignment(device.id, agent_token_id)
flash_message = handle_device_creation(device)
@ -531,7 +531,7 @@ defmodule ToweropsWeb.DeviceLive.Form do
AuditLogger.log_device_updated(nil, user.id, device.id, fields_changed)
# device update
handle_agent_assignment(device.id, agent_token_id)
_ = handle_agent_assignment(device.id, agent_token_id)
flash_message = handle_device_update(old_device, device)

View file

@ -17,10 +17,11 @@ defmodule ToweropsWeb.DeviceLive.Index do
devices = Devices.list_organization_devices(organization.id)
sites = Sites.list_organization_sites(organization.id)
if connected?(socket) do
Phoenix.PubSub.subscribe(Towerops.PubSub, "devices:org:#{organization.id}")
schedule_tick()
end
_ =
if connected?(socket) do
_ = Phoenix.PubSub.subscribe(Towerops.PubSub, "devices:org:#{organization.id}")
_ = schedule_tick()
end
# Load device quota
{current, limit} = SubscriptionLimits.device_quota(organization)
@ -256,7 +257,7 @@ defmodule ToweropsWeb.DeviceLive.Index do
# Periodic tick to refresh "time ago" timestamps between poll events
@impl true
def handle_info(:tick, socket) do
schedule_tick()
_ = schedule_tick()
if socket.assigns.active_tab == "existing" do
{:noreply, schedule_debounced_reload(socket, :tick)}
@ -310,9 +311,10 @@ defmodule ToweropsWeb.DeviceLive.Index do
defp schedule_debounced_reload(socket, event) do
# Cancel any pending debounced reload
if ref = socket.assigns.pending_reload_ref do
Process.cancel_timer(ref)
end
_ =
if ref = socket.assigns.pending_reload_ref do
_ = Process.cancel_timer(ref)
end
# For status changes, skip reload entirely if viewing the discovered tab
if event == :device_status_changed && socket.assigns.active_tab == "discovered" do

View file

@ -988,11 +988,12 @@ defmodule ToweropsWeb.DeviceLive.Show do
case BackupRequests.create_request(device.id, job_id, "manual") do
{:ok, _request} ->
Phoenix.PubSub.broadcast(
Towerops.PubSub,
"agent:#{agent_token_id}:backup",
{:backup_requested, job}
)
_ =
Phoenix.PubSub.broadcast(
Towerops.PubSub,
"agent:#{agent_token_id}:backup",
{:backup_requested, job}
)
{:noreply,
socket

View file

@ -995,7 +995,7 @@ defmodule ToweropsWeb.GraphLive.Show do
socket
timer_ref ->
Process.cancel_timer(timer_ref)
_ = Process.cancel_timer(timer_ref)
assign(socket, :live_poll_timer, nil)
end
end
@ -1122,11 +1122,12 @@ defmodule ToweropsWeb.GraphLive.Show do
sensor_oids = Enum.map(sensors, & &1.sensor_oid)
# Broadcast live poll request with reply topic and sensor OIDs
Phoenix.PubSub.broadcast(
Towerops.PubSub,
"agent:#{agent_token_id}:live_poll",
{:live_poll_requested, device_id, sensor_oids, reply_topic}
)
_ =
Phoenix.PubSub.broadcast(
Towerops.PubSub,
"agent:#{agent_token_id}:live_poll",
{:live_poll_requested, device_id, sensor_oids, reply_topic}
)
# Wait for response with timeout
receive do

View file

@ -92,7 +92,7 @@ defmodule ToweropsWeb.MobileQRLive do
defp cancel_timer(nil), do: :ok
defp cancel_timer(timer_ref) when is_reference(timer_ref) do
Process.cancel_timer(timer_ref)
_ = Process.cancel_timer(timer_ref)
:ok
end

View file

@ -157,7 +157,7 @@ defmodule ToweropsWeb.Org.SettingsLive do
{:ok, invitation} ->
invitation = Map.put(invitation, :organization, organization)
accept_url = url(~p"/invitations/#{invitation.token}")
UserNotifier.deliver_invitation_email(invitation, accept_url)
_ = UserNotifier.deliver_invitation_email(invitation, accept_url)
{:noreply,
socket

View file

@ -16,9 +16,10 @@ defmodule ToweropsWeb.RfLinkHealthLive do
def mount(_params, _session, socket) do
organization = socket.assigns.current_scope.organization
if connected?(socket) do
Phoenix.PubSub.subscribe(Towerops.PubSub, "wireless_clients:org:#{organization.id}")
end
_ =
if connected?(socket) do
_ = Phoenix.PubSub.subscribe(Towerops.PubSub, "wireless_clients:org:#{organization.id}")
end
summary = RfLinks.get_summary(organization.id)
links = RfLinks.list_rf_links(organization.id)

View file

@ -20,9 +20,10 @@ defmodule ToweropsWeb.StatusPageLive do
|> assign(:page_title, "Not Found")}
config ->
if connected?(socket) do
Phoenix.PubSub.subscribe(Towerops.PubSub, "status_page:#{config.id}")
end
_ =
if connected?(socket) do
_ = Phoenix.PubSub.subscribe(Towerops.PubSub, "status_page:#{config.id}")
end
components = StatusPages.list_components(config.id)
active_incidents = StatusPages.list_active_incidents(config.id)

View file

@ -94,12 +94,13 @@ defmodule ToweropsWeb.UserRegistrationLive do
case Accounts.register_user_with_organization(user_params_with_timezone) do
{:ok, user} ->
Accounts.deliver_user_confirmation_instructions(
user,
&url(~p"/users/confirm/#{&1}")
)
_ =
Accounts.deliver_user_confirmation_instructions(
user,
&url(~p"/users/confirm/#{&1}")
)
WelcomeEmailWorker.enqueue(user.id)
_ = WelcomeEmailWorker.enqueue(user.id)
{:noreply,
socket
@ -119,12 +120,13 @@ defmodule ToweropsWeb.UserRegistrationLive do
with {:ok, invitation} <- get_valid_invitation(invitation_token),
{:ok, user} <- Accounts.register_user(user_params_with_timezone),
{:ok, _membership} <- Organizations.accept_invitation(invitation, user.id) do
Accounts.deliver_user_confirmation_instructions(
user,
&url(~p"/users/confirm/#{&1}")
)
_ =
Accounts.deliver_user_confirmation_instructions(
user,
&url(~p"/users/confirm/#{&1}")
)
WelcomeEmailWorker.enqueue(user.id)
_ = WelcomeEmailWorker.enqueue(user.id)
{:noreply,
socket

View file

@ -302,7 +302,7 @@ defmodule ToweropsWeb.UserSettingsLive do
case Accounts.delete_account(user, password) do
{:ok, _} ->
# Send farewell email after deletion
UserNotifier.deliver_account_deleted_notification(user.email, user.first_name)
_ = UserNotifier.deliver_account_deleted_notification(user.email, user.first_name)
socket =
socket

View file

@ -77,10 +77,11 @@ defmodule ToweropsWeb.UserSettingsLive.TotpManager do
"""
def close_device_qr_modal(socket) do
# Delete the unverified device if user cancels
if device_id = socket.assigns.new_device_id do
user = socket.assigns.current_scope.user
Accounts.delete_totp_device(device_id, user.id)
end
_ =
if device_id = socket.assigns.new_device_id do
user = socket.assigns.current_scope.user
Accounts.delete_totp_device(device_id, user.id)
end
socket
|> Phoenix.Component.assign(:show_device_qr_modal, false)

View file

@ -14,7 +14,7 @@ defmodule ToweropsWeb.WeathermapLive do
# Subscribe to topology changes and capacity updates if connected
_ =
if connected?(socket) do
Phoenix.PubSub.subscribe(Towerops.PubSub, "topology:#{organization.id}")
_ = Phoenix.PubSub.subscribe(Towerops.PubSub, "topology:#{organization.id}")
Phoenix.PubSub.subscribe(Towerops.PubSub, "capacity:#{organization.id}")
end
@ -34,9 +34,10 @@ defmodule ToweropsWeb.WeathermapLive do
}
# Schedule auto-refresh every 60 seconds
if connected?(socket) do
Process.send_after(self(), :refresh_data, 60_000)
end
_ =
if connected?(socket) do
_ = Process.send_after(self(), :refresh_data, 60_000)
end
{:ok,
socket

View file

@ -42,7 +42,7 @@ defmodule ToweropsWeb.Plugs.UpdateSessionActivity do
token ->
live_socket_id = get_session(conn, :live_socket_id)
Task.start(fn -> handle_session_activity(token, live_socket_id) end)
_ = Task.start(fn -> handle_session_activity(token, live_socket_id) end)
conn
end
end

View file

@ -343,10 +343,11 @@ defmodule ToweropsWeb.UserAuth do
Plug for routes that require the user to be authenticated.
"""
def set_user_locale(conn, _opts) do
if conn.assigns[:current_scope] && conn.assigns.current_scope.user do
locale = conn.assigns.current_scope.user.language || "en"
Gettext.put_locale(ToweropsWeb.Gettext, locale)
end
_ =
if conn.assigns[:current_scope] && conn.assigns.current_scope.user do
locale = conn.assigns.current_scope.user.language || "en"
Gettext.put_locale(ToweropsWeb.Gettext, locale)
end
conn
end
@ -499,7 +500,7 @@ defmodule ToweropsWeb.UserAuth do
if socket.assigns.current_scope && socket.assigns.current_scope.user do
locale = socket.assigns.current_scope.user.language || "en"
Gettext.put_locale(ToweropsWeb.Gettext, locale)
_ = Gettext.put_locale(ToweropsWeb.Gettext, locale)
{:cont, socket}
else
socket =
@ -1000,9 +1001,10 @@ defmodule ToweropsWeb.UserAuth do
defp determine_login_method(_conn, _params), do: "password"
defp maybe_subscribe_to_status_updates(socket, organization) do
if organization && LiveView.connected?(socket) do
Phoenix.PubSub.subscribe(Towerops.PubSub, "organization:#{organization.id}:alerts")
end
_ =
if organization && LiveView.connected?(socket) do
Phoenix.PubSub.subscribe(Towerops.PubSub, "organization:#{organization.id}:alerts")
end
socket
end