From 37c9ac79ed238f0295a4af7794d54f0c1ec246a9 Mon Sep 17 00:00:00 2001 From: Graham McIntire Date: Fri, 25 Jul 2025 12:54:13 -0500 Subject: [PATCH] Fix Process.alive? crash with remote PIDs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The cleanup_stale_registrations function was calling Process.alive? on remote PIDs, which causes an ArgumentError. Fixed by: - Using Process.alive? only for local PIDs - Using :rpc.call for remote PID liveness checks - Adding proper error handling for RPC failures - Cleaning up registrations for disconnected nodes This prevents GenServer crashes when checking leader status. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- lib/aprsme/cluster/leader_election.ex | 43 +++++++++++++++++++++++---- 1 file changed, 37 insertions(+), 6 deletions(-) diff --git a/lib/aprsme/cluster/leader_election.ex b/lib/aprsme/cluster/leader_election.ex index 19cfa73..a1796fa 100644 --- a/lib/aprsme/cluster/leader_election.ex +++ b/lib/aprsme/cluster/leader_election.ex @@ -136,13 +136,44 @@ defmodule Aprsme.Cluster.LeaderElection do :ok pid when is_pid(pid) -> - # Check if the registered process is alive and on a connected node - if Process.alive?(pid) and node(pid) in [node() | Node.list()] do - # Process is alive and on a connected node - leave it alone - :ok + pid_node = node(pid) + connected_nodes = [node() | Node.list()] + + # Check if the PID's node is still connected + if pid_node in connected_nodes do + # Node is connected, try to check if process is alive + try do + if pid_node == node() do + # Local PID - use Process.alive? + if Process.alive?(pid) do + :ok + else + Logger.info("Cleaning up stale leader registration for dead local process #{inspect(pid)}") + :global.unregister_name(@election_key) + end + else + # Remote PID - use RPC to check if alive + case :rpc.call(pid_node, Process, :alive?, [pid]) do + true -> + :ok + + false -> + Logger.info("Cleaning up stale leader registration for dead remote process #{inspect(pid)}") + :global.unregister_name(@election_key) + + {:badrpc, _reason} -> + Logger.info("Cleaning up stale leader registration for unreachable process #{inspect(pid)}") + :global.unregister_name(@election_key) + end + end + rescue + _error -> + Logger.info("Cleaning up stale leader registration for problematic process #{inspect(pid)}") + :global.unregister_name(@election_key) + end else - # Process is dead or on a disconnected node - unregister it - Logger.info("Cleaning up stale leader registration for dead/disconnected process #{inspect(pid)}") + # Node is disconnected - clean up the registration + Logger.info("Cleaning up stale leader registration for disconnected node #{pid_node}") :global.unregister_name(@election_key) end end