Search code examples
erlanggen-server

Gen Server Error noproc


I get the following error when I try to run my program through shell using erlang.mk.

=INFO REPORT==== 5-May-2016::05:47:57 ===
application: rad
exited: {bad_return,
            {{rad_app,start,[normal,[]]},
             {'EXIT',
                 {noproc,{gen_server,call,[rad_config,{lookup,port}]}}}}}
type: permanent
Eshell V6.4  (abort with ^G)
([email protected])1> {"Kernel pid terminated",application_controller,"{application_start_failure,rad,{bad_return,{{rad_app,start,[normal,[]]},{'EXIT',{noproc,{gen_server,call,[rad_config,{lookup,port}]}}}}}}"}
Kernel pid terminated (application_controller) ({application_start_failure,rad,{bad_return,{{rad_app,start,[normal,[]]},{'EXIT',{noproc,{gen_server,call,[radheart: Thu May  5 05:47:58 2016: _coErlang is crashing .. (waiting for crash dump file)nf
ig,{lookup,porheart: Thu May  5 05:47:58 2016: tWould reboot. Terminating.}
]}}}}}})
make: *** [run] Error 1

rad.app.src

{application, rad,
[
{description, "Awesome server written in Erlang"},
{vsn, "0.0.1"},
{registered, [rad_sup, rad_config]},
{modules, []},
{applications, [
  kernel,
  stdlib,
  cowboy
]},
{mod, {rad_app, []}},
{env, []}
]}.

rad_config.erl

-module(rad_config).
-behaviour(gen_server).

%% API
-export([start_link/0]).

%% Gen Server Callbacks
-export([init/1 , handle_call/3 , handle_cast/2 , handle_info/2 , terminate/2 , code_change/3]).
-export([lookup/1]).

-define(SERVER, ?MODULE).
-record(state, {conf}).

start_link() ->
    gen_server:start_link({local, ?SERVER}, ?MODULE, [], []).

init([]) ->
    {ok, Conf} = file:consult("config/rad.cfg"),
    {ok, #state{conf = Conf}}.

handle_call({lookup, Tag} , _From , State) ->
    Reply = case lists:keyfind(Tag, 1, State#state.conf) of
            {Tag, Value} ->
                Value;
                    false ->
                        {error, noinstance}
        end,
    {reply, Reply, State};

handle_call(_Request, _From, State) ->
    Reply = ok,
    {reply, Reply, State}.

handle_cast(_Msg , State) ->
    {noreply, State}.

handle_info(_Info , State) ->
    {noreply, State}.

terminate(Reason , _State) ->
    io:format("~n Server shutdown. Reason: ~s.~n", [Reason]),
    ok.

code_change(_OldVsn , State , _Extra) ->
    {ok, State}.

lookup(Tag) ->
    gen_server:call(?SERVER, {lookup, Tag}).

rad_app.erl

-module(rad_app).
-behaviour(application).

-export([start/2]).
-export([stop/1]).

%%  First we need to define and compile the dispatch list, a list of routes
%%  that Cowboy will use to map requests to handler modules. Then we tell
%%  Cowboy to listen for connections.
start(_Type, _Args) ->
    Port = rad_config:lookup(port),

    Dispatch = cowboy_router:compile([
    {'_', [{"/", route_handler, []}]}
      ]),
    {ok, _} = cowboy:start_http(rad_http_listener, 100,
    [{port, Port}], [{env, [{dispatch, Dispatch}]}]),

    %% Start the supervisor
    rad_sup:start_link().

stop(_State) ->
    ok.

rad_sup.erl

-module(rad_sup).
-behaviour(supervisor).

%% API
-export([start_link/0]).
%% Supervisor callbacks
-export([init/1, shutdown/0]).

-define(SERVER, ?MODULE).

%% Helper macro for declaring children of supervisor
-define(CHILD(I, Type), {I, {I, start_link, []}, permanent, 5000, Type, [I]}).

%%         ===================================================================
%% API functions
%% ===================================================================

start_link() ->
    supervisor:start_link({local, ?SERVER}, ?MODULE, []).

%% ===================================================================
%% Supervisor callbacks
%% ===================================================================

init([]) ->
    RestartStrategy = simple_one_for_one,
    MaxRestarts = 10,
    MaxSecondsBwRestarts = 5,

    SupFlag = {RestartStrategy, MaxRestarts, MaxSecondsBwRestarts},

    Processes = [?CHILD(rad_config, worker)],
    {ok, {SupFlag, Processes}}.

%% Supervisor can be shutdown by calling exit(SupPid,shutdown)
%% or, if it's linked to its parent, by parent calling exit/1.
shutdown() ->
    exit(whereis(?MODULE), shutdown).

So basically I've two questions related to the error that is thrown here:

  1. Is this error thrown because my gen_server is not able to start?

  2. The line in rad_config corresponding to file:consult/1, I want to ask from where does this function fetches the file as in the parameter that I've passed to it is config/rad.cfg but all the .erl files are stored in src folder. And both these folders src and config are at the same directory level. So, the parameter that I've passed to file:consult/1, is it correct? Although I've tried to pass the parameter as ../config/rad.cfg also. I still get the same error.

Please help me out. I'm new to Erlang and I'm trying to solve this error for quite some time. Btw, I using Erlang 17.5.


Solution

  • First, it seems like when you run rad_app.erl your rad_config server is not yet started. so when your get to this line:

    Port = rad_config:lookup(port)
    

    You are actually calling:

    lookup(Tag) ->
        gen_server:call(?SERVER, {lookup, Tag}).
    

    And the gen_server is not started so you are getting a noproc error.

    In addition to this, even if the server was started already, you are not able to make a gen_server:call to your self. The best way to handle a case that you want to send yourself an event is to open a new process using spawn and from inside the spawned process make the call.

    Your should read more about gen_server and OTP.