Skip to content
Permalink
Browse files

Merge pull request #68 from jglick/starvation-JENKINS-25890

[JENKINS-25890] Use own thread pool for CpsStepContext.getProgramPromise
  • Loading branch information...
jglick committed Mar 4, 2015
2 parents 2e48ba9 + 37e44c6 commit 729984d402ebae38c2dc44ea3d72eb5f01aa6dfe
@@ -427,6 +427,7 @@ public void onSuccess(Unmarshaller u) {
}

public void onFailure(Throwable t) {
// Note: not calling result.setException(t) since loadProgramFailed in fact sets a result
try {
loadProgramFailed(t, result);
} finally {
@@ -31,6 +31,8 @@
import groovy.lang.Closure;
import hudson.model.Descriptor;
import hudson.model.Result;
import hudson.util.DaemonThreadFactory;
import hudson.util.NamingThreadFactory;
import jenkins.model.Jenkins;
import org.jenkinsci.plugins.workflow.cps.nodes.StepEndNode;
import org.jenkinsci.plugins.workflow.cps.nodes.StepStartNode;
@@ -57,9 +59,11 @@
import java.util.Collections;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.logging.Level;
import java.util.logging.Logger;
import jenkins.util.Timer;
import jenkins.util.ContextResettingExecutorService;
import org.codehaus.groovy.runtime.InvokerInvocationException;

import static org.jenkinsci.plugins.workflow.cps.persistence.PersistenceContext.*;
@@ -160,6 +164,12 @@
*/
private transient volatile StepDescriptor stepDescriptor;

/**
* Cached value of {@link #getProgramPromise}.
* Never null once set (might be overwritten).
*/
private transient volatile ListenableFuture<CpsThreadGroup> programPromise;

@CpsVmThreadOnly
CpsStepContext(StepDescriptor step, CpsThread thread, FlowExecutionOwner executionRef, FlowNode node, Closure body) {
this.threadId = thread.id;
@@ -224,22 +234,26 @@ public String getDisplayName() {
throw new IOException(e);
}
}


private static final ExecutorService getProgramPromiseExecutorService = new ContextResettingExecutorService(Executors.newCachedThreadPool(new NamingThreadFactory(new DaemonThreadFactory(), "CpsStepContext.getProgramPromise")));
private @Nonnull ListenableFuture<CpsThreadGroup> getProgramPromise() {
final SettableFuture<CpsThreadGroup> f = SettableFuture.create();
// TODO is there some more convenient way of writing this using Futures.transform?
Timer.get().submit(new Runnable() {
@Override public void run() {
try {
ListenableFuture<CpsThreadGroup> pp = getFlowExecution().programPromise;
assert pp != null;
f.set(pp.get());
} catch (Exception x) { // from getFlowExecution() or get()
f.setException(x);
if (programPromise == null) {
final SettableFuture<CpsThreadGroup> f = SettableFuture.create();
// TODO is there some more convenient way of writing this using Futures.transform? FlowExecutionOwner.get should really return ListenableFuture<FlowExecution>
getProgramPromiseExecutorService.submit(new Runnable() {
@Override public void run() {
try {
ListenableFuture<CpsThreadGroup> pp = getFlowExecution().programPromise;
assert pp != null;
f.set(pp.get());
} catch (Exception x) { // from getFlowExecution() or get()
f.setException(x);
}
}
}
});
return f;
});
programPromise = f;
}
return programPromise;
}

@Override public boolean isReady() {

0 comments on commit 729984d

Please sign in to comment.
You can’t perform that action at this time.