use of com.cloudbees.groovy.cps.Outcome in project workflow-cps-plugin by jenkinsci.
the class CpsFlowExecution method start.
@Override
public void start() throws IOException {
final CpsScript s = parseScript();
scriptClass = s.getClass();
s.$initialize();
final FlowHead h = new FlowHead(this);
synchronized (this) {
heads.put(h.getId(), h);
}
h.newStartNode(new FlowStartNode(this, iotaStr()));
final CpsThreadGroup g = new CpsThreadGroup(this);
g.register(s);
final SettableFuture<CpsThreadGroup> f = SettableFuture.create();
programPromise = f;
// Ensures we've saves the WorkFlowRun at least once with initial state
saveOwner();
g.runner.submit(new Runnable() {
@Override
public void run() {
CpsThread t = g.addThread(new Continuable(s, createInitialEnv()), h, null);
t.resume(new Outcome(null, null));
f.set(g);
}
/**
* Environment to start executing the script in.
* During sandbox execution, we need to call sandbox interceptor while executing asynchronous code.
*/
private Env createInitialEnv() {
return Envs.empty(isSandbox() ? new SandboxInvoker() : new DefaultInvoker());
}
});
}
use of com.cloudbees.groovy.cps.Outcome in project workflow-cps-plugin by jenkinsci.
the class CpsThread method runNextChunk.
/**
* Executes CPS code synchronously a little bit more, until it hits
* the point the workflow needs to be dehydrated.
*/
@SuppressWarnings("rawtypes")
@Nonnull
Outcome runNextChunk() {
assert program != null;
Outcome outcome;
final CpsThread old = CURRENT.get();
CURRENT.set(this);
try (Timeout timeout = Timeout.limit(5, TimeUnit.MINUTES)) {
LOGGER.log(FINE, "runNextChunk on {0}", resumeValue);
final Outcome o = resumeValue;
resumeValue = null;
outcome = program.run0(o, categories);
if (outcome.getAbnormal() != null) {
LOGGER.log(FINE, "ran and produced error", outcome.getAbnormal());
} else {
LOGGER.log(FINE, "ran and produced {0}", outcome);
}
if (outcome.getNormal() instanceof ThreadTask) {
// if an execution in the thread safepoint is requested, deliver that
ThreadTask sc = (ThreadTask) outcome.getNormal();
ThreadTaskResult r = sc.eval(this);
if (r.resume != null) {
// yield, then keep evaluating the CPS code
resumeValue = r.resume;
} else {
// break but with a different value
outcome = r.suspend;
}
}
} finally {
CURRENT.set(old);
}
if (promise != null) {
if (outcome.isSuccess())
promise.set(outcome.getNormal());
else {
try {
promise.setException(outcome.getAbnormal());
} catch (Error e) {
if (e == outcome.getAbnormal()) {
// affects other places that use SettableFuture
;
} else {
throw e;
}
}
}
promise = null;
}
return outcome;
}
use of com.cloudbees.groovy.cps.Outcome in project groovy-cps by cloudbees.
the class GreenThread method start.
/**
* Creates a new green thread that executes the given closure.
*/
public void start() {
Block b;
try {
run();
// closure had run synchronously.
b = Block.NOOP;
} catch (CpsCallableInvocation inv) {
// this will create a thread, and resume with the newly created thread
b = inv.asBlock();
} catch (Throwable t) {
// closure had run synchronously and failed
b = new ThrowBlock(new ConstantBlock(t));
}
final Block bb = b;
invoke(new ThreadTask() {
public Result eval(GreenWorld w) {
w = w.withNewThread(new GreenThreadState(GreenThread.this, bb));
return new Result(w, new Outcome(GreenThread.this, null), false);
}
});
// thus the code will never reach here
throw new AssertionError();
}
use of com.cloudbees.groovy.cps.Outcome in project groovy-cps by cloudbees.
the class GreenWorld method update.
/**
* Called when we execute something in one of the member thread.
*
* We'll build an updated {@link GreenWorld} then return it.
*/
Next update(GreenThreadState g) {
GreenWorld d = this.with(g);
Outcome y = g.n.yield;
if (y == null) {
// no yield. rotate to next thread and keep going
return d.withNewCur().asNext(null);
}
if (y.getNormal() instanceof ThreadTask) {
// a task that needs to update/access the state
ThreadTask task = (ThreadTask) y.getNormal();
Result r = task.eval(d);
d = r.w;
if (// yield the value, then come back to the current thread later
r.suspend)
return d.asNext(r.value);
else
return d.update(g.resumeFrom(r.value));
} else {
// other Outcome is for caller
return d.asNext(y);
}
}
use of com.cloudbees.groovy.cps.Outcome in project workflow-cps-plugin by jenkinsci.
the class CpsFlowExecution method loadProgramFailed.
/**
* Used by {@link #loadProgramAsync(File)} to propagate a failure to load the persisted execution state.
* <p>
* Let the workflow interrupt by throwing an exception that indicates how it failed.
* @param promise same as {@link #programPromise} but more strongly typed
*/
private void loadProgramFailed(final Throwable problem, SettableFuture<CpsThreadGroup> promise) {
FlowHead head;
synchronized (this) {
if (heads == null || heads.isEmpty()) {
head = null;
} else {
head = getFirstHead();
}
}
if (head == null) {
// something went catastrophically wrong and there's no live head. fake one
head = new FlowHead(this);
try {
head.newStartNode(new FlowStartNode(this, iotaStr()));
} catch (IOException e) {
LOGGER.log(Level.FINE, "Failed to persist", e);
}
}
CpsThreadGroup g = new CpsThreadGroup(this);
final FlowHead head_ = head;
promise.set(g);
runInCpsVmThread(new FutureCallback<CpsThreadGroup>() {
@Override
public void onSuccess(CpsThreadGroup g) {
CpsThread t = g.addThread(new Continuable(new ThrowBlock(new ConstantBlock(problem instanceof AbortException ? problem : new IOException("Failed to load build state", problem)))), head_, null);
t.resume(new Outcome(null, null));
}
@Override
public void onFailure(Throwable t) {
LOGGER.log(Level.WARNING, "Failed to set program failure on " + owner, t);
croak(t);
}
});
}
Aggregations