What I’m Trying to Do
I’m just starting out learning Elixir, coming from an imperative programming background. I’m working on a system that needs to maintain a mapping of user_id -> pid
.
For each user_id
, I want to ensure:
-
There is exactly one active process at any time.
-
When a new process claims a
user_id
: -
Any existing process for that
user_id
is terminated. -
The new process immediately takes over the
user_id
mapping. -
This should happen without retries, reconnects, or race conditions.
What I’ve Tried
Registry
I’m using a :unique
Registry. The approach is:
- Lookup the existing process with:
Registry.lookup(user_id)
- If found, call:
Process.exit(old_pid, :some_reason)
- Register the new process with:
Registry.register(user_id, pid)
Problem: There’s a race condition. The new process may attempt to register before the old process has unregistered, resulting in:
{:error, {:already_registered, pid}}
This forces retries or client reconnects, which I’d like to avoid.
ETS
ETS allows atomic key replacement with :ets.insert
, but:
-
No automatic cleanup when processes die.
-
I’d need to manually
Process.monitor
and handle:DOWN
messages.
My Questions
-
Is there a way to atomically replace a Registry mapping from another process, without requiring reconnects or retries?
-
If not, and ETS is the way forward, what are the best practices for managing cleanup and avoiding stale entries?
-
Otherwise, how can I achieve what I’m trying to do?
Thanks for any insights!