Related
I have created a release of my program with rebar. Navigating around in the output directory I see my Erlang source files. Is there any way to create binary only releases of Erlang programs, so that they can be distributed (as closed source) to customers?
Yes, in rebar.config file. {include_src, false} in prod section
{profiles, [
{dev1, [{relx, [{dev_mode, false},
{include_erts, false},
{sys_config, "./config/dev1/sys.config"},
{vm_args, "./config/dev1/vm.args"}]}
]
},
{prod, [{relx, [{dev_mode, false},
{include_erts, true},
{include_src, false},
{sys_config, "./config/prod/sys.config"},
{vm_args, "./config/prod/vm.args"}]}]
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 created a Erlang application, a small calendar_server. Which insert events, retrieve them and also edit and delete the events. It works correctly when run on the prompt(using erl). I inserted events(birthdays, meetings etc), then the database(Mnesia.nonode#nohost) is created on the directory. And it possible to retrieve the events. But when created the same application using rebar/rebar3, no database is created. I really like to know what the problem i have faced, or what mistake i did.
The reltool.config and calendarApp.app.src are given below..
reltool.config
{sys, [
{lib_dirs, ["../apps"]},
{erts, [{mod_cond, derived}, {app_file, strip}]},
{app_file, strip},
{rel, "calendarApp", "1",
[
kernel,
stdlib,
sasl,
mnesia,
calendarApp
]},
{rel, "start_clean", "",
[
kernel,
stdlib
]},
{boot_rel, "calendarApp"},
{profile, embedded},
{incl_cond, exclude},
{excl_archive_filters, [".*"]}, %% Do not archive built libs
{excl_sys_filters, ["^bin/.*", "^erts.*/bin/(dialyzer|typer)",
"^erts.*/(doc|info|include|lib|man|src)"]},
{excl_app_filters, ["\.gitignore"]},
{app, sasl, [{incl_cond, include}]},
{app, stdlib, [{incl_cond, include}]},
{app, kernel, [{incl_cond, include}]},
{app, mnesia, [{incl_cond, include}]},
{app, calendarApp, [{incl_cond, include}]}
]}.
{target_dir, "calendarApp"}.
{overlay, [
{mkdir, "log/sasl"},
{copy, "files/erl", "\{\{erts_vsn\}\}/bin/erl"},
{copy, "files/nodetool", "\{\{erts_vsn\}\}/bin/nodetool"},
{copy, "files/calendarApp", "bin/calendarApp"},
{copy, "files/calendarApp.cmd", "bin/calendarApp.cmd"},
{copy, "files/start_erl.cmd", "bin/start_erl.cmd"},
{copy, "files/install_upgrade.escript", "bin/install_upgrade.escript"},
{copy, "files/sys.config", "releases/\{\{rel_vsn\}\}/sys.config"},
{copy, "files/vm.args", "releases/\{\{rel_vsn\}\}/vm.args"}
]}.
calendarApp.app.src
{application, calendarApp,
[
{description, ""},
{vsn, "1"},
{registered, []},
{applications, [
kernel,
stdlib,
mnesia
]},
{mod, { calendarApp_app, []}},
{env, []}
]}.
If anyone know why the database is not created, please help me to find my mistake.
For creating disc-based Mnesia you can use mnesia:create_schema/1 function (which I think you did somewhere in your code). This function requires Mnesia to be stopped.
In your reltool.config you specified mnesia application before calendarApp application which is where you probably created mnesia disc-based schema. It means that mnesia was started before creating its schema, so the schema cannot be created.
If you change the order of mnesia and calendarApp under the key of rel in your reltool.config file, everything should be correct.
{sys, [
{lib_dirs, ["../apps"]},
{erts, [{mod_cond, derived}, {app_file, strip}]},
{app_file, strip},
{rel, "calendarApp", "1",
[
kernel,
stdlib,
sasl,
calendarApp,
mnesia
]},
...
Yes, I started myApp (dumperl_sync) first:
{relx, [{release, { dumperl_sync, "0.1.0" },
[dumperl_sync,
sasl,
mnesia
]},
...
}.
Then, in application behaviour:
start(_Application, _Type) ->
application:set_env(mnesia, dir,"/path/to/Mnesia.node"),
mnesia:create_schema([node()])
...
end.
Then, in gen_server behaviour inside handle_info:
handle_info(_, State) ->
mnesia:start(),
mnesia:create_table(dates,
[
{disc_only_copies, [node()]},
{attributes,record_info(fields, dates)}
]
)
....
{noreply, State}.
dates is a record:
-record(dates,{}).
Everything should be correct!
I am trying to build mongooseim with rabbitMQ. Im getting the below error while doing make rel.
==> rel (generate)
ERROR: generate failed while processing /home/mongoose/MongooseIM/rel: {'EXIT',{{badmatch,{error,"Module mochijson2 potentially included by two different applications: mochijson2 and rabbit_common."}},
[{rebar_reltool,generate,2,[]},
{rebar_core,run_modules,4,[]},
{rebar_core,execute,5,[]},
{rebar_core,process_dir1,6,[]},
{rebar_core,process_each,5,[]},
{rebar_core,process_dir1,6,[]},
{rebar_core,process_commands,2,[]},
{rebar,main,1,[]}]}}
make: *** [rel] Error 1
What should be the best way to fix this? I didnt get much info from google. My rebar configuration file is as below:
{ok, Path} = file:get_cwd(),
ConfigureOut = Path ++ "/../configure.out",
Conf = case file:consult(ConfigureOut) of
{ok, Terms} -> Terms;
E -> io:format("WARN: error ~p reading file: ~p - using default rel config~n", [E, ConfigureOut]), []
end,
BaseAppsToRun = [compiler,
lager,
kernel,
mnesia,
sasl,
ssl,
stdlib,
ejabberd,
inets,
syntax_tools,
p1_stringprep,
exml,
cowboy,
fusco,
folsom,
exometer,
xmerl,
amqp_client,
rabbit_common],
AppsToRunIn = BaseAppsToRun ++ proplists:get_value(apps_to_run, Conf, []),
AppsToRun = ordsets:to_list(ordsets:from_list(AppsToRunIn)),
BaseAppsToInclude = AppsToRun ++
[asn1,
crypto,
public_key,
goldrush,
runtime_tools,
p1_utils,
ranch,
cowlib,
bear,
mochijson2,
p1_cache_tab,
pa,
base16,
cuesport,
alarms,
idna,
recon,
setup,
xmerl,
amqp_client,
rabbit_common],
RemovedApps = [mysql,pgsql,redo,seestar,odbc],
AppsToIncludeIn = BaseAppsToInclude ++ proplists:get_value(apps_to_include, Conf, []),
AppsToInclude = ordsets:to_list(ordsets:from_list(AppsToIncludeIn)),
IncludeApps = lists:map(fun(App) -> {app, App, [{incl_cond, include}]} end, AppsToInclude),
[{sys, [
{lib_dirs, ["../apps", "../deps"]},
{incl_cond, exclude},
{rel, "mongooseim", "", [mongoose | AppsToRun]},
{rel, "start_clean", "", [kernel,stdlib]},
{boot_rel, "mongooseim"},
{profile, embedded},
{excl_archive_filters, [".*"]}, % do no archive built libs
{excl_sys_filters, ["^bin/.*",
"^erts.*/bin/(dialyzer|typer)"]},
{app, mongoose, [{incl_cond, include}, {lib_dir, ".."}]}
] ++ IncludeApps},
{target_dir, "mongooseim"},
{overlay_vars, "vars.config"},
{overlay, [{mkdir, "log/sasl"},
{copy, "files/erl", "\{\{erts_vsn\}\}/bin/erl"},
{copy, "files/nodetool", "\{\{erts_vsn\}\}/bin/nodetool"},
{copy, "files/mongooseim", "bin/mongooseim"},
{copy, "files/mongooseimctl", "bin/mongooseimctl"},
{copy, "files/app.config", "etc/app.config"},
{template, "files/vm.args", "etc/vm.args"},
{template, "files/ejabberd.cfg", "etc/ejabberd.cfg"},
{mkdir, "var"},
{mkdir, "var/log"}
]}
].
I have faced the same problem before. There are several ways to solve the problem.
use older version of rabbitmq common. common's 2.8.2 version doesn't contain mochijson2 module.
In the "reltool.config" file, try to exclude mochijson2 for rabbitmq common or from mochiweb. ( it need to read carefully release-related documents).
I am successfully using the rebar-friendly package of rabbitmq-erlang-client for a simple Hello World rebarized and OTP "compliant" app and things work fine on the dev environment. I am able to fire up an erl console and do my application:start(helloworld). and connect to the broker, open up a channel and communicate to queues.
However, then I proceed to do rebar generate and it builds up the release just fine, but when I try to fire up from the self contained release package then things suddenly explode.
I know rebar releases are known to be an obscure art, but I would like to know what are my options as far as deployment for an app using the rabbitmq-erlang-client.
Below you will find the output of the console on the crash:
=INFO REPORT==== 18-Dec-2012::16:41:35 ===
application: session_record
exited: {{{badmatch,
{error,
{'EXIT',
{undef,
[{amqp_connection_sup,start_link,
[{amqp_params_network,<<"guest">>,<<"guest">>,<<"/">>,
"127.0.0.1",5672,0,0,0,infinity,none,
[#Fun<amqp_auth_mechanisms.plain.3>,
#Fun<amqp_auth_mechanisms.amqplain.3>],
[],[]}],
[]},
{supervisor2,do_start_child_i,3,
[{file,"src/supervisor2.erl"},{line,391}]},
{supervisor2,handle_call,3,
[{file,"src/supervisor2.erl"},{line,413}]},
{gen_server,handle_msg,5,
[{file,"gen_server.erl"},{line,588}]},
{proc_lib,init_p_do_apply,3,
[{file,"proc_lib.erl"},{line,227}]}]}}}},
[{amqp_connection,start,1,
[{file,"src/amqp_connection.erl"},{line,164}]},
{hello_qp,start_link,0,[{file,"src/hello_qp.erl"},{line,10}]},
{session_record_sup,init,1,
[{file,"src/session_record_sup.erl"},{line,55}]},
{supervisor_bridge,init,1,
[{file,"supervisor_bridge.erl"},{line,79}]},
{gen_server,init_it,6,[{file,"gen_server.erl"},{line,304}]},
{proc_lib,init_p_do_apply,3,
[{file,"proc_lib.erl"},{line,227}]}]},
{session_record_app,start,[normal,[]]}}
type: permanent {"Kernel pid terminated",application_controller
EDIT: As requested in the comments.
reltool.config
{sys, [
{lib_dirs, ["..", "../deps"]},
{erts, [{mod_cond, derived}, {app_file, strip}]},
{app_file, strip},
{rel, "session_record", "0.1.0",
[
kernel,
stdlib,
sasl,
session_record
]},
{rel, "start_clean", "",
[
kernel,
stdlib
]},
{boot_rel, "session_record"},
{profile, embedded},
{incl_cond, derived},
{mod_cond, derived},
{excl_archive_filters, [".*"]}, %% Do not archive built libs
{excl_sys_filters, ["^bin/.*", "^erts.*/bin/(dialyzer|typer)",
"^erts.*/(doc|info|include|lib|man|src)"]},
{excl_app_filters, ["\.gitignore"]},
{app, session_record, [{mod_cond, app}, {incl_cond, include}, {lib_dir, ".."}]},
{app, hipe, [{incl_cond, exclude}]}
]}.
{target_dir, "session_record"}.
{overlay, [
{mkdir, "log/sasl"},
{copy, "files/erl", "\{\{erts_vsn\}\}/bin/erl"},
{copy, "files/nodetool", "\{\{erts_vsn\}\}/bin/nodetool"},
{copy, "files/session_record", "bin/session_record"},
{copy, "files/session_record.cmd", "bin/session_record.cmd"},
{copy, "files/start_erl.cmd", "bin/start_erl.cmd"},
{copy, "files/install_upgrade.escript", "bin/install_upgrade.escript"},
{copy, "files/sys.config", "releases/\{\{rel_vsn\}\}/sys.config"},
{copy, "files/vm.args", "releases/\{\{rel_vsn\}\}/vm.args"}
]}.
Try changing {mod_cond, derived} to {mod_cond, all}. That means that reltool will not try to be clever about which modules to take from the included applications. I suspect that your problem is that reltool didn't consider amqp_connection_sup to be necessary; you could confirm that by checking whether it's present in lib/amqp_client-0.8/ebin.
Answer given by #legoscia worked.
Here is sample, reltool.config
%% -*- mode: erlang -*-
%% ex: ft=erlang
{sys, [
{lib_dirs, ["..","../deps"]},
{erts, [{mod_cond, all}, {app_file, strip}]},
{app_file, strip},
{rel, "chat_grabber", "1",
[
kernel,
stdlib,
sasl,
couchbeam,
chat_grabber
]},
{rel, "start_clean", "",
[
kernel,
stdlib
]},
{boot_rel, "chat_grabber"},
{profile, embedded},
{incl_cond, derived},
{excl_archive_filters, [".*"]}, %% Do not archive built libs
{excl_sys_filters, ["^bin/(?!start_clean.boot)",
"^erts.*/bin/(dialyzer|typer)",
"^erts.*/(doc|info|include|lib|man|src)"]},
{excl_app_filters, ["\.gitignore"]},
{app,couchbeam,[{mod_cond,app},{incl_cond,include},{lib_dir, "../deps/"}]},
{app, chat_grabber, [{mod_cond, app}, {incl_cond, include}, {lib_dir, ".."}]}
]}.
{target_dir, "chat_grabber"}.
{overlay, [
{mkdir, "log/sasl"},
{copy, "files/erl", "\{\{erts_vsn\}\}/bin/erl"},
{copy, "files/nodetool", "releases/\{\{rel_vsn\}\}/nodetool"},
{copy, "chat_grabber/bin/start_clean.boot",
"\{\{erts_vsn\}\}/bin/start_clean.boot"},
{copy, "files/chat_grabber", "bin/chat_grabber"},
{copy, "files/chat_grabber.cmd", "bin/chat_grabber.cmd"},
{copy, "files/start_erl.cmd", "bin/start_erl.cmd"},
{copy, "files/install_upgrade.escript", "bin/install_upgrade.escript"},
{copy, "files/sys.config", "releases/\{\{rel_vsn\}\}/sys.config"},
{copy, "files/vm.args", "releases/\{\{rel_vsn\}\}/vm.args"}
]}.