diff --git a/src/main/java/org/jenkinsci/plugins/workflow/flow/FlowExecution.java b/src/main/java/org/jenkinsci/plugins/workflow/flow/FlowExecution.java index 27273754..289dd9a7 100644 --- a/src/main/java/org/jenkinsci/plugins/workflow/flow/FlowExecution.java +++ b/src/main/java/org/jenkinsci/plugins/workflow/flow/FlowExecution.java @@ -317,8 +317,10 @@ public Iterable iterateEnclosingBlocks(@NonNull FlowNode node) { return getInternalGraphLookup().iterateEnclosingBlocks(node); } - /** Perform shutdown-specific logic -- should be invoked by the {@link FlowExecutionOwner#notifyShutdown()} method - * in response to {@link FlowExecutionList#saveAll()} */ + /** + * @deprecated No longer used. + */ + @Deprecated protected void notifyShutdown() { // Default is no-op } diff --git a/src/main/java/org/jenkinsci/plugins/workflow/flow/FlowExecutionList.java b/src/main/java/org/jenkinsci/plugins/workflow/flow/FlowExecutionList.java index 220a2272..20199eaa 100644 --- a/src/main/java/org/jenkinsci/plugins/workflow/flow/FlowExecutionList.java +++ b/src/main/java/org/jenkinsci/plugins/workflow/flow/FlowExecutionList.java @@ -11,6 +11,7 @@ import hudson.ExtensionList; import hudson.XmlFile; import hudson.init.InitMilestone; +import hudson.init.TermMilestone; import hudson.init.Terminator; import hudson.model.Computer; import hudson.model.listeners.ItemListener; @@ -38,6 +39,7 @@ import java.util.logging.Logger; import org.jenkinsci.plugins.workflow.graph.FlowNode; import org.jenkinsci.plugins.workflow.graphanalysis.LinearBlockHoppingScanner; +import org.jvnet.hudson.reactor.Milestone; import org.kohsuke.accmod.Restricted; import org.kohsuke.accmod.restrictions.Beta; @@ -50,6 +52,19 @@ */ @Extension public class FlowExecutionList implements Iterable { + + /** + * Milestone for {@link Terminator} between {@link TermMilestone#STARTED} and {@link #LIST_SAVED}. + * All running builds have been suspended and their {@link FlowExecutionOwner#getListener}s closed. + */ + public static final String EXECUTIONS_SUSPENDED = "FlowExecutionList.EXECUTIONS_SUSPENDED"; + + /** + * Milestone for {@link Terminator} between {@link #EXECUTIONS_SUSPENDED} and {@link TermMilestone#COMPLETED}. + * {@link FlowExecutionList} itself has been saved. + */ + public static final String LIST_SAVED = "FlowExecutionList.LIST_SAVED"; + private final CopyOnWriteList runningTasks = new CopyOnWriteList<>(); private final SingleLaneExecutorService executor = new SingleLaneExecutorService(Timer.get()); private XmlFile configFile; @@ -238,7 +253,9 @@ public void onFailure(@NonNull Throwable t) { } @Restricted(DoNotUse.class) - @Terminator public static void saveAll() throws InterruptedException { + @SuppressWarnings("deprecation") + @Terminator(requires = EXECUTIONS_SUSPENDED, attains = LIST_SAVED) + public static void saveAll() throws InterruptedException { LOGGER.fine("ensuring all executions are saved"); for (FlowExecutionOwner owner : get().runningTasks.getView()) { diff --git a/src/main/java/org/jenkinsci/plugins/workflow/flow/FlowExecutionOwner.java b/src/main/java/org/jenkinsci/plugins/workflow/flow/FlowExecutionOwner.java index f8a0e322..1c85716b 100644 --- a/src/main/java/org/jenkinsci/plugins/workflow/flow/FlowExecutionOwner.java +++ b/src/main/java/org/jenkinsci/plugins/workflow/flow/FlowExecutionOwner.java @@ -53,7 +53,10 @@ public abstract class FlowExecutionOwner implements Serializable { @NonNull public abstract FlowExecution get() throws IOException; - /** Invoked in {@link FlowExecutionList#saveAll()} to notify that execution has been suspended */ + /** + * @deprecated No longer used. + */ + @Deprecated void notifyShutdown() { FlowExecution exec = getOrNull(); if (exec != null) {