Skip to content

Commit

Permalink
Merge pull request #17484 from essobedo/maven-build-thread-safe
Browse files Browse the repository at this point in the history
Make the maven build task compatible with parallel builds
  • Loading branch information
aloubyansky authored May 28, 2021
2 parents 850b263 + c44cdc8 commit 966f3c3
Show file tree
Hide file tree
Showing 19 changed files with 482 additions and 24 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -348,10 +348,13 @@ private BuildResult runAugment(boolean firstRun, Set<String> changedResources,
Class<? extends BuildItem>... finalOutputs) {
ClassLoader old = Thread.currentThread().getContextClassLoader();
try {
Thread.currentThread().setContextClassLoader(curatedApplication.getAugmentClassLoader());
ProfileManager.setLaunchMode(launchMode);

QuarkusClassLoader classLoader = curatedApplication.getAugmentClassLoader();
Thread.currentThread().setContextClassLoader(classLoader);
ProfileManager.setLaunchMode(launchMode);
ProfileManager.setRuntimeDefaultProfile(
Optional.ofNullable(quarkusBootstrap.getBuildSystemProperties())
.map(properties -> properties.getProperty(ProfileManager.QUARKUS_PROFILE_PROP))
.orElse(null));

QuarkusAugmentor.Builder builder = QuarkusAugmentor.builder()
.setRoot(quarkusBootstrap.getApplicationRoot())
Expand Down Expand Up @@ -398,6 +401,7 @@ private BuildResult runAugment(boolean firstRun, Set<String> changedResources,
throw new RuntimeException(e);
}
} finally {
ProfileManager.setRuntimeDefaultProfile(null);
Thread.currentThread().setContextClassLoader(old);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,12 @@
*
* The profile is resolved in the following way:
*
* - The quarkus.profile system property
* - The QUARKUS_PROFILE environment entry
* - The default runtime profile provided during build
* - The default property for the launch mode
* <ul>
* <li>The quarkus.profile system property</li>
* <li>The QUARKUS_PROFILE environment entry</li>
* <li>The default runtime profile provided during build</li>
* <li>The default property for the launch mode</li>
* </ul>
*
*/
public class ProfileManager {
Expand All @@ -23,7 +25,7 @@ public class ProfileManager {
private static final String BACKWARD_COMPATIBLE_QUARKUS_PROFILE_PROP = "quarkus-profile";

private static volatile LaunchMode launchMode = LaunchMode.NORMAL;
private static String runtimeDefaultProfile = null;
private static volatile String runtimeDefaultProfile;

public static void setLaunchMode(LaunchMode mode) {
launchMode = mode;
Expand All @@ -37,7 +39,7 @@ public static void setRuntimeDefaultProfile(final String profile) {
runtimeDefaultProfile = profile;
}

//NOTE: changes made here must be replicated in BootstrapProfileManager
//NOTE: changes made here must be replicated in BootstrapProfile
public static String getActiveProfile() {
if (launchMode == LaunchMode.TEST) {
String profile = System.getProperty(QUARKUS_TEST_PROFILE_PROP);
Expand Down
20 changes: 9 additions & 11 deletions devtools/maven/src/main/java/io/quarkus/maven/BuildMojo.java
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,11 @@
import io.quarkus.bootstrap.app.AugmentResult;
import io.quarkus.bootstrap.app.CuratedApplication;
import io.quarkus.bootstrap.util.IoUtils;
import io.quarkus.runtime.configuration.ProfileManager;

/**
* Builds the Quarkus application.
*/
@Mojo(name = "build", defaultPhase = LifecyclePhase.PACKAGE, requiresDependencyResolution = ResolutionScope.COMPILE_PLUS_RUNTIME)
@Mojo(name = "build", defaultPhase = LifecyclePhase.PACKAGE, requiresDependencyResolution = ResolutionScope.COMPILE_PLUS_RUNTIME, threadSafe = true)
public class BuildMojo extends QuarkusBootstrapMojo {

private static final String PACKAGE_TYPE_PROP = "quarkus.package.type";
Expand Down Expand Up @@ -118,15 +117,14 @@ && isNativeProfileEnabled(mavenProject())) {
System.setProperty(PACKAGE_TYPE_PROP, packageType);
propertiesToClear.add(PACKAGE_TYPE_PROP);
}
// Set the build profile based on the value of the project property ProfileManager.QUARKUS_PROFILE_PROP
// if and only if it has not already been set using the corresponding system property
// or environment variable.
final Object profile = mavenProject().getProperties().get(ProfileManager.QUARKUS_PROFILE_PROP);

if (profile != null && System.getProperty(ProfileManager.QUARKUS_PROFILE_PROP) == null
&& System.getenv(ProfileManager.QUARKUS_PROFILE_ENV) == null) {
System.setProperty(ProfileManager.QUARKUS_PROFILE_PROP, profile.toString());
propertiesToClear.add(ProfileManager.QUARKUS_PROFILE_PROP);
if (!propertiesToClear.isEmpty() && mavenSession().getRequest().getDegreeOfConcurrency() > 1) {
getLog().warn("*****************************************************************");
getLog().warn("* Your build is requesting parallel execution, but the project *");
getLog().warn("* relies on System properties at build time which could cause *");
getLog().warn("* race condition issues thus unpredictable build results. *");
getLog().warn("* Please avoid using System properties or avoid enabling *");
getLog().warn("* parallel execution *");
getLog().warn("*****************************************************************");
}
try (CuratedApplication curatedApplication = bootstrapApplication()) {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,6 @@ public static String getActiveProfile(QuarkusBootstrap.Mode mode) {
case REMOTE_DEV_CLIENT:
case PROD:
return PROD;
case TEST:
return TEST;
default:
throw new RuntimeException("unknown mode:" + mode);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -116,17 +116,32 @@ void testMultiBuildMode() throws MavenInvocationException, InterruptedException,
}

@Test
public void testModulesInProfiles()
void testModulesInProfiles()
throws MavenInvocationException, IOException, InterruptedException {
testDir = initProject("projects/modules-in-profiles");
build("-Dquarkus.bootstrap.effective-model-builder");
}

@Test
void testMultiBuildModeLaunchedInParallel() throws MavenInvocationException, InterruptedException, IOException {
testDir = initProject("projects/multi-build-mode-parallel");
build(true);

launch(TestContext.FAST_NO_PREFIX, new File(testDir, "module-1"), "foo-1-", "Hello foo 1");
launch(TestContext.FAST_NO_PREFIX, new File(testDir, "module-1"), "bar-1-", "Hello bar 1");
launch(TestContext.FAST_NO_PREFIX, new File(testDir, "module-2"), "foo-2-", "Hello foo 2");
launch(TestContext.FAST_NO_PREFIX, new File(testDir, "module-2"), "bar-2-", "Hello bar 2");
}

private void launch() throws IOException {
launch(TestContext.FAST_NO_PREFIX, "", "hello, from foo");
}

private void launch(TestContext context, String outputPrefix, String expectedMessage) throws IOException {
launch(context, testDir, outputPrefix, expectedMessage);
}

private void launch(TestContext context, File testDir, String outputPrefix, String expectedMessage) throws IOException {
File output = new File(testDir, String.format("target/%s%soutput.log", context.prefix, outputPrefix));
output.createNewFile();
Process process = JarRunnerIT
Expand All @@ -142,8 +157,12 @@ private void launch(TestContext context, String outputPrefix, String expectedMes
}

private void build(String... arg) throws MavenInvocationException, InterruptedException, IOException {
build(false, arg);
}

private void build(boolean parallel, String... arg) throws MavenInvocationException, InterruptedException, IOException {
assertThat(testDir).isDirectory();
running = new RunningInvoker(testDir, false);
running = new RunningInvoker(testDir, false, parallel);

final List<String> args = new ArrayList<>(2);
args.add("package");
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
<?xml version="1.0"?>
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<parent>
<groupId>org.multi-build-mode-parallel</groupId>
<artifactId>parent</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>module-1</artifactId>
<properties>
<maven.compiler.source>11</maven.compiler.source>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.target>11</maven.compiler.target>
</properties>
<build>
<plugins>
<plugin>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-maven-plugin</artifactId>
<version>${quarkus-plugin.version}</version>
<extensions>true</extensions>
<executions>
<execution>
<id>foo-1</id>
<goals>
<goal>build</goal>
</goals>
<configuration>
<properties>
<quarkus.profile>foo-1</quarkus.profile>
<quarkus.package.output-directory>foo-1-quarkus-app</quarkus.package.output-directory>
</properties>
</configuration>
</execution>
<execution>
<id>bar-1</id>
<goals>
<goal>build</goal>
</goals>
<configuration>
<properties>
<quarkus.profile>bar-1</quarkus.profile>
<quarkus.package.output-directory>bar-1-quarkus-app</quarkus.package.output-directory>
</properties>
</configuration>
</execution>
</executions>
</plugin>

<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>${surefire-plugin.version}</version>
<executions>
<execution>
<id>test-foo</id>
<goals>
<goal>test</goal>
</goals>
<configuration>
<groups>foo</groups>
<excludedGroups>others</excludedGroups>
<skip>${maven.test.skip}</skip>
<systemPropertyVariables>
<quarkus.test.profile>foo-1</quarkus.test.profile>
<java.util.logging.manager>org.jboss.logmanager.LogManager</java.util.logging.manager>
<maven.home>${maven.home}</maven.home>
</systemPropertyVariables>
</configuration>
</execution>
<execution>
<id>test-bar</id>
<goals>
<goal>test</goal>
</goals>
<configuration>
<groups>bar</groups>
<excludedGroups>others</excludedGroups>
<skip>${maven.test.skip}</skip>
<systemPropertyVariables>
<quarkus.test.profile>bar-1</quarkus.test.profile>
<java.util.logging.manager>org.jboss.logmanager.LogManager</java.util.logging.manager>
<maven.home>${maven.home}</maven.home>
</systemPropertyVariables>
</configuration>
</execution>
</executions>
<configuration>
<excludedGroups>foo,bar</excludedGroups>
</configuration>
</plugin>

</plugins>
</build>
</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package org.acme;

import io.quarkus.arc.profile.IfBuildProfile;

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;

@IfBuildProfile("bar-1")
@Path("/hello")
public class HelloResourceBar {

@GET
@Produces(MediaType.TEXT_PLAIN)
public String hello() {
return "Hello bar 1";
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package org.acme;

import io.quarkus.arc.profile.IfBuildProfile;

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;

@IfBuildProfile("foo-1")
@Path("/hello")
public class HelloResourceFoo {

@GET
@Produces(MediaType.TEXT_PLAIN)
public String hello() {
return "Hello foo 1";
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package org.acme;

import io.quarkus.test.junit.QuarkusTest;
import org.junit.jupiter.api.Tag;
import org.junit.jupiter.api.Test;

import static io.restassured.RestAssured.given;
import static org.hamcrest.CoreMatchers.is;

@Tag("bar")
@QuarkusTest
public class HelloResourceBarTest {
@Test
void testHelloEndpoint() throws Exception {
for (int i = 0; i < 5; i++) {
if (i > 0) {
Thread.sleep(1_000L); // Make it wait to cause build conflicts
}
given()
.when().get("/hello")
.then()
.statusCode(200)
.body(is("Hello bar 1"));

}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package org.acme;

import io.quarkus.test.junit.QuarkusTest;
import org.junit.jupiter.api.Tag;
import org.junit.jupiter.api.Test;

import static io.restassured.RestAssured.given;
import static org.hamcrest.CoreMatchers.is;

@Tag("foo")
@QuarkusTest
public class HelloResourceFooTest {
@Test
void testHelloEndpoint() throws Exception {
for (int i = 0; i < 5; i++) {
if (i > 0) {
Thread.sleep(1_000L); // Make it wait to cause build conflicts
}
given()
.when().get("/hello")
.then()
.statusCode(200)
.body(is("Hello foo 1"));
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
quarkus.http.test-port=0
Loading

0 comments on commit 966f3c3

Please sign in to comment.