public class CpsFlowExecution
extends org.jenkinsci.plugins.workflow.flow.FlowExecution
implements org.jenkinsci.plugins.workflow.flow.BlockableResume
FlowExecution
implemented with Groovy CPS.
CpsFlowExecution
goes through the following states:
+----------------------+
| |
v |
PERSISTED --> PREPARING --> SUSPENDED --> RUNNABLE --> RUNNING --> COMPLETE
^
|
INITIAL
CpsFlowExecution
is created, it starts from here.
When start()
method is called, we get one thread scheduled, and we arrive at RUNNABLE state.
CpsFlowExecution
is on disk with its owner, for example in build.xml
of the workflow run.
Nothing exists in memory. For example, Jenkins is not running.
Transition from this into PREPARING is triggered outside our control by XStream using
CpsFlowExecution.ConverterImpl
to unmarshal CpsFlowExecution
. FlowExecution.onLoad()
is called
at the end, and we arrive at the PREPARING state.
CpsFlowExecution
is in memory, but CpsThreadGroup
isn't. We are trying to
restore all the ephemeral pickles that are necessary to get workflow going again.
programPromise
represents a promise of completing this state.
PickleResolver
keeps track of this, and when it's all done, we arrive at SUSPENDED state.
CpsThreadGroup
is in memory, but all CpsThread
s are not runnable,
which means they are waiting for some conditions to trigger (such as a completion of a shell script that's executing,
human approval, etc). CpsFlowExecution
and CpsThreadGroup
are safe to persist.
When a condition is met, CpsThread.resume(Outcome)
is called, and that thread becomes runnable,
and we move to the RUNNABLE state.
CpsThread
s are runnable, but we aren't actually running. The conditions that triggered
CpsThread
is captured in CpsThread.resumeValue
.
As we get into this state, CpsThreadGroup.scheduleRun()
should be called to schedule the execution.
CpsFlowExecution
and CpsThreadGroup
are safe to persist in this state, just like in the SUSPENDED state.
When CpsThreadGroup.runner
allocated a real Java thread to the execution, we move to the RUNNING state.
CpsThreadGroup.run()
and is actively mutating the object graph inside the script.
This state continues until no threads are runnable any more.
Only one thread executes CpsThreadGroup.run()
.
In this state, CpsFlowExecution
still need to be persistable (because generally we don't get to
control when it is persisted), but CpsThreadGroup
isn't safe to persist.
When the Java thread leaves CpsThreadGroup.run()
, we move to the SUSPENDED state.
CpsThread
s have terminated and there's nothing more to execute, and there's no more events to wait.
The result is finalized and there's no further state change.
Modifier and Type | Class and Description |
---|---|
static class |
CpsFlowExecution.ConverterImpl |
static class |
CpsFlowExecution.PipelineTimings |
Modifier and Type | Field and Description |
---|---|
com.google.common.util.concurrent.ListenableFuture<CpsThreadGroup> |
programPromise
Loading of the program is asynchronous because it requires us to re-obtain stateful objects.
|
Constructor and Description |
---|
CpsFlowExecution(String script,
boolean sandbox,
org.jenkinsci.plugins.workflow.flow.FlowExecutionOwner owner) |
CpsFlowExecution(String script,
boolean sandbox,
org.jenkinsci.plugins.workflow.flow.FlowExecutionOwner owner,
org.jenkinsci.plugins.workflow.flow.FlowDurabilityHint durabilityHint) |
CpsFlowExecution(String script,
org.jenkinsci.plugins.workflow.flow.FlowExecutionOwner owner)
Deprecated.
|
Modifier and Type | Method and Description |
---|---|
void |
addListener(org.jenkinsci.plugins.workflow.flow.GraphListener listener) |
boolean |
blocksRestart()
See JENKINS-22941 for why this exists.
|
boolean |
canResume()
If true, we are allowed to resume the build because resume is enabled AND we shut down cleanly.
|
org.acegisecurity.Authentication |
getAuthentication() |
com.google.common.util.concurrent.ListenableFuture<List<org.jenkinsci.plugins.workflow.steps.StepExecution>> |
getCurrentExecutions(boolean innerMostOnly) |
List<org.jenkinsci.plugins.workflow.graph.FlowNode> |
getCurrentHeads() |
org.jenkinsci.plugins.workflow.cps.FlowHead |
getFlowHead(int id) |
Map<String,String> |
getLoadedScripts() |
String |
getNextScriptName(String path)
Finds the expected next loaded script name, like
Script1 . |
org.jenkinsci.plugins.workflow.graph.FlowNode |
getNode(String id) |
org.jenkinsci.plugins.workflow.flow.FlowExecutionOwner |
getOwner() |
Result |
getResult() |
String |
getScript() |
groovy.lang.GroovyShell |
getShell()
Returns a groovy compiler used to load the script.
|
org.jenkinsci.plugins.workflow.support.storage.FlowNodeStorage |
getStorage() |
File |
getStorageDir()
Directory where workflow stores its state.
|
CpsThreadDump |
getThreadDump()
Synchronously obtain the current state of the workflow program.
|
groovy.lang.GroovyShell |
getTrustedShell()
Returns a groovy compiler used to load the trusted script.
|
protected void |
initializeStorage() |
void |
interrupt(Result result,
CauseOfInterruption... causes) |
int |
iota() |
String |
iotaStr()
Assigns a new ID.
|
boolean |
isComplete() |
boolean |
isCurrentHead(org.jenkinsci.plugins.workflow.graph.FlowNode n) |
boolean |
isDoneFlagSet()
Has the execution been marked done - note that legacy builds may not have that flag persisted, in which case
we look for a single FlowEndNode head (see:
isComplete() and FlowExecution.isComplete() ) |
boolean |
isPaused() |
boolean |
isResumeBlocked()
If true, pipeline is forbidden to resume even if it can.
|
boolean |
isSandbox()
True if executing with groovy-sandbox, false if executing with approval.
|
List<Action> |
loadActions(org.jenkinsci.plugins.workflow.graph.FlowNode node) |
void |
loadProgramAsync(File programDataFile)
Deserializes
CpsThreadGroup from getProgramDataFile() if necessary. |
static void |
maybeAutoPersistNode(org.jenkinsci.plugins.workflow.graph.FlowNode node)
Invoke me to toggle autopersist back on for steps that delay it.
|
protected void |
notifyShutdown()
Ensures that even if we're limiting persistence of data for performance, we still write out data for shutdown.
|
void |
onLoad(org.jenkinsci.plugins.workflow.flow.FlowExecutionOwner owner) |
void |
pause(boolean v)
Pause or unpause the execution.
|
void |
removeListener(org.jenkinsci.plugins.workflow.flow.GraphListener listener) |
void |
saveActions(org.jenkinsci.plugins.workflow.graph.FlowNode node,
List<Action> actions) |
void |
setResult(Result v) |
void |
setResumeBlocked(boolean resumeBlocked) |
void |
start() |
static void |
suspendAll() |
String |
toString() |
void |
waitForSuspension()
Waits for the workflow to move into the SUSPENDED state.
|
public transient volatile com.google.common.util.concurrent.ListenableFuture<CpsThreadGroup> programPromise
Future
for filling in CpsThreadGroup
.
TODO: provide a mechanism to diagnose how far along this process is.runInCpsVmThread(FutureCallback)
@Deprecated public CpsFlowExecution(String script, org.jenkinsci.plugins.workflow.flow.FlowExecutionOwner owner) throws IOException
IOException
public CpsFlowExecution(@Nonnull String script, boolean sandbox, @Nonnull org.jenkinsci.plugins.workflow.flow.FlowExecutionOwner owner, @CheckForNull org.jenkinsci.plugins.workflow.flow.FlowDurabilityHint durabilityHint) throws IOException
IOException
public CpsFlowExecution(String script, boolean sandbox, org.jenkinsci.plugins.workflow.flow.FlowExecutionOwner owner) throws IOException
IOException
public boolean isResumeBlocked()
isResumeBlocked
in interface org.jenkinsci.plugins.workflow.flow.BlockableResume
public void setResumeBlocked(boolean resumeBlocked)
setResumeBlocked
in interface org.jenkinsci.plugins.workflow.flow.BlockableResume
public groovy.lang.GroovyShell getShell()
GroovyShell.getClassLoader()
public groovy.lang.GroovyShell getTrustedShell()
public org.jenkinsci.plugins.workflow.support.storage.FlowNodeStorage getStorage()
public String getScript()
public boolean isSandbox()
public org.jenkinsci.plugins.workflow.flow.FlowExecutionOwner getOwner()
getOwner
in class org.jenkinsci.plugins.workflow.flow.FlowExecution
public File getStorageDir() throws IOException
IOException
public void start() throws IOException
start
in class org.jenkinsci.plugins.workflow.flow.FlowExecution
IOException
@Restricted(value=org.kohsuke.accmod.restrictions.NoExternalUse.class) public String iotaStr()
@Restricted(value=org.kohsuke.accmod.restrictions.NoExternalUse.class) public int iota()
protected void initializeStorage() throws IOException
IOException
public boolean canResume()
public void onLoad(org.jenkinsci.plugins.workflow.flow.FlowExecutionOwner owner) throws IOException
onLoad
in class org.jenkinsci.plugins.workflow.flow.FlowExecution
IOException
public void loadProgramAsync(File programDataFile)
CpsThreadGroup
from getProgramDataFile()
if necessary.
This moves us into the PREPARING state.programDataFile
- public boolean blocksRestart()
blocksRestart
in class org.jenkinsci.plugins.workflow.flow.FlowExecution
public void waitForSuspension() throws InterruptedException, ExecutionException
@CheckForNull public org.jenkinsci.plugins.workflow.cps.FlowHead getFlowHead(int id)
public List<org.jenkinsci.plugins.workflow.graph.FlowNode> getCurrentHeads()
getCurrentHeads
in class org.jenkinsci.plugins.workflow.flow.FlowExecution
public com.google.common.util.concurrent.ListenableFuture<List<org.jenkinsci.plugins.workflow.steps.StepExecution>> getCurrentExecutions(boolean innerMostOnly)
getCurrentExecutions
in class org.jenkinsci.plugins.workflow.flow.FlowExecution
public CpsThreadDump getThreadDump()
The workflow can be already completed, or it can still be running.
public boolean isCurrentHead(org.jenkinsci.plugins.workflow.graph.FlowNode n)
isCurrentHead
in class org.jenkinsci.plugins.workflow.flow.FlowExecution
public void addListener(org.jenkinsci.plugins.workflow.flow.GraphListener listener)
addListener
in class org.jenkinsci.plugins.workflow.flow.FlowExecution
public void removeListener(org.jenkinsci.plugins.workflow.flow.GraphListener listener)
removeListener
in class org.jenkinsci.plugins.workflow.flow.FlowExecution
public void interrupt(Result result, CauseOfInterruption... causes) throws IOException, InterruptedException
interrupt
in class org.jenkinsci.plugins.workflow.flow.FlowExecution
IOException
InterruptedException
public org.jenkinsci.plugins.workflow.graph.FlowNode getNode(String id) throws IOException
getNode
in class org.jenkinsci.plugins.workflow.flow.FlowExecution
IOException
public void setResult(Result v)
public Result getResult()
public List<Action> loadActions(org.jenkinsci.plugins.workflow.graph.FlowNode node) throws IOException
loadActions
in interface org.jenkinsci.plugins.workflow.graph.FlowActionStorage
IOException
public void saveActions(org.jenkinsci.plugins.workflow.graph.FlowNode node, List<Action> actions) throws IOException
saveActions
in interface org.jenkinsci.plugins.workflow.graph.FlowActionStorage
IOException
public static void maybeAutoPersistNode(@Nonnull org.jenkinsci.plugins.workflow.graph.FlowNode node)
public boolean isComplete()
isComplete
in class org.jenkinsci.plugins.workflow.flow.FlowExecution
public org.acegisecurity.Authentication getAuthentication()
getAuthentication
in class org.jenkinsci.plugins.workflow.flow.FlowExecution
@Restricted(value=org.kohsuke.accmod.restrictions.NoExternalUse.class) public String getNextScriptName(String path)
Script1
.path
- a file path being loaded (currently ignored)public boolean isDoneFlagSet()
isComplete()
and FlowExecution.isComplete()
)public boolean isPaused()
public void pause(boolean v) throws IOException
v
- true to pause, false to unpause.IOException
@Restricted(value=org.kohsuke.accmod.restrictions.DoNotUse.class) @Terminator public static void suspendAll()
protected void notifyShutdown()
notifyShutdown
in class org.jenkinsci.plugins.workflow.flow.FlowExecution
Copyright © 2016–2020. All rights reserved.