diff --git a/src/main/java/org/jenkinsci/plugins/workflow/steps/SynchronousNonBlockingStepExecution.java b/src/main/java/org/jenkinsci/plugins/workflow/steps/SynchronousNonBlockingStepExecution.java index acfc0d3..b5cfc85 100644 --- a/src/main/java/org/jenkinsci/plugins/workflow/steps/SynchronousNonBlockingStepExecution.java +++ b/src/main/java/org/jenkinsci/plugins/workflow/steps/SynchronousNonBlockingStepExecution.java @@ -1,17 +1,20 @@ package org.jenkinsci.plugins.workflow.steps; +import hudson.ExtensionList; +import hudson.ExtensionPoint; import hudson.security.ACL; import hudson.security.ACLContext; import hudson.util.ClassLoaderSanityThreadFactory; import hudson.util.DaemonThreadFactory; import hudson.util.NamingThreadFactory; -import java.io.IOException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; import edu.umd.cs.findbugs.annotations.NonNull; import jenkins.model.Jenkins; +import org.kohsuke.accmod.Restricted; +import org.kohsuke.accmod.restrictions.Beta; import org.springframework.security.core.Authentication; /** @@ -92,9 +95,26 @@ public void onResume() { static synchronized ExecutorService getExecutorService() { if (executorService == null) { - executorService = Executors.newCachedThreadPool(new NamingThreadFactory(new ClassLoaderSanityThreadFactory(new DaemonThreadFactory()), "org.jenkinsci.plugins.workflow.steps.SynchronousNonBlockingStepExecution")); + ExecutorService result = Executors.newCachedThreadPool(new NamingThreadFactory(new ClassLoaderSanityThreadFactory(new DaemonThreadFactory()), "org.jenkinsci.plugins.workflow.steps.SynchronousNonBlockingStepExecution")); + + for (ExecutorServiceAugmentor augmentor : ExtensionList.lookup(ExecutorServiceAugmentor.class)) { + result = augmentor.augment(result); + } + executorService = result; } return executorService; } + /** + * Extension point for augmenting the executorService of {@link SynchronousNonBlockingStepExecution}. + */ + @Restricted(Beta.class) + public interface ExecutorServiceAugmentor extends ExtensionPoint { + /** + * Augment the executor service used by {@link SynchronousNonBlockingStepExecution} and {@link GeneralNonBlockingStepExecution}. + * @param executorService the executor service to augment + */ + ExecutorService augment(ExecutorService executorService); + } + } diff --git a/src/test/java/org/jenkinsci/plugins/workflow/steps/SynchronousNonBlockingStepExecutorServiceAugmentorTest.java b/src/test/java/org/jenkinsci/plugins/workflow/steps/SynchronousNonBlockingStepExecutorServiceAugmentorTest.java new file mode 100644 index 0000000..442dc81 --- /dev/null +++ b/src/test/java/org/jenkinsci/plugins/workflow/steps/SynchronousNonBlockingStepExecutorServiceAugmentorTest.java @@ -0,0 +1,42 @@ +package org.jenkinsci.plugins.workflow.steps; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.hasItem; + +import java.util.concurrent.ExecutorService; +import java.util.logging.Level; +import java.util.logging.Logger; +import org.junit.Rule; +import org.junit.Test; +import org.jvnet.hudson.test.JenkinsRule; +import org.jvnet.hudson.test.LoggerRule; +import org.jvnet.hudson.test.TestExtension; + +public class SynchronousNonBlockingStepExecutorServiceAugmentorTest { + + @Rule + public JenkinsRule r = new JenkinsRule(); + + @Rule + public LoggerRule loggerRule = + new LoggerRule().record(AugmentorTestExtension.class, Level.FINE).capture(10); + + @Test + public void smokes() throws Exception { + SynchronousNonBlockingStepExecution.getExecutorService(); + assertThat(loggerRule.getMessages(), hasItem("Augmenting")); + } + + @TestExtension + public static class AugmentorTestExtension + implements SynchronousNonBlockingStepExecution.ExecutorServiceAugmentor { + + private static final Logger LOGGER = Logger.getLogger(AugmentorTestExtension.class.getName()); + + @Override + public ExecutorService augment(ExecutorService executorService) { + LOGGER.fine(() -> "Augmenting"); + return executorService; + } + } +}