From 4b87e757975ce62f42e3acad91717a31d4df3fd8 Mon Sep 17 00:00:00 2001 From: Jonathan Giles Date: Fri, 12 Jul 2024 19:42:24 +1200 Subject: [PATCH] Fix issue with lifecycle hooks concurrently modifying the underlying resources list. --- .../microsoft/aspire/ManifestGenerator.java | 23 ++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/aspire4j/aspire4j/src/main/java/com/microsoft/aspire/ManifestGenerator.java b/aspire4j/aspire4j/src/main/java/com/microsoft/aspire/ManifestGenerator.java index 95b44d8..ac08540 100644 --- a/aspire4j/aspire4j/src/main/java/com/microsoft/aspire/ManifestGenerator.java +++ b/aspire4j/aspire4j/src/main/java/com/microsoft/aspire/ManifestGenerator.java @@ -6,6 +6,7 @@ import java.io.IOException; import java.io.PrintStream; import java.nio.file.*; +import java.util.HashSet; import java.util.Set; import java.util.logging.Level; import java.util.logging.Logger; @@ -61,7 +62,7 @@ private ObjectMapper prepareObjectMapper(DistributedApplication app) { } // run the precommit lifecycle hook on all resources - app.manifest.getResources().values().iterator().forEachRemaining(ResourceWithLifecycle::onResourcePrecommit); + callLifecyclePrecommitHook(app); LOGGER.info("Validating models..."); // Firstly, disable the info logging messages that are printed by Hibernate Validator @@ -134,6 +135,26 @@ private void writeTemplateFile(TemplateFileOutput templateFile) { } } + private void callLifecyclePrecommitHook(DistributedApplication app) { + Set processedResources = new HashSet<>(); + Set currentResources = new HashSet<>(app.manifest.getResources().values()); + + while (!currentResources.isEmpty()) { + // Create a snapshot of current resources to iterate over + Set snapshot = new HashSet<>(currentResources); + for (ResourceWithLifecycle resource : snapshot) { + if (!processedResources.contains(resource)) { + resource.onResourcePrecommit(); + processedResources.add(resource); + } + currentResources.remove(resource); + } + // Update currentResources to include only new resources added during processing + currentResources.addAll(app.manifest.getResources().values()); + currentResources.removeAll(processedResources); + } + } + private void printAnnotations(PrintStream out, DistributedApplication app) { app.manifest.getResources().values().forEach(resource -> { out.println("Resource: " + resource.getName());