{application, irc,
[{description, "IRC protocol application"},
- {vsn, "5"},
+ {vsn, "6"},
{modules, [irc_util, irc_app, irc_sup, irc_net_sup, irc_conn,
irc_object_sup, irc_amqp_listener, irc_command]},
- {registered, [irc_sup]},
+ {registered, [irc_sup, irc_dummy]},
{applications, [core, amqp]},
{mod, {irc_app, []}}
]}.
-behavior(gen_server).
-vsn(2).
+-define(RECONNECT_TIME, 30000).
+
-export([
start_link/3,
send_command/2
init({Instance, Supervisor, TableId}) ->
ets:insert(TableId, {irc_conn_pid, self()}), % record the connection PID in the table
+ % The reconnect_timer sends a dummy message to a process that does not exist,
+ % simply so that we can read whether it has fired or not. This lets us prevent
+ % reconnecting to the server too quickly.
+ case ets:lookup(TableId, reconnect_timer) of
+ [{reconnect_timer, TimerId}] ->
+ case erlang:read_timer(TimerId) of
+ false -> ok;
+ Millis ->
+ % sleep that long in this process, since the process that set
+ % the timer is long dead.
+ timer:sleep(Millis)
+ end;
+ [] -> ok
+ end,
+ NewTimerId = erlang:start_timer(?RECONNECT_TIME, irc_dummy, ok),
+ ets:insert(TableId, {reconnect_timer, NewTimerId}),
+
gen_server:cast(self(), create_object_sup), % This process is tasked with creating
% the irc_object_sup, but we defer until
% after init() finishes to avoid deadlock
supervisor,
[irc_object_sup]
},
- {ok, ObjectSupPid} = supervisor:start_child(Supervisor, ObjectSup),
+ % Pattern match to handle the case where the object_sup starts before irc_conn
+ case supervisor:start_child(Supervisor, ObjectSup) of
+ {ok, ObjectSupPid} -> ok;
+ {error, {already_started, ObjectSupPid}} -> ok
+ end,
{ok, ObjectSupPid}.
%% @doc Kills the irc_object_sup running under this supervisor