Erlang application problem - erlang

I try to write application to my Erlang program.
I have test_app.erl:
-module(test_app).
-behaviour(application).
%% Application callbacks
-export([start/2, stop/1]).
start(_Type, _StartArgs) ->
test_sup:start_link().
stop(_State) ->
ok.
And .app file:
{application, test,
[{description, "test system."},
{vsn, "1.0"},
{modules, [test_app, test_sup, fsm]},
{registered, [test_sup, fsm]},
{applications, [kernel, stdlib]},
{mod, {test_app, []}}
]}.
When i try to start application:
application:start(test).
I get error:
=INFO REPORT==== 18-Feb-2011::19:38:53 ===
application: test
exited: {bad_return,
{{test_app,start,[normal,[]]},
{'EXIT',
{undef,
[{test_sup,start_link,[[]]},
{test_app,start,2},
{application_master,start_it_old,4}]}}}}
type: temporary
{error,{bad_return,{{test_app,start,[normal,[]]},
{'EXIT',{undef,[{test_sup,start_link,[[]]},
{test_app,start,2},
{application_master,start_it_old,4}]}}}}}
What's wrong? How can i fix it?
If i make in eshell:
test_app:start(normal, []).
Than all works.
Thank you.

I suppose this might be caused by not loading the [proper] .beam. Ensure that all modules are in the same directory, or try to use -pa key to erl(1), e. g.:
$ erl -pa ../ebin
1> application:start(test).
...

Related

Can not start Erlang Application due to bad return error

I have a simple erlang application and i am trying to start it to no avail getting a bad return error:
> {error,
> {bad_return,
> {{mapp,start,[normal,[]]},
> {'EXIT',
> {undef,
> [{mapp,start,[normal,[]],[]},
> {application_master,start_it_old,4,
> [{file,"application_master.erl"},{line,277}]}]}}}}}
.app
{
application,mapp,
[
{vsn,"1.0.0"},
{description,"some description"},
{mod,{mapp,[]}},
{modules,[mapp,m1]}
]
}.
Folder structure:
-root
-mapp.app
-src
-m1.erl
-mapp.erl
-include
-state.hrl
-ebin
Application
-module(mapp).
-behaviour(application).
-export([start/2,stop/1]).
start(normal,_Args)->
Pid=m1:start_link(),
{ok,Pid}.
stop(State)->ok.
Module
-module(m1).
-include("r.hrl").
-export([start_link/0]).
start_link()->
Pid=spawn_link(?MODULE,serv,#state{count=2}),
Pid.
serv(State=#state{count=C})->
receive
{From,MSG} ->From ! {ok,MSG},
serv(State#state{count=C=1})
end.
.hrl
-record(state,{
count=0
}).
So my m1 module returns a Pid.I comply to the application:start/2 return type and return a {ok,Pid}.
What is wrong here ? I have tried both with Pid and {ok,Pid} to no avail.
The error states that the mapp:start/2 is undef. Seeing that your mapp.erl exports it, I suspect that the module mapp is not loaded.
How are you running the application? I suspect that you're not using a release tool like rebar3 or erlang.mk because usually the app files are inside src.

How to configure httpc profiles with rebar3?

How can I set configuration options for httpc's profiles when using rebar3?
Here is the only example being via erl -config inets.config that looks like this:
[{inets,
[{services,[{httpc,[{profile, server1}]},
{httpc, [{profile, server2}]}]}]
}].
I tried adopting it to my rebar3 project structure.
Code
Project was created with rebar3, with standard OTP layout:
rebar3 new release myapp
Here is my myapp/config/sys.config:
[
{ myapp, []},
{inets, [{services, [{httpc, [{profile, myapp}]}]}]}
].
rebar.config:
{erl_opts, [debug_info]}.
{deps, []}.
{relx, [{release, { myapp, "0.1.0" },
[myapp,
sasl]},
{sys_config, "./config/sys.config"},
{vm_args, "./config/vm.args"},
{dev_mode, true},
{include_erts, false},
{extended_start_script, true}]
}.
{profiles, [{prod, [{relx, [{dev_mode, false},
{include_erts, true}]}]
}]
}.
Here is my myapp.app.src file for completeness:
{application, myapp,
[{description, "An OTP application"},
{vsn, "0.1.0"},
{registered, []},
{mod, { myapp_app, []}},
{applications,
[kernel,
stdlib
]},
{env,[]},
{modules, []},
{maintainers, []},
{licenses, []},
{links, []}
]}.
Requests
Here is a request I'm trying to make from rebar`s shell:
$ ./rebar3 shell
1> ===> Booted myapp
1> ===> Booted sasl
...
1> httpc:request( "http://reddit.com", myapp).
** exception exit: {noproc,
{gen_server,call,
[httpc_myapp,
{request,
{request,undefined,<0.88.0>,0,http,
{"reddit.com",80},
"/",[],get,
{http_request_h,undefined,"keep-alive",undefined,
undefined,undefined,undefined,undefined,undefined,
undefined,...},
{[],[]},
{http_options,"HTTP/1.1",infinity,true,
{essl,[]},
undefined,false,infinity,...},
"http://reddit.com",[],none,[],1478280329839,
undefined,undefined,false}},
infinity]}}
in function gen_server:call/3 (gen_server.erl, line 212)
in call from httpc:handle_request/9 (httpc.erl, line 574)
Here is the request without a profile, to check that inets actually works:
2> httpc:request( "http://reddit.com").
=PROGRESS REPORT==== 4-Nov-2016::13:25:51 ===
supervisor: {local,inet_gethost_native_sup}
started: [{pid,<0.107.0>},{mfa,{inet_gethost_native,init,[[]]}}]
=PROGRESS REPORT==== 4-Nov-2016::13:25:51 ===
supervisor: {local,kernel_safe_sup}
started: [{pid,<0.106.0>},
{id,inet_gethost_native_sup},
{mfargs,{inet_gethost_native,start_link,[]}},
{restart_type,temporary},
{shutdown,1000},
{child_type,worker}]
{ok,{{"HTTP/1.1",200,"OK"},...
rebar3 itself use inets http clients so when It starts your application in shell, inets is already started and configured. One workaround would be stop inets before your application starts, as It's suggested by rebar3 developer (copied below). Another one would be boot your release in console mode:
./_build/default/rel/myapp/bin/myapp console
Beside that there is another problem with your project. You have not told you want inets being started for you. You should have this line in myapp.src:
{applications, [kernel, stdlib, inets]}
Or you can list inets in rebar.config release section, to tell relx this app should be included in release and started on boot.
{relx, [{release, { myapp, "0.1.0" }, [inets, myapp, sasl]} ]}
Stop Inets from Loading on rebar3 shell startup
Here is the copy of the full answer by Fred Hebert from the rebar3 mailing list:
We do need inets for package fetching and will likely not turn it off
automatically for all use cases as this could compromise general usage
of the rebar3 agent in case where the user application does not use
inets, but still asks to fetch packages in a subsequent run. The
workaround I would suggest would be to use a hook script for it. Hook
scripts run before we boot user applications and are regular escripts:
#!/usr/bin/env escript
main(_) -> application:stop(inets).
You can then hook the script in with:
{shell, [{script_file, "path/to/file"}]}
in rebar3.config, or with
rebar3 shell --script_file test/check_env.escript
I can't find anything in the documentation to suggest that rebar.config can contain the application configuration you want.
Instead, application configuration is often kept in a configuration directory in your application, and like the example you gave says, you must use the -config flag when launching erl to point to the configuration file.
If you use rebar3 for making release and start your service by script made with relx (from _build/default/rel/<release_name>/bin/<release_name> by default) the application configuration file is passed to erl for you. If config file exist in your application directory, by default in config/sys.config, It will be regarded as application configuration, otherwise an empty configuration will be made. You can customize Its path by relax' release option sys_config.
For our software, we typically had a single config/sys.config file. The structure is the same as the config sample you have provided. Note that the configuration file can contain settings for many different services. For example, mixing inets with one of ours:
[{inets, [
{services,[{httpc,[{profile, server1}]},
{httpc, [{profile, server2}]}]}
]},
{my_app, [
{my_setting, "my value"}
]}
].
We launch with erl -config config/sys.config.
This way if we need to set service configuration we can simply update our configuration file, which also houses the configuration specific to this application.
As far as I'm aware, this is the correct method to use. I have not been able to find documentation supporting any other way of doing this.

Start GProc as a dependency

I am trying to start gproc as a dependency inside the app, but it fails with:
{error,{not_started,gproc}}
This is my app.src file which is used by Rebar3 when compiling:
{application, myapp,
[{description, "MyApp"},
{vsn, "0.1.0"},
{registered, []},
{mod, { my_app, []}},
{applications,
[kernel,
stdlib,
sasl,
gproc <--- Dependency, and is compiled with Rebar3
]},
{env,[]},
{modules, []},
{maintainers, []},
{licenses, []},
{links, []}
]}.
When starting from the shell with application:start(gproc). and then application:start(myapp). everything works beautifully. I don't understand why...
Maybe it is because of some sort of race condition?
The shell is started with:
erl -pa _build/default/lib/*/ebin -boot start_sasl -eval "application:start(myapp)"
Edit: When using rebar3 shell all works fine, what is the difference from the shell command I am using?
Use
application:ensure_all_started(myapp).
The plain start tries to start only the requested application, only verifying that the dependencies are already running.
Docs:
application:start/1:
Starts Application. If it is not loaded, the application controller first loads it using load/1. It ensures that any included applications are loaded, but does not start them. That is assumed to be taken care of in the code for Application.
application:ensure_all_started/1:
Equivalent to calling start/1,2 repeatedly on all dependencies that are not yet started for an application

Error running the cowboy application

I am having trouble starting the cowboy application it is giving me following error. For some reason the ranch is not starting, although I have added code to start the ranch in my application.
I see a new git repo cowlib being pulled. but still having trouble.
1> application:start(satomi).
{error,
{bad_return,
{{satomi_app,start,[normal,[]]},
{'EXIT',
{noproc,
{gen_server,call,
[ranch_sup,
{start_child,
{{ranch_listener_sup,http},
{ranch_listener_sup,start_link,
[http,100,ranch_tcp,
[{port,9090}],
cowboy_protocol,
[{...}]]},
permanent,5000,supervisor,
[ranch_listener_sup]}},
infinity]}}}}}}
=INFO REPORT==== 12-Sep-2013::11:42:46 ===
application: satomi
exited: {bad_return,
{{satomi_app,start,[normal,[]]},
{'EXIT',
{noproc,
{gen_server,call,
[ranch_sup,
{start_child,
{{ranch_listener_sup,http},
{ranch_listener_sup,start_link,
[http,100,ranch_tcp,
[{port,9090}],
cowboy_protocol,
[{env,
[{dispatch,
[{'_',[],[{[],[],toppage_handler,[]}]}]}]}]]},
permanent,5000,supervisor,
[ranch_listener_sup]}},
infinity]}}}}}
type: temporary
Following is my app.src
>cat satomi.app.src
{application, satomi,
[
{description, ""},
{vsn, "1"},
{registered, []},
{applications, [
kernel,
stdlib,
cowboy
]},
{mod, { satomi_app, []}},
{env, []}
]}.
>cat satomi.erl
-module(satomi).
-export([start/0]).
start()->
ok = application:start(crypto),
ok = application:start(sasl),
ok = application:start(ranch),
ok = application:start(cowlib),
ok = application:start(cowboy),
ok = application:start(satomi).
I am trying to figure out what's going wrong here
Can anyone point me to the working sample of cowboy that I can use as a template. I am using rebar to compile the code. I don't think that should make any difference.
I am using following command to start the application
erl -pa ./ebin ./deps/*/ebin
When calling application:start(satomi) from the shell it doesn't automatically start the applications it depends on, those need to be started manually.
The satomi:start/0 function you have does exactly this, so the solution is to call satomi:start() from the shell.
The reason is that application:start(satomi) will actually not call satomi:start(), it is a convenience method for starting the application and its dependencies when the application is not part of an Erlang release.
UPDATE: Since Erlang R16B02, there is also application:ensure_all_started. It starts all the dependencies automatically.

Cannot run a simple application in Erlang

I wrote a simple application in Erlang, but it refuses to work with the following error:
=SUPERVISOR REPORT==== 18-Jan-2012::15:03:27 ===
Supervisor: {<0.60.0>,my_sup}
Context: start_error
Reason: {'EXIT',{undef,[{my,start,[{8077,none}]},
{supervisor,do_start_child,2},
{supervisor,start_children,3},
{supervisor,init_children,2},
{gen_server,init_it,6},
{proc_lib,init_p_do_apply,3}]}}
Offender: [{pid,undefined},
{name,my},
{mfa,{my,start,[{8077,none}]}},
{restart_type,permanent},
{shutdown,brutal_kill},
{child_type,worker}]
=INFO REPORT==== 18-Jan-2012::15:03:27 ===
application: my
exited: {shutdown,{my_app,start,[normal,[noarg]]}}
type: temporary {error,{shutdown,{my_app,start,[normal,[noarg]]}}}
And the modules:
my.erl
-module(my).
-export([start/2, stop/0]).
start(Port,_arg) ->
io:format("starting my").
stop() ->
ok.
my_app.erl Application module, perform application behavior.
-module(my_app).
-behaviour(application).
-export([start/2, stop/1]).
start(_Type, _Args) ->
io:format("my server starting~n"),
my_sup:start_link().
stop(_State) ->
io:format("my server terminating~n"),
ok.
my_sup.erl Supervisor logic
-module(my_sup).
-behaviour(supervisor).
-export([start_link/0]).
-export([init/1]).
start_link() ->
supervisor:start_link(my_sup, []).
init(_Args) ->
{ok, {
{one_for_one, 10, 60},
[{my, {my, start, [{8077,none}]
},
permanent, brutal_kill, worker, [my]}]}}.
Config file (my.app):
{application, my,
[
{description, "Demo"},
{vsn, "1.0"},
{id, "hello"},
{modules, [my,my_sup]},
{registered, [my,my_sup]},
{applications, [kernel, stdlib]},
%%
%% mod: Specify the module name to start the application, plus args
%%
{mod, {my_app, [noarg]}},
{env, []}
]
}.
I changed child spec like you recommend, but the problem still remains.
=SUPERVISOR REPORT==== 19-Jan-2012::00:34:21 ===
Supervisor: {<0.96.0>,my_sup}
Context: start_error
Reason: <0.97.0>
Offender: [{pid,undefined},
{name,my},
{mfa,{my,start,[8077,none]}},
{restart_type,permanent},
{shutdown,brutal_kill},
{child_type,worker}]
=ERROR REPORT==== 19-Jan-2012::00:34:21 ===
Error in process <0.97.0> with exit value:
{{badmatch,{error,eaddrinuse}},[{my,'- start/2-fun-0-',1}]}
=INFO REPORT==== 19-Jan-2012::00:34:21 ===
application: my
exited: {shutdown,{my_app,start,[normal,[noarg]]}}
type: temporary
{error,{shutdown,{my_app,start,[normal,[noarg]]}}}
The my:start/2 should take two arguments but in the child specification you only give it one argument ({8077,none}). You could change the child spec to:
{my, {my, start, [8077,none]}, permanent, brutal_kill, worker, [my]}
As an aside your indentation and line breaking of the Supervisor Specification is a bit off making it difficult to see what belongs to what.
EDIT: Comment to new error
This is not the same problem as before. You are getting a new error, eaddrinuse, which normally means you are trying to use an IP address/port which is already in use. This would imply you are doing some socket programming in your code.
Your supervisor specifies that my:start should take one argument, but it takes two. You probably want to change the child spec to:
{one_for_one, 10, 60},[{my, {my, start, [8077,none]}
Your my:start/2 provides a wrong return value.
Supervisor expects tuple {ok,Pid}, while your function simply returns ok (the last call is to io:format, which returns ok, so your function also does).
If you want to use a supervisor, you must spawn a new process and link it to the supervisor. For example
start(_) -> {ok,spawn_link(fun() -> io:format("~w started~n",[self()]),timer:sleep(5000),io:format("~w exiting~n",[self()]) end)}.
should do the job for you.

Resources