From 1eb8b2d80673abe76b9cced7a1cf491872d22748 Mon Sep 17 00:00:00 2001 From: Falko Modler Date: Thu, 10 Aug 2023 00:05:57 +0200 Subject: [PATCH] Lock jib execution to avoid OverlappingFileLockException in parallel builds --- .../image/jib/deployment/JibProcessor.java | 31 +++++++++++++++++-- 1 file changed, 28 insertions(+), 3 deletions(-) diff --git a/extensions/container-image/container-image-jib/deployment/src/main/java/io/quarkus/container/image/jib/deployment/JibProcessor.java b/extensions/container-image/container-image-jib/deployment/src/main/java/io/quarkus/container/image/jib/deployment/JibProcessor.java index e406fed36f2ea..2d79781a403c1 100644 --- a/extensions/container-image/container-image-jib/deployment/src/main/java/io/quarkus/container/image/jib/deployment/JibProcessor.java +++ b/extensions/container-image/container-image-jib/deployment/src/main/java/io/quarkus/container/image/jib/deployment/JibProcessor.java @@ -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; @@ -26,6 +25,7 @@ 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; @@ -33,6 +33,7 @@ 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; @@ -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; @@ -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(), @@ -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()); } @@ -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());