[ 
https://issues.apache.org/jira/browse/MNG-8096?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=17837139#comment-17837139
 ] 

Joseph Leonard commented on MNG-8096:
-------------------------------------

Note that this bug has been discussed in the mailing list here: 
https://lists.apache.org/list?us...@maven.apache.org:2024-2

> Inconsistent dependency resolution behaviour for concurrent multi-module 
> build can cause failures
> -------------------------------------------------------------------------------------------------
>
>                 Key: MNG-8096
>                 URL: https://issues.apache.org/jira/browse/MNG-8096
>             Project: Maven
>          Issue Type: Bug
>          Components: Core
>    Affects Versions: 3.8.2, 3.9.6
>            Reporter: Joseph Leonard
>            Priority: Major
>
> h2. tl;dr
> Maven can resolve dependencies either from:
>  * an external repo
>  * a class directory of a module being built within the reactor
>  * a packaged jar of a module being built within the reactor
> If you run a concurrent multi-module build it is possible to get a race 
> condition whereby the build of module _Foo_ may resolve module _Bar_ from 
> either of the three resolution {_}channels{_}. This inconsistency can result 
> in the Maven _war_ plugin sometimes failing to build a functional war file. I 
> would expect a consistent resolution would always take place.
> h2. Full details
> h4. Scenario
> Consider you have a repo with the following structure:
> {noformat}
>                        App
>                      /     \
>                     /       \
>        (compile scope)      (test scope)
>                   /           \
>                 \/_           _\/
>              ModuleA      TestSupportModule1
>                 /
>                /
>     (compile scope)
>              /
>            \/_ 
>         ModuleB
>            /
>           /
>     (test scope)
>         /
>       \/_   
> TestSupportModule2
> {noformat}
> If you were to make a src code change to the following test support modules:
>  * TestSupportModule1
>  * TestSupportModule2
> Then the minimum number of modules we need to build to verify the change set 
> is OK is:
>  * TestSupportModule1
>  * TestSupportModule2
>  * ModuleB
>  * App
> i.e. there is no requirement to build ModuleA because we know that none of 
> the src code changes could impact the classpaths used in its maven build.
> We know that despite 'App' depending (transitively) on ModuleB there is no 
> need for the 'App' build to wait for ModuleB to complete its build because 
> the src code change to TestSupportModule2 will not impact any of the 
> classpaths used in the App maven build. Therefore to get the most efficient 
> build possible we ideally would invoke Maven to run with 2 threads and with 
> instruction to build *two distinct* 'dependency graphs':
>  * TestSupportModule1 followed by ModuleB
>  * TestSupportModule1 followed by App
> The following Maven command achieves exactly what we want because the reactor 
> build order is based only on the *direct* (i.e. non-transitive) dependencies 
> of the modules provided to the reactor in the build command. Therefore the 
> absence of ModuleA results in two distinct 'dependency graphs':
> {noformat}
> mvn clean verify -pl TestSupportModule1,TestSupportModule2,ModuleB,App -T 2
> {noformat}
> Note: In reality the code base I maintain has a very large monobuild with 
> 100s of modules and this type of build optimisation makes a significant 
> difference to the speed of our monobuild (we use 
> [https://github.com/gitflow-incremental-builder/gitflow-incremental-builder] 
> to automate the logic of determining which modules to include in the reactor 
> based on our change set).
> h4. Issue
> We have encountered an issue in the above scenario because the 'App' build 
> has a race condition with the ModuleB build which will result in one of the 
> following three outcomes:
>  * If the 'App' build starts before the ModuleB build has compiled its src 
> classes then the 'App' build will resolve ModuleB from the external repo 
> (i.e. equivalent to ModuleB not being in the reactor at all)
>  * If the 'App' build starts after ModuleB has compiled its src classes but 
> before it has packaged these classes into a jar then the 'App' build will 
> resolve ModuleB's {{target/classes}} directory
>  * If the 'App' build starts after ModuleB has packaged its jar file then the 
> 'App' build will resolve ModuleB's {{target/ModuleB.jar}} file.
> In many scenarios this dependency resolution inconsistency doesn't represent 
> a challenge. However, it does cause an issue in our case because the 'App' 
> POM has its Maven {{packaging}} stanza configured to {{war}} and in the 
> scenario where ModuleB's {{target/classes}} directory is resolved by the 
> 'App' then this results in the resultant 'App' war file being packaged with a 
> completely empty ModuleB.jar file.
> h4. Proposed solution
> Ideally we would like the Maven reactor to retain isolation between the *two 
> distinct* 'dependency graphs' it constructs at _instantiation_ throughout the 
> entire Maven build. This would mean, in the simple example above, that the 
> 'App' would *always* resolves ModuleB from the external repo (regardless of 
> whether the reactor has built ModuleB or not in a _separate_ 'dependency 
> graph' in the reactor).



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

Reply via email to