Skip to content

Commit 0df005b

Browse files
committed
fix: reduce concurrent PWA icons generation tasks
Submitting multiple asynchronous jobs to generate PWA icons at build time can cause OutOfMemory errors with Gradle. This change introduces a fixed thread pool executor so that fewer icon generations are processed concurrently, allowing the JVM to clean up memory for already generated images. Fixes #20842
1 parent f1e7d30 commit 0df005b

2 files changed

Lines changed: 19 additions & 7 deletions

File tree

flow-server/src/main/java/com/vaadin/flow/server/frontend/NodeTasks.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import java.nio.charset.StandardCharsets;
2323
import java.nio.file.Files;
2424
import java.nio.file.Path;
25+
import java.time.Duration;
2526
import java.util.ArrayList;
2627
import java.util.Arrays;
2728
import java.util.Collections;
@@ -340,8 +341,14 @@ public void execute() throws ExecutionFailedException {
340341
sortCommands(commands);
341342
GeneratedFilesSupport generatedFilesSupport = new GeneratedFilesSupport();
342343
for (FallibleCommand command : commands) {
344+
long startTime = System.nanoTime();
343345
command.setGeneratedFileSupport(generatedFilesSupport);
344346
command.execute();
347+
Duration durationInNs = Duration
348+
.ofNanos(System.nanoTime() - startTime);
349+
getLogger().debug("Task [ {} ] completed in {} ms",
350+
command.getClass().getSimpleName(),
351+
durationInNs.toMillis());
345352
}
346353
} finally {
347354
releaseLock();

flow-server/src/main/java/com/vaadin/flow/server/frontend/TaskGeneratePWAIcons.java

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,20 +17,20 @@
1717
package com.vaadin.flow.server.frontend;
1818

1919
import javax.imageio.ImageIO;
20-
2120
import java.awt.image.BufferedImage;
2221
import java.io.File;
2322
import java.io.IOException;
2423
import java.io.InputStream;
2524
import java.io.OutputStream;
2625
import java.io.UncheckedIOException;
2726
import java.net.URL;
28-
import java.net.URLConnection;
2927
import java.nio.file.Files;
3028
import java.nio.file.Path;
3129
import java.util.concurrent.CancellationException;
3230
import java.util.concurrent.CompletableFuture;
3331
import java.util.concurrent.CompletionException;
32+
import java.util.concurrent.ExecutorService;
33+
import java.util.concurrent.Executors;
3434

3535
import org.slf4j.Logger;
3636
import org.slf4j.LoggerFactory;
@@ -92,11 +92,13 @@ public void execute() throws ExecutionFailedException {
9292
BufferedImage baseImage = loadBaseImage(iconURL);
9393
createGeneratedIconsFolder();
9494

95+
ExecutorService executor = Executors.newFixedThreadPool(4);
9596
CompletableFuture<?>[] iconsGenerators = PwaRegistry
9697
.getIconTemplates(pwaConfiguration.getIconPath()).stream()
9798
.map(icon -> new InternalPwaIcon(icon, baseImage))
98-
.map(this::generateIcon).toArray(CompletableFuture[]::new);
99-
99+
.map(this::generateIcon)
100+
.map(task -> CompletableFuture.runAsync(task, executor))
101+
.toArray(CompletableFuture[]::new);
100102
try {
101103
CompletableFuture.allOf(iconsGenerators).join();
102104
} catch (CompletionException ex) {
@@ -111,6 +113,8 @@ public void execute() throws ExecutionFailedException {
111113
} catch (CancellationException ex) {
112114
throw new ExecutionFailedException(
113115
"PWA icons generation failed", ex);
116+
} finally {
117+
executor.shutdown();
114118
}
115119
} finally {
116120
if (headless == null) {
@@ -170,16 +174,16 @@ private URL findIcon(PwaConfiguration pwaConfiguration) {
170174
return iconURL;
171175
}
172176

173-
private CompletableFuture<?> generateIcon(InternalPwaIcon icon) {
177+
private Runnable generateIcon(InternalPwaIcon icon) {
174178
Path iconPath = generatedIconsPath.resolve(icon.getRelHref()
175179
.substring(1).replace('/', File.separatorChar));
176-
return CompletableFuture.runAsync(() -> {
180+
return () -> {
177181
try (OutputStream os = Files.newOutputStream(iconPath)) {
178182
icon.write(os);
179183
} catch (IOException e) {
180184
throw new UncheckedIOException(e);
181185
}
182-
});
186+
};
183187
}
184188

185189
private static class InternalPwaIcon extends PwaIcon {
@@ -194,5 +198,6 @@ public InternalPwaIcon(PwaIcon icon, BufferedImage baseImage) {
194198
protected BufferedImage getBaseImage() {
195199
return baseImage;
196200
}
201+
197202
}
198203
}

0 commit comments

Comments
 (0)