erlware / relx

Sane, simple release creation for Erlang
http://erlware.github.io/relx
Apache License 2.0
697 stars 232 forks source link

Order of dependencies #511

Closed silviucpp closed 6 years ago

silviucpp commented 8 years ago

Hello,

I already read all threads on this subject but I can't understand how I can fix my issue.

I migrated from rebar to rebar3 and seems my app is not starting properly because of the deps order.

In my_app.src I have the apps like:

{applications, [
        kernel,
        stdlib,
        lager,
        folsom,
        hackney,
        beanstalkd_consumer
    ]},
{included_applications, [graylog_lager, jsone]},

In relx:

{release, { my_app, "1.0" }, [my_app]},

The my_app.rel loks like:

{release,{"my_app","1.0"},
         {erts,"8.0"},
         [{stdlib,"3.0"},
          {kernel,"5.0"},
          {poolboy,"1.5.1"},
          {lager,"3.2.1"},
          {ebeanstalkd,"1.1",load},
          {revolver,"1.3.0",load},
          {ratx,"1.0",load},
          {beanstalkd_consumer,"1.5"},
          {metrics,"1.0.1"},
          {ssl,"8.0"},
          {ssl_verify_fun,"1.1.0"},
          {certifi,"0.4.0"},
          {mimerl,"1.0.2"},
          {idna,"1.2.0"},
          {public_key,"1.2"},
          {crypto,"3.7"},
          {asn1,"4.0.3"},
          {hackney,"1.6.0"},
          {bear,"0.8.2"},
          {folsom,"0.8.2"},
          {jsone,"1.3.2"},
          {graylog_lager,"1.0.0"},
          {compiler,"7.0"},
          {syntax_tools,"2.0"},
          {goldrush,"0.1.8"},
          {my_app,"1.0"}]}. 

Problem is folsom is required before hackney to be started. It's used as a plugin to record the metrics and is not listed in hackeny .src file. Only in my app.config:

{hackney, [
        {mod_metrics, folsom}
    ]
}

Using reltool are ordered properly but with relx I have no idea how to do this.

Help is appreciated!

Silviu

ferd commented 8 years ago

If you move the folsom entry before the hackney entry in the release tuple of the relx config, that may be enough to have it start first.

silviucpp commented 8 years ago

Hello @ferd , Where exactly to move it ? in my_app.rel ? This one is generated by relx, not edited by me.

Silviu

tsloughter commented 8 years ago

@silviucpp just to be sure, you are using the current version of rebar3, correct, 3.3.1? There was a time that relx ordered deps itself instead of relying on systools, but now it should have the same order that reltool had because they both use systools for the ordering.

silviucpp commented 8 years ago

Hello, Yes I'm using rebar3 3.3.1. Silviu

lrascao commented 8 years ago

Where exactly to move it ? in my_app.rel ? This one is generated by relx, not edited by me.

i think Fred is referring to the relx tuple of your rebar.config,

{relx, [
   ...
   {release, [
     ...
    folsom,
    hackney
     ...
   ]}
   ...
]}.
silviucpp commented 8 years ago

Hmm,

Is this the way to do it ? Then becomes redundant to add them in both applications and relx release section.

In applications are already in the proper order. Something is strange because as I told with reltool is working fine and @tsloughter is telling that should be the same.

Silviu

tsloughter commented 8 years ago

@silviucpp can you post the my_app.rel that is generated for this when using rebar2/reltool?

silviucpp commented 8 years ago

Here it is :

%% rel generated at {2016,9,23} {20,2,49}
{release,{"my_app","1.0"},
         {erts,"8.0.2"},
         [{kernel,"5.0"},
          {stdlib,"3.0.1"},
          {syntax_tools,"2.0"},
          {compiler,"7.0.1"},
          {goldrush,"0.1.8"},
          {lager,"3.2.1"},
          {jsone,"1.3.2"},
          {graylog_lager,"1.0.0"},
          {bear,"0.8.2"},
          {folsom,"0.8.2"},
          {crypto,"3.7"},
          {asn1,"4.0.3"},
          {public_key,"1.2"},
          {ssl,"8.0"},
          {idna,"1.2.0"},
          {mimerl,"1.0.2"},
          {certifi,"0.4.0"},
          {ssl_verify_fun,"1.1.0"},
          {metrics,"1.0.1"},
          {hackney,"1.6.0"},
          {ratx,"1.0"},
          {revolver,"1.3.0"},
          {poolboy,"1.5.1"},
          {ebeanstalkd,"1.1"},
          {beanstalkd_consumer,"1.5"},
          {my_app,"1.0"},
          {common_test,"1.12.2",load},
          {debugger,"4.2",load},
          {et,"1.6",load},
          {hipe,"3.15.1",load},
          {inets,"6.3.1",load},
          {mnesia,"4.14",load},
          {observer,"2.2.1",load},
          {runtime_tools,"1.10",load},
          {sasl,"3.0",load},
          {snmp,"5.2.3",load},
          {ssh,"4.3.1",load},
          {tools,"2.8.5",load},
          {wx,"1.7",load},
          {xmerl,"1.3.11",load}]}.

Only one note: I run it on a different pc. If you want from the same we need to wait until monday . even if I know with rebar2 is working fine on both.

Silviu

tsloughter commented 8 years ago

Hm, same computer won't matter but same OTP could. I notice this is erts 8.0.2 and the last was 8.0? And this release is very different, it has a lot of other apps being loaded?

silviucpp commented 8 years ago

Hello,

I will check on Monday on the same pc and same otp :). I run it over the same project no idea why it included all other apps as time I don't have any other reference to them in any file.

Silviu

silviucpp commented 8 years ago

Hello @tsloughter,

I tested on the same machine and seems reltool include automatically the other apps (no idea why). File is identical with the one I sent before the only difference being the OTP version.

You can replicate this with any rebar.config looking like:

{
    deps, [
        {lager, ".*", {git, "https://github.com/basho/lager.git", {tag, "3.2.1"}}},
        {graylog_lager, ".*", {git, "https://github.com/silviucpp/graylog_lager.git", {tag, "v1.2"}}},
        {jsone, ".*", {git, "https://github.com/sile/jsone.git", {tag, "1.3.2"}}},
        {folsom, ".*", {git, "https://github.com/folsom-project/folsom", {tag, "0.8.2"}}},
        {hackney, ".*", {git, "https://github.com/benoitc/hackney.git", {tag, "1.6.0"}}},
        {beanstalkd_consumer, ".*",{git, "https://github.com/silviucpp/beanstalkd-consumer.git", {tag, "v1.5"}}}
    ]
}.

%for rebar2
{
    sub_dirs, ["rel"]
}.

{
    erl_opts, [
        debug_info,
        warnings_as_errors,
        warn_export_all,
        {parse_transform,lager_transform}
    ]
}.

And with an empty project where app.src looks like:

{application, my_app, [
    {description, "My app desciption"},
    {vsn, "1.0"},
    {registered, []},
    {applications, [
        kernel,
        stdlib,
        lager,
        folsom,
        hackney,
        beanstalkd_consumer
    ]},
    {included_applications, [graylog_lager, jsone]},
    {mod, {woow_push_app, []}},
    {env, []}
]}.

Using reltool folsom will be before hackney, using relx after.

Silviu

silviucpp commented 8 years ago

Hmm looking to the proper order and what relx generated I see that I need to reverse the order of the apps in my app.src. If I do this it's ok and are generated properly.

Doing this:

   {applications, [
        beanstalkd_consumer,
        hackney,
        folsom,
        lager,
        stdlib,
        kernel
    ]}

will generate:

{release,{"my_app","1.0"},
         {erts,"8.0"},
         [{stdlib,"3.0"},
          {kernel,"5.0"},
          {jsone,"1.3.2"},
          {graylog_lager,"1.0.0",load},
          {bear,"0.8.2"},
          {folsom,"0.8.2"},
          {metrics,"1.0.1"},
          {ssl,"8.0"},
          {ssl_verify_fun,"1.1.0"},
          {certifi,"0.4.0"},
          {mimerl,"1.0.2"},
          {idna,"1.2.0"},
          {public_key,"1.2"},
          {crypto,"3.7"},
          {asn1,"4.0.3"},
          {hackney,"1.6.0"},
          {poolboy,"1.5.1"},
          {lager,"3.2.1"},
          {ebeanstalkd,"1.1",load},
          {revolver,"1.3.0",load},
          {ratx,"1.0",load},
          {compiler,"7.0"},
          {syntax_tools,"2.0"},
          {goldrush,"0.1.8"},
          {beanstalkd_consumer,"1.5"},
          {my_app,"1.0"}]}. 

which seems the proper order for me. @tsloughter do you think is any lists:reverse somewhere in relx ?

Silviu

tsloughter commented 8 years ago

Hm, that could be :(

silviucpp commented 8 years ago

Hy @tsloughter , Until this bug is fixed do you see any other way to fix my problem ? :) any place where I can reverse the list before being read by relx ?

I don't want to reverse it in my app.src to keep it compatible with rebar and reltool

Silviu

silviucpp commented 8 years ago

Hy @tsloughter,

Do you consider this as being a bug ? Will help me to know in order to find a way to avoid this meanwhile.

Silviu

tsloughter commented 8 years ago

Yes, it is a bug.

tsloughter commented 8 years ago

I am not sure when I'll have time to dig in to find where it is getting reversed.

lrascao commented 8 years ago

I think i've found it, relx's dep graph isn't complete in this case since relx doesn't know that hackney depends on folsom, hackney should be declaring folsom as an included_application

tsloughter commented 8 years ago

No, it should not be an included_application that would break if another app wants to depend on folsom as well.

tsloughter commented 8 years ago

And the dep graph is handled by systools, so if reltool has enough context then relx does as well, they both use the same thing to sort apps.

lrascao commented 8 years ago

No, it should not be an included_application that would break if another app wants to depend on folsom as well.

right you are, the doc does say that:

An application can only be included by one other application.
silviucpp commented 8 years ago

Hackeny cannot include anyway folsom because this is optional. You might use exometer instead

Hackney offers the following metrics You can enable metrics collection by adding a mod_metrics entry to hackney's app config. Metrics are disabled by default. The module specified must have an API matching that of the hackney metrics module. To use folsom, specify {mod_metrics, folsom}, or if you want to use exometer, specify{mod_metrics, exometer} and ensure that folsom or exometer is in your code path and has been started.

Also the fact that the apps are reversed I think it's real as time if I provide the list reverse in the main app I can see that the proper order is generated as with reltool.

Silviu

lrascao commented 8 years ago

This seems related to #492, #493

silviucpp commented 8 years ago

Any update on this ?

Silviu

cmullaparthi commented 8 years ago

I logged this as an issue on rebar3 but was asked to log it here instead.

Current behaviour

As far as I understand how rebar3 works, it generates the order of applications in the .rel file by using the constraints specified in individual .app.src files, and the list of applications specified in the relx section of rebar.config ?

For one of the projects I'm working on, I cannot make it produce the correct order of application startup in the .rel file despite having the correct information in .app.src files.

Expected behaviour

I've written a small module to determine the order purely based on the contents of the application directive in a .app.src file and it gives me the correct output consistently. To use it, make sure it is in your code path for a project and use the command:

debug_relx:go().

It will find all the .app.src files under that directory and produce a list of applications in an order which satisfies the constraints in every .app.src or fail with an error message if it detects cyclical dependencies.

I find that the output of my test module is exactly the order I want whereas I cannot make sense of the ordering produce by rebar3. Can someone please explain how this works?

I've attached a zip file relx_bug.zip with a sample 'release' and apps generated using rebar3 new. The .app.src files have been modified to create a dependency between these apps. When generating a release using rebar3 release, the contents of the .rel file are:

{release,{"relx_bug","0.1.0"},
         {erts,"7.3"},
         [{app_4,"0.1.0"},
          {stdlib,"2.8"},
          {kernel,"4.2"},
          {relx_bug,"0.1.0"},
          {app_1,"0.1.0"},
          {app_3,"0.1.0"},
          {app_2,"0.1.0"},
          {sasl,"2.7"}]}. 

Whereas, the ordering generated by my test module is:

1> debug_relx:go(".").
Processing file: ./apps/app_2/src/app_2.app.src...
Processing file: ./apps/app_4/src/app_4.app.src...
Processing file: ./apps/relx_bug/src/relx_bug.app.src...
Processing file: ./apps/app_3/src/app_3.app.src...
Processing file: ./apps/app_1/src/app_1.app.src...
[kernel,stdlib,sasl,app_4,app_3,app_2,relx_bug,app_1]

Environment

$ rebar3 report
Rebar3 report
 version 3.3.1+build.3580.refcc7141b
 generated at 2016-10-10T15:05:06+00:00
=================
Please submit this along with your issue at https://github.com/erlang/rebar3/issues (and feel free to edit out private information, if any)
-----------------
Task: 
Entered as:

-----------------
Operating System: x86_64-unknown-linux-gnu
ERTS: Erlang/OTP 18 [erts-7.3] [source] [64-bit] [async-threads:0] [hipe] [kernel-poll:false]
Root Directory: $HOME/erlang/R18.3/lib/erlang
Library directory: $HOME/erlang/R18.3/lib/erlang/lib
-----------------
Loaded Applications:
bbmustache: 1.3.0
certifi: 0.4.0
cf: 0.2.1
common_test: 1.12
compiler: 6.0.3
crypto: 3.6.3
cth_readable: 1.2.3
dialyzer: 2.9
edoc: 0.7.18
erlware_commons: 0.21.0
eunit: 2.2.13
eunit_formatters: 0.3.1
getopt: 0.8.2
inets: 6.2
kernel: 4.2
providers: 1.6.0
public_key: 1.1.1
relx: 3.21.0
sasl: 2.7
snmp: 5.2.2
ssl_verify_fun: 1.1.1
stdlib: 2.8
syntax_tools: 1.7
tools: 2.8.3

-----------------
Escript path: $HOME/bin/rebar3
Providers:
  app_discovery as clean compile compile config cover ct cut deps dialyzer do docs edoc escriptize eunit help info install install_deps key list lock new owner path pkgs publish release relup report search shell state tar tree unlock update upgrade upgrade upgrade user version xref 
lrascao commented 8 years ago

@cmullaparthi despite being different, the order generated by relx is still correct, if i understood your dependency graph correctly (ignoring kernel, stdlib since they are always started):

maybe this example isn't capturing the problem you're actually having

cmullaparthi commented 8 years ago

Yes, you're right. Sorry about that. Let me see if I can translate from the real project I'm dealing with to an example.

tsloughter commented 8 years ago

@cmullaparthi important question here is is the result the reverse of what you expect?

cmullaparthi commented 8 years ago

@tsloughter Having looked at the above example closely, I agree with @lrascao that the output generated by relx is correct for the above example. But for my actual project, I keep specifying cowboy, ranch and cowlib as dependencies, and the generated .rel file has them starting after my actual app.

lrascao commented 8 years ago

i think this test (to be added to rlx_depsolver_tests) captures the problem we're having, have app2, app3, app4, app5 all depend on app1, it fails because the returned order of the dependencies is the inverse of what is expected

fourth_test() ->
    Pkg1Deps = [app2, app3, app4, app5],

    Dom0 = rlx_depsolver:add_packages(rlx_depsolver:new_graph(), [{app1, [{"0.1.0", Pkg1Deps}]},
                                                                  {app2, [{"0.2.0", []}]},
                                                                  {app3, [{"0.3.0", []}]},
                                                                  {app4, [{"0.4.0", []}]},
                                                                  {app5, [{"0.5.0", []}]}]),
    ?assertMatch({ok, [{app2,{{0,2,0},{[],[]}}},
                       {app3,{{0,3,0},{[],[]}}},
                       {app4,{{0,4,0},{[],[]}}},
                       {app5,{{0,5,0},{[],[]}}},
                       {app1,{{0,1,0},{[],[]}}}]},
                 rlx_depsolver:solve(Dom0, [app1])).
lrascao commented 7 years ago

@cmullaparthi @silviucpp could you please try out #530 and check if this fixes your issues?

silviucpp commented 7 years ago

Any idea how I can test this using rebar3 ? I mean how I can make rebar3 to use this version of relx

Silviu

lrascao commented 7 years ago

sure, you need to:

silviucpp commented 7 years ago

So what I did:

git clone https://github.com/lrascao/rebar3
changed in rebar.config th relx line with {relx, ".*", {git, "https://github.com/erlware/relx.git", "2722180a709ec4303d4f6fce8ed6dd5ea86d7d07"}},
./bootstrap

After I replaced the relx bin in my project I compiled again. I see the same order nothing changed. I hope I didn't done any mistake in making rebar to use the proper relx version

Silviu

lrascao commented 7 years ago

please checkout the custom_relx branch i mentioned, the relx sha1 should be 2722180a

lrascao commented 7 years ago

ah sorry, you have the correct sha1, try the following: git reset --hard origin/custom_relx rm -rf _build ./bootstrap

silviucpp commented 7 years ago

Woow ! I realised I was a moron ! I looked in a wrong file! Seems working nice this fix! Generates proper order !

Silviu

lrascao commented 7 years ago

ping @tsloughter, i believe you mentioned that the topo sort caused some issues in the past, do you remember what were they?

tsloughter commented 7 years ago

That could mean a lot of different things depending on context :). But ignoring old (pre-R12) systools bugs and relx's old sort we haven't used in a while there should be no issues if dependencies are properly specified.

lrascao commented 7 years ago

ok, i'll go ahead and get this merged then

lrascao commented 7 years ago

closing as #530 has been merged

silviucpp commented 7 years ago

Any idea when this will be part of rebar3 ?

Silviu

lrascao commented 7 years ago

Probably in the next release, i guess you can carry around the rebar3 binary in your project until then

leoliu commented 6 years ago

I am hit by this bug with rebar 3.5.0+build.4035.refd4c529a4 on Erlang/OTP 20 Erts 9.3. is this bug actually fixed?

tsloughter commented 6 years ago

@leoliu what are you seeing?

leoliu commented 6 years ago

This is the relx section in rebar.config:

{relx, [{release, {koala, "0.1.0"},
         [{runtime_tools, load}, {recon, load}, sasl,
          compiler, {yaws, load}, koala]},

        {sys_config, "./config/devel.sys.config"},
        {vm_args, "./config/devel.vm.args"},

        {dev_mode, true},
        {include_erts, false},
        {extended_start_script, true}]}.

{profiles,
 [{prod, [{relx, [{dev_mode, false},
                  {include_src, false},
                  {include_erts, false},
                  {sys_config, "./config/prod.sys.config"},
                  {vm_args, "./config/prod.vm.args"},
                  {lib_dirs, ["./yawslib"]}]}]}
 ]}.

koala.app.src looks like this:

{application, koala,
 [{description, "koala app"},
  {vsn, "0.1.0"},
  {registered, []},
  {mod, {koala_app, []}},
  {applications,
   [kernel,
    stdlib,
    mnesia,
    sway,
    jsx,
    aws
   ]},
  {env,[]},
  {modules, []}
 ]}.

sway has optional dep on mnesia (i.e. mnesia is not in sway.app file) which koala specifies and places before sway. koala is the only app that specifies mnesia. However the RELEASES (from rebar3 as prod release) file looks like this where mnesia is placed after sway.

%% coding: utf-8
[{release,"koala","0.1.0","9.3",
          [{kernel,"5.4.3","./lib/kernel-5.4.3"},
           {stdlib,"3.4.5","./lib/stdlib-3.4.5"},
           {runtime_tools,"1.12.5","./lib/runtime_tools-1.12.5"},
           {recon,"2.3.4","./lib/recon-2.3.4"},
           {sasl,"3.1.1","./lib/sasl-3.1.1"},
           {compiler,"7.1.5","./lib/compiler-7.1.5"},
           {yaws,"2.0.5","./lib/yaws-2.0.5"},
           {crypto,"4.2.1","./lib/crypto-4.2.1"},
           {asn1,"5.0.5","./lib/asn1-5.0.5"},
           {public_key,"1.5.2","./lib/public_key-1.5.2"},
           {ssl,"8.2.5","./lib/ssl-8.2.5"},
           {ranch,"1.5.0","./lib/ranch-1.5.0"},
           {cowlib,"2.2.1","./lib/cowlib-2.2.1"},
           {gun,"1.0.0-pre.5","./lib/gun-1.0.0-pre.5"},
           {jsx,"2.9.0","./lib/jsx-2.9.0"},
           {aws,"0.1.0","./lib/aws-0.1.0"},
           {inets,"6.5","./lib/inets-6.5"},
           {sway,"0.1.0","./lib/sway-0.1.0"},
           {mnesia,"4.15.3","./lib/mnesia-4.15.3"},
           {koala,"0.1.0","./lib/koala-0.1.0"}],
          permanent}].
leoliu commented 6 years ago

Let me know if there is anything unclear ;)

jadeallenx commented 6 years ago

hashtag me too

Hit this ordering problem too. Are there any options which are better than enumerating every single app in the order I want them? Because this particular app has about 50 dependencies and it would suck a lot.

nalundgaard commented 6 years ago

I have also come up against a very similar problem to what @leoliu described above. I've got a dependent application (call it, dep1) that relies on configurable "backend" apps (b1, b2, b3). Because I don't always want all of the backends to be started, they are not OTP application dependencies of dep1. In my top-level application's OTP dependencies, I have something like:

{application, myapp, [
    {description, "myapp"},
    {applications, 
     [
      kernel,
      stdlib,
      % ... many apps ....
      b1,
      app1
      % , ... many more apps ... 
    ]},
    {mod, {myapp, []}},
    {env,[]}
]}.

However, whichever "backend" is configured must start before dep1. When I make a release with rebar3 release, I end up with app1 booting prior to b1, even with something like this in my rebar.config:

{relx, [
    {release, {"myapp", semver}, [b1, myapp]},
    {dev_mode, false},
    {include_erts, true},
    {extended_start_script, true}
]}.

As a result, the application won't boot; app1 crashes when making calls to b1 before it's booted.

tsloughter commented 6 years ago

If someone can give me a reproduceable project I have some tweaks I can try.

Trying by just adding unrelated apps to the list of applications doesn't have a problem, they are booted in the order they are found in the applications list of the relx config.

@nalundgaard and to be clear, b1 does not depend on app1 either, right?