Skip to content

Commit

Permalink
Merge pull request #35308 from famod/jib-parallel
Browse files Browse the repository at this point in the history
Lock jib execution to avoid OverlappingFileLockException in parallel builds
  • Loading branch information
aloubyansky authored Aug 14, 2023
2 parents 8009695 + 1eb8b2d commit 42cd3ea
Showing 1 changed file with 28 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
import static io.quarkus.container.image.deployment.util.EnablementUtil.buildContainerImageNeeded;
import static io.quarkus.container.image.deployment.util.EnablementUtil.pushContainerImageNeeded;
import static io.quarkus.container.util.PathsUtil.findMainSourcesRoot;
import static io.quarkus.deployment.pkg.PackageConfig.MUTABLE_JAR;

import java.io.IOException;
import java.io.UncheckedIOException;
Expand All @@ -26,13 +25,15 @@
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.ExecutionException;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import org.eclipse.microprofile.config.ConfigProvider;
import org.jboss.logging.Logger;

import com.google.cloud.tools.jib.api.CacheDirectoryCreationException;
import com.google.cloud.tools.jib.api.Containerizer;
import com.google.cloud.tools.jib.api.DockerDaemonImage;
import com.google.cloud.tools.jib.api.ImageReference;
Expand All @@ -42,6 +43,7 @@
import com.google.cloud.tools.jib.api.JibContainer;
import com.google.cloud.tools.jib.api.JibContainerBuilder;
import com.google.cloud.tools.jib.api.LogEvent;
import com.google.cloud.tools.jib.api.RegistryException;
import com.google.cloud.tools.jib.api.RegistryImage;
import com.google.cloud.tools.jib.api.buildplan.AbsoluteUnixPath;
import com.google.cloud.tools.jib.api.buildplan.FileEntriesLayer;
Expand Down Expand Up @@ -249,7 +251,7 @@ private JibContainer containerize(ContainerImageConfig containerImageConfig,
previousContextStorageSysProp = System.setProperty(OPENTELEMETRY_CONTEXT_CONTEXT_STORAGE_PROVIDER_SYS_PROP,
"default");

JibContainer container = jibContainerBuilder.containerize(containerizer);
JibContainer container = containerizeUnderLock(jibContainerBuilder, containerizer);
log.infof("%s container image %s (%s)\n",
containerImageConfig.isPushExplicitlyEnabled() ? "Pushed" : "Created",
container.getTargetImage(),
Expand Down Expand Up @@ -300,7 +302,7 @@ private Containerizer createContainerizer(ContainerImageConfig containerImageCon
}
containerizer.setToolName("Quarkus");
containerizer.setToolVersion(Version.getVersion());
containerizer.addEventHandler(LogEvent.class, (e) -> {
containerizer.addEventHandler(LogEvent.class, e -> {
if (!e.getMessage().isEmpty()) {
log.log(toJBossLoggingLevel(e.getLevel()), e.getMessage());
}
Expand All @@ -311,6 +313,29 @@ private Containerizer createContainerizer(ContainerImageConfig containerImageCon
return containerizer;
}

/**
* Wraps the containerize invocation in a synchronized block to avoid OverlappingFileLockException when running parallel jib
* builds (e.g. mvn -T2 ...).
* Each build thread uses its own augmentation CL (which is why the OverlappingFileLockException prevention in jib doesn't
* work here), so the lock object
* has to be loaded via the parent classloader so that all build threads lock the same object.
* QuarkusAugmentor was chosen semi-randomly (note: quarkus-core-deployment is visible to that parent CL, this jib extension
* is not!).
*/
private JibContainer containerizeUnderLock(JibContainerBuilder jibContainerBuilder, Containerizer containerizer)
throws InterruptedException, RegistryException, IOException, CacheDirectoryCreationException, ExecutionException {
Class<?> lockObj = getClass();
ClassLoader parentCL = getClass().getClassLoader().getParent();
try {
lockObj = parentCL.loadClass("io.quarkus.deployment.QuarkusAugmentor");
} catch (ClassNotFoundException e) {
log.warnf("Could not load io.quarkus.deployment.QuarkusAugmentor with parent classloader: %s", parentCL);
}
synchronized (lockObj) {
return jibContainerBuilder.containerize(containerizer);
}
}

private void writeOutputFiles(JibContainer jibContainer, ContainerImageJibConfig jibConfig,
OutputTargetBuildItem outputTarget) {
doWriteOutputFile(outputTarget, Paths.get(jibConfig.imageDigestFile), jibContainer.getDigest().toString());
Expand Down

0 comments on commit 42cd3ea

Please sign in to comment.