I was trying to implement an emoji server and write codes for it. But when I test it in the terminal it is showing timeout error. For checking the code please check the alias function for it:
-spec alias(Pid :: pid(), Short1 :: shortcode(), Short2 :: shortcode()) -> ok | {error, Reason :: term()}.
alias(Pid, Short1, Short2) when is_pid(Pid), is_list(Short1), is_list(Short2) ->
Pid ! {alias, Short1, Short2},
receive
{ok, Short2} -> ok;
{error, Reason} -> {error, Reason}
after 1000 -> {error, timeout}
end.
emoji_loop(State = #emoji_state{}) ->
receive
{alias, Short1, Short2} ->
io:format("Received alias: Short1 = ~p, Short2 = ~p~n", [Short1, Short2]),
case dict:find(Short1, State#emoji_state.shortcodes) of
{ok, _} ->
case dict:find(Short2, State#emoji_state.aliases) of
{ok, _} -> emoji_loop(State);
error ->
NewAliases = dict:store(Short2, Short1, State#emoji_state.aliases),
emoji_loop(State#emoji_state{aliases = NewAliases})
end;
error -> emoji_loop(State)
end;
end.
I have added io:format to debug the code and it seems my new_shortcode function has the issue, but I could not able to find out the issue.
Here is the input that I entered into the terminal:
{ok, Pid} = emoji:start([{"happy", <<"">>}, {"sad", <<"">>}]).
and then received the output like this:
{ok,<0.92.0>}
Then again entered another input
emoji:new_shortcode(Pid, "dollar", <<""/utf8>>).
and received a message like this:
Received new_shortcode: Short = "dollar", Emo = <<240,159,146,181>>
with timeout error {error,timeout}.
How can I run the create shortcode function perfectly?
Thank you for the clarification again but still I am struggling with the stop function. Here is my code for stop function in the loop.
{stop, Pid} ->
if
Pid =:= self() ->
exit(Pid);
true ->
emoji_loop(State)
end
In this stop function I need to stop the server when write the command emoji:stop(Pid). After that the server's commands for emoji will not work and give errors. Here is the stop main function where pass the Pid as you instructed.
-spec stop(Pid :: pid()) -> ok | {error, Reason :: term()}.
stop(Pid) when is_pid(Pid) ->
Pid ! {stop, self()},
receive
ok -> ok;
{error, Reason} -> {error, Reason}
after 5000 ->
{error, timeout}
end.
Looking at the
new_shortcode/3function, we see that it sends a message toPidand then expects a response, but it fails with{error, timeout}because it never gets that response:The
Pidhere is the process running theemoji_loop/1function, which receives commands in the form of tuples and carries them out by changing the loop state. But what theemoji_loop/1function doesn't do is send a message back to the process sending the command, which is why a function likenew_shortcode/3times out waiting for a reply.To fix it, send the caller's pid to
emoji_loop/1so it can reply. This means changingnew_shortcode/1to addself()into the command tuple it sends toemoji_loop/1:We then have to change
emoji_loop/1to send a reply back to the caller. For example, change the handling ofnew_shortcodelike this:With this change and a similar change for
lookup, we can see it works as expected:We have to make similar changes to all command functions that expect replies from the
emoji_loop/1process.I strongly suggest you to look into using a
gen_serverrather than rolling your own server, as it easily handles everything you're trying to do here and also helps with error handling and with process management and cleanup.Update: the question was revised to add a specific question about
emoji:stop/1, so I'm updating my answer to address it:The original
stophandler inemoji_loop/1simply exited:To address the timeout problem, you've modified it to be:
But there are two problems with this change:
Pidwill never beself()becauseemoji_loop/1doesn't send itself messages, so the first clause of theifjust never happens.emoji_loop/1call itself recursively as in thetrueclause means that the loop process keeps running rather than stopping as requested.To fix these issues, you have to fix the
stophandler just the same as thenew_shortcodehandler was fixed above: pass the caller's pid with the command, and have the command handler send a reply back to the caller. If we go back to the originalstophandler and make these changes, we get:And the
stop/1function has to be changed to send its pid with the command:We can test
stop/1to verify that it actually stops the loop process: