Current section

Files

Jump to
erlang_python src py_event_worker_registry.erl
Raw

src/py_event_worker_registry.erl

%% @doc ETS-based registry for event workers.
%% Provides O(1) worker lookup by loop_id.
-module(py_event_worker_registry).
-behaviour(gen_server).
-export([start_link/0, register/3, unregister/1, lookup/1, lookup_pid/1, list_all/0]).
-export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]).
-define(TAB, py_event_workers).
start_link() -> gen_server:start_link({local, ?MODULE}, ?MODULE, [], []).
register(LoopId, WorkerPid, LoopRef) ->
gen_server:call(?MODULE, {register, LoopId, WorkerPid, LoopRef}).
unregister(LoopId) ->
gen_server:call(?MODULE, {unregister, LoopId}).
lookup(LoopId) ->
case ets:lookup(?TAB, LoopId) of
[{LoopId, WorkerPid, LoopRef}] -> {ok, {WorkerPid, LoopRef}};
[] -> {error, not_found}
end.
lookup_pid(LoopId) ->
case ets:lookup(?TAB, LoopId) of
[{LoopId, WorkerPid, _}] -> {ok, WorkerPid};
[] -> {error, not_found}
end.
list_all() -> ets:tab2list(?TAB).
init([]) ->
?TAB = ets:new(?TAB, [named_table, public, set, {read_concurrency, true}]),
{ok, #{}}.
handle_call({register, LoopId, WorkerPid, LoopRef}, _From, State) ->
true = ets:insert(?TAB, {LoopId, WorkerPid, LoopRef}),
MonRef = erlang:monitor(process, WorkerPid),
NewState = maps:put(WorkerPid, {LoopId, MonRef}, State),
{reply, ok, NewState};
handle_call({unregister, LoopId}, _From, State) ->
case ets:lookup(?TAB, LoopId) of
[{LoopId, WorkerPid, _}] ->
true = ets:delete(?TAB, LoopId),
case maps:get(WorkerPid, State, undefined) of
{LoopId, MonRef} ->
erlang:demonitor(MonRef, [flush]),
{reply, ok, maps:remove(WorkerPid, State)};
_ -> {reply, ok, State}
end;
[] -> {reply, ok, State}
end;
handle_call(_, _, State) -> {reply, {error, unknown_request}, State}.
handle_cast(_, State) -> {noreply, State}.
handle_info({'DOWN', MonRef, process, WorkerPid, _Reason}, State) ->
case maps:get(WorkerPid, State, undefined) of
{LoopId, MonRef} ->
true = ets:delete(?TAB, LoopId),
{noreply, maps:remove(WorkerPid, State)};
_ -> {noreply, State}
end;
handle_info(_, State) -> {noreply, State}.
terminate(_, _) -> ok.
code_change(_, State, _) -> {ok, State}.