Related
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 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.
I am working on MQTT broker (http://www.emqtt.io), which is written in Erlang. I have a use case where I need to call one of my python module from emqtt broker code written in erlang.
I have already checked into the google about erlport (http://erlport.org/) which is use for port communication between erlang and python. It works well in erlang shell but when I use the same in emqtt erlang code then it does not work. It throws an error shown below
17:22:40.073 <0.717.0> [error] gen_server <0.717.0> terminated with reason: call to undefined function python:start()
17:22:40.073 <0.717.0> [error] CRASH REPORT Process <0.717.0> with 1 neighbours exited with reason: call to undefined function python:start() in gen_server2:terminate/3 line 1151
17:22:40.073 <0.631.0> [error] Supervisor emqttd_session_sup had child session started with {emqttd_session,start_link,undefined} at <0.717.0> exit with reason call to undefined function python:start() in context child_terminated
17:22:40.073 <0.677.0> [error] Supervisor 'esockd_connection_sup - <0.677.0>' had child connection started with emqttd_client:start_link([{packet,[{max_clientid_len,512},{max_packet_size,65536}]},{client,[{idle_timeout,30}]},{session,...},...]) at <0.716.0> exit with reason call to undefined function python:start() in context connection_crashed
We are calling python module from emqtt plugins code, change of code is show below
on_message_acked(ClientId, Message, _Env) ->
io:format("client ~s acked: ~s~n", [ClientId, emqttd_message:format(Message)]),
io:format("client ~s",[python:start()]),
{ok, Message}.
Please help us.
I have a yaws runmod defined in yaws.conf as:
runmod = sg_app
the module contains an exported function:
start()->
io:format("~p start~n", [ sg_sup:start_link() ]).
When I start yaws I see a call to the runmod:
=INFO REPORT==== 29-Oct-2015::16:46:51 === sync call sg_app:start
{ok,<0.61.0>} start
But the supervisor is nonexistent:
1> whereis(sg_sup).
undefined
If I call the runmod:start manually, the supervisor hangs around.
2> sg_app:start().
{ok,<0.73.0>} start
ok
3> whereis(sg_sup).
<0.73.0>
What have I done wrong?
Your runmod's start/0 function is starting the supervisor with start_link/0, which means it's getting linked to the parent process. When that process dies, it takes your runmod process down with it, due to the link. The runmod feature isn't designed for starting a supervision tree.
You might instead consider using a yapp, which allows your code to run as a regular Erlang application in the same Erlang node as Yaws and be registered to have Yaws dispatch requests into it.
Another option is to launch your application using a separately spawned, infinite process:
start()->
spawn(fun () ->
application:start(my_app, permanent),
receive after infinity -> ok end
end).
What is the appropriate place for performing inets:start() ?
in `applicationname_app' module?
in applicationname_sup supervisor module?
in a child process hanging from the supervisor?\
someplace else?
(I am still struggling with inets:httpd)
Note: the answer cannot be to the tune " use a boot file " , please.
inets is a "stand-alone" Erlang application; inets:start() is just an alias to application:start(inets). I guess the answer pretty much depends on how you maintain your code.
If your code is packaged as an application, your .app file should list inets as required to be started before yours (see the applications tag). Starting your applicaion with application:start(my_app). will now ensure that inets is also started. Consequence: if you make a boot file, it will also start inets for you :-P
If you are keen on not using applications, I guess the choice depends on how your code works. If you will always need inets to be started, it is better started by any of your supervisors. If it is rarely needed, you can always make sure it is started with something like:
ensure_app_started(App) ->
case application:started(App) of
ok -> ok;
{error, already_started} -> ok;
Error -> Error
end.
In 2019, we use rebar3 to create an application and manage its dependencies. For dependencies that need to be downloaded, you add them to rebar.config, and rebar3 will download the dependencies. For example, if you add hackney (an http client) to rebar.config:
{erl_opts, [debug_info]}.
{deps, [
{hackney, ".*", {git, "git://github.com/benoitc/hackney.git", {branch, "master"}}}
]}.
{shell, [
% {config, "config/sys.config"},
{apps, [http_client]}
]}.
Then do:
../your_app_name$ rebar3 compile
rebar3 will download hackney and compile all the files in the application.
To make sure that all your dependencies get started before your app, you add the names of the dependencies to:
src/your_app_name.app.src
For instance,
{application, http_client,
[{description, "An OTP application"},
{vsn, "0.1.0"},
{registered, []},
{mod, {http_client_app, []}},
{applications,
[kernel,
stdlib,
hackney %%%<=========HERE
]},
{env,[]},
{modules, []},
{licenses, ["Apache 2.0"]},
{links, []}
]}.
The actual .app file gets created here:
_build/default/lib/your_app_name/ebin/your_app_name.app
To start your app in the shell along with all its dependencies, you do:
../your_app_name$ rebar3 shell
The inets application comes with erlang, so it doesn't need to be downloaded, so you don't specify inets as a dependency in rebar.config (you'll get an error when you $ rebar3 compile). You still need to specify inets as a dependency in your application in the file:
src/your_app_name.app.src
But rebar3 itself uses inets (to download your dependencies), so even if you didn't specify inets as a dependency in your application, inets would still get started before your app. You can test that by not specifying inets as a dependency in your application, then doing:
$ rebar3 shell
...
...
1> application:start(inets)
{error,{already_started,inets}}
But, don't rely on that and DO specify inets as a dependency in your application.
If your code is packaged as an application, list inets in the application resource file:
% Filename: ebin/flamingo.app
{application, flamingo,
[{vsn, "1.0.0"},
{modules, [flamingo_app,
flamingo_sup,
flamingo]},
{applications, [kernel,
stdlib,
inets]},
{mod, {flamingo_app, []}}
]}.
Then you can start the application using application:ensure_all_started(flamingo). This ensures that inets is started automatically for you (i.e. there is no need to explicitly call inets:start()).
For example (assuming the *.app file and *.beam files and are in ebin/):
$ erl -pa ebin/
Eshell V9.2 (abort with ^G)
1> application:ensure_all_started(flamingo).
{ok,[inets,flamingo]}