I have a system created according http://www.erlang.org/doc/system_principles/create_target.html
which includes crypto application.
I can boot it, but after I add '-mode embedded' to bin/start it seems that something does not start anymore.
I am stuck, how do I investigate? I also added -sname and -setcookie to bin/start, when I remove -mode embedded system starts, application works, I can connect to it using distributed erlang technique. But with embedded it does not interact at all.
The smallest test case is to apply the following patch to the example app from https://github.com/basho/rebar/wiki/Release-handling Once you 'rebar generate' and start it, you won't be able to connect to its erlang vm. Also it does not stop gracefully. Any ideas?
diff --git a/rel/reltool.config b/rel/reltool.config
index 0c26333..ba4bd35 100644
--- a/rel/reltool.config
+++ b/rel/reltool.config
## -6,7 +6,6 ##
kernel,
stdlib,
sasl,
- crypto,
test
]},
{rel, "start_clean", "",
## -24,7 +23,6 ##
{app, sasl, [{incl_cond, include}]},
{app, stdlib, [{incl_cond, include}]},
{app, kernel, [{incl_cond, include}]},
- {app, crypto, [{incl_cond, include}]},
{app, test, [{incl_cond, include}]}
]}.
In embedded mode, all code is loaded during system start-up according
to the boot script. (Code can also be loaded later by explicitly
ordering the code server to do so).
I think you may forgot to to load some library modules.
For debug erl, do you use +v now?
+V
Makes the emulator print out its version number.
**> +v
**Verbose**.**
How about to use rebar (rebar generation) to do the same thing (release operation)?
Rebar will generate the same kind of files for you automatically. You can compare these files with your files and find out the error. especially the boot script.
Related
I am building a server based on 'cowboy', using 'jiffy' for json processing. The problem I am running into is that after starting the shell by executing the binary generated by rebar3, only 'cowboy' is functioning as expected, but I have no access to mnesia, which is part of OTP. Also running rebar3 using the .config file produces this output:
>There are missing function calls in the release.
===> Make sure all applications needed at runtime are included in the release.
===> db_access:init_tables/0 calls undefined function **mnesia:create_table/2**
===> db_access:insert_apod_entries/1 calls undefined function **mnesia:transaction/1**
===> db_access:insert_apod_entries/1 calls undefined function **mnesia:write/1**
If I start Erlang by issuing the command 'erl' then mnesia is availabe.
I've include the rebar.config I'm using. Any help with this issue would be greatly appreciated.
%% -*- mode: erlang;erlang-indent-level: 4;indent-tabs-mode: nil -*-
%% ex: ts=4 sw=4 ft=erlang et
%% escript_incl_extra is for internal rebar-private use only.
%% Do not use outside rebar. Config interface is not stable.
{require_erts_vsn, ".*"}.
{require_otp_vsn, ".*"}.
{require_min_otp_vsn, ".*"}.
{escript_incl_extra, [{"priv/templates/*", "."}]}.
{include_src, false}.
{deps, [
{jiffy, "1.1.1", "deps/"},
{cowlib,"2.11.0", "deps/"},
{cowboy, "2.9.0", "deps/"}
]}.
{erl_first_files, ["src/db_access.erl",
"src/tar_watch_handler.erl",
"star_watch_server_app.erl",
"star_watch_server_sup.erl"
]}.
% {artifacts, ["/home/oleg/Projects/erlang_practice/star_watch_server/deps/jiffy/priv/jiffy.so"]}.
{plugins, [
{ pc, {git, "git#github.com:blt/port_compiler.git", {branch, "master"}}}
]}.
{overrides,
[{override, jiffy, [
{plugins, [pc]},
{artifacts, ["priv/jiffy.so"]},
{provider_hooks, [
{post,
[
{compile, {pc, compile}},
{clean, {pc, clean}}
]
}]
}
]}
]}.
{base_dir, "_build"}.
%% directory in '<base_dir>/<profile>/' where deps go
{deps_dir, "lib"}.
%% where rebar3 operates from; defaults to the current working directory
{root_dir, "."}.
%% where checkout dependencies are to be located
{checkouts_dir, "_checkouts"}.
%% where, under <base_dir>/<profile> checkout dependencies are to be built
{checkouts_out_dir, "checkouts"}.
%% directory in '<base_dir>/<profile>/' where plugins go
{plugins_dir, "plugins"}.
%% directories where OTP applications for the project can be located
{project_app_dirs, ["apps/*", "lib/*", "."]}.
%% Directories where source files for an OTP application can be found
{src_dirs, ["src"]}.
%% Paths to miscellaneous Erlang files to compile for an app
%% without including them in its modules list
{extra_src_dirs, []}.
%% Types dict:dict() and digraph:digraph() have been introduced in Erlang 17.
%% At the same time, their counterparts dict() and digraph() are to be
%% deprecated in Erlang 18. namespaced_types option is used to select proper
%% type name depending on the OTP version used.
{erl_opts,
[
{platform_define, "(linux|solaris|freebsd|darwin)", 'HAVE_SENDFILE'},
{platform_define, "(linux|freebsd)", 'BACKLOG', 128},
{platform_define, "R13", 'old_inets'},
{src_dirs, ["src"]}
]}.
{minimum_otp_vsn, "25.0.4"}.
{application_resource_extensions, [
".app.src.script", ".app.src"
]}.
{cover_enabled, true}.
{validate_app_modules, true}.
{base_dir, "_build"}.
%% directory in '<base_dir>/<profile>/' where deps go
{deps_dir, "lib"}.
%% where rebar3 operates from; defaults to the current working directory
{root_dir, "."}.
%% where checkout dependencies are to be located
{checkouts_dir, "_checkouts"}.
%% where, under <base_dir>/<profile> checkout dependencies are to be built
{checkouts_out_dir, "checkouts"}.
{xref_checks, []}.
{xref_queries,
[{"(XC - UC) || (XU - X - B
- (\"escript\":\"foldl\"/\"3\")
- (\"eunit_test\":\"function_wrapper\"/\"2\")
- (\"eflame\":\"apply\"/\"5\")
- (\"abnfc\":\"file\"/\"2\")
- (\"erlydtl\":\"compile\"/\"3\")
- (\"lfe_comp\":\"file\"/\"2\")
- (\"neotoma\":\"file\"/\"2\")
- (\"protobuffs_compile\":\"scan_file\"/\"2\")
- (\"gpb_compile\":\"file\"/\"2\")
- (\"gpb_compile\":\"format_error\"/\"1\")
- (\"diameter_codegen\":\"from_dict\"/\"4\")
- (\"diameter_dict_util\":\"format_error\"/\"1\")
- (\"diameter_dict_util\":\"parse\"/\"2\")
- (\"erlang\":\"timestamp\"/\"0\")
- (\"rebar_rnd\":\"seed\"/\"1\")
- (\"rebar_rnd\":\"uniform\"/\"0\"))",
[]}]}.
{dialyzer,
[
{plt_extra_apps, [diameter]},
{warnings,
[
unmatched_returns,
error_handling,
race_conditions
]}
]}.
You will need to add mnesia to your app's app.src file.
From http://rebar3.org/docs/workflow/#setting-up-dependencies
If the dependency is needed at runtime by your application in order for it to work (e.g. you need a web server or call the library directly), add it to your application’s .app.src file under the {applications, [stdlib, kernel, ...]} tuple.
The tool that generates the release (relx) also uses the same definition to figure out which applications to include in the release.
I have an OTP application. So far, I have two configuration files: rebar.config and config/vm.args, the latter of which is referenced in the former: {vm_args, "config/vm.args"}.
In the lager documentation: https://github.com/erlang-lager/lager
There is mention of another configuration file: app.config. Where does this file go and how do I reference it from my rebar config? In /src or at the root of the application? I ask because I tried adding that lager section in my rebar.config and that didn't do anything: lager is still operating with the defaults. So I probably need this app.config.
OK figured this out. In Rebar you can specify sys.config: https://www.rebar3.org/docs/releases
So I have a new file config/sys.config and my relx section now reads:
{relx, [
{release,
{myapp,"3.4.1"},
[myapp]
},
%{extend_start_script,true},
%
%for the following two fancyiness see https://www.rebar3.org/docs/releases
%Supply our own vm.args
{vm_args, "config/vm.args"},
%supply our own application configuration
{sys_config, "config/sys.config"}
]}.
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 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
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]}