Class CpsFlowExecution
java.lang.Object
org.jenkinsci.plugins.workflow.flow.FlowExecution
org.jenkinsci.plugins.workflow.cps.CpsFlowExecution
- All Implemented Interfaces:
org.jenkinsci.plugins.workflow.flow.BlockableResume
,org.jenkinsci.plugins.workflow.graph.FlowActionStorage
,org.jenkinsci.plugins.workflow.graph.GraphLookupView
public class CpsFlowExecution
extends org.jenkinsci.plugins.workflow.flow.FlowExecution
implements org.jenkinsci.plugins.workflow.flow.BlockableResume
FlowExecution
implemented with Groovy CPS.
State Transition
CpsFlowExecution
goes through the following states:
+----------------------+
| |
v |
PERSISTED --> PREPARING --> SUSPENDED --> RUNNABLE --> RUNNING --> COMPLETE
^
|
INITIAL
- INITIAL
-
When a new
CpsFlowExecution
is created, it starts from here. Whenstart()
method is called, we get one thread scheduled, and we arrive at RUNNABLE state. - PERSISTED
-
CpsFlowExecution
is on disk with its owner, for example inbuild.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 usingCpsFlowExecution.ConverterImpl
to unmarshalCpsFlowExecution
.FlowExecution.onLoad()
is called at the end, and we arrive at the PREPARING state. - PREPARING
-
CpsFlowExecution
is in memory, butCpsThreadGroup
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. - SUSPENDED
-
CpsThreadGroup
is in memory, but allCpsThread
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
andCpsThreadGroup
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. - RUNNABLE
-
Some of
CpsThread
s are runnable, but we aren't actually running. The conditions that triggeredCpsThread
is captured inCpsThread.resumeValue
. As we get into this state,CpsThreadGroup.scheduleRun()
should be called to schedule the execution.CpsFlowExecution
andCpsThreadGroup
are safe to persist in this state, just like in the SUSPENDED state. WhenCpsThreadGroup.runner
allocated a real Java thread to the execution, we move to the RUNNING state. - RUNNING
-
A thread is inside
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 executesCpsThreadGroup.run()
. In this state,CpsFlowExecution
still need to be persistable (because generally we don't get to control when it is persisted), butCpsThreadGroup
isn't safe to persist. When the Java thread leavesCpsThreadGroup.run()
, we move to the SUSPENDED state. - COMPLETE
-
All the
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.
- Author:
- Kohsuke Kawaguchi
-
Nested Class Summary
Modifier and TypeClassDescriptionstatic final class
static class
static class
Nested classes/interfaces inherited from interface org.jenkinsci.plugins.workflow.graph.GraphLookupView
org.jenkinsci.plugins.workflow.graph.GraphLookupView.EnclosingBlocksIterable
-
Field Summary
Modifier and TypeFieldDescriptionstatic boolean
Iftrue
, then when the execution completes, we migrate the flow node storage fromSimpleXStreamFlowNodeStorage
toBulkFlowNodeStorage
.com.google.common.util.concurrent.ListenableFuture<CpsThreadGroup>
Loading of the program is asynchronous because it requires us to re-obtain stateful objects.Fields inherited from class org.jenkinsci.plugins.workflow.flow.FlowExecution
durabilityHint, internalGraphLookup
-
Constructor Summary
ConstructorDescriptionCpsFlowExecution
(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. -
Method Summary
Modifier and TypeMethodDescriptionvoid
addListener
(org.jenkinsci.plugins.workflow.flow.GraphListener listener) protected void
boolean
See JENKINS-22941 for why this exists.boolean
If true, we are allowed to resume the build because resume is enabled AND we shut down cleanly.com.google.common.util.concurrent.ListenableFuture<List<org.jenkinsci.plugins.workflow.steps.StepExecution>>
getCurrentExecutions
(boolean innerMostOnly) List<org.jenkinsci.plugins.workflow.graph.FlowNode>
org.jenkinsci.plugins.workflow.cps.FlowHead
getFlowHead
(int id) getNextScriptName
(String path) Finds the expected next loaded script name, likeScript1
.org.jenkinsci.plugins.workflow.graph.FlowNode
org.jenkinsci.plugins.workflow.flow.FlowExecutionOwner
getOwner()
groovy.lang.GroovyShell
getShell()
Returns a groovy compiler used to load the script.org.jenkinsci.plugins.workflow.support.storage.FlowNodeStorage
Directory where workflow stores its state.Synchronously obtain the current state of the workflow program.groovy.lang.GroovyShell
Returns a groovy compiler used to load the trusted script.protected void
void
interrupt
(Result result, CauseOfInterruption... causes) int
iota()
iotaStr()
Assigns a new ID.boolean
boolean
isCurrentHead
(org.jenkinsci.plugins.workflow.graph.FlowNode n) boolean
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()
andFlowExecution.isComplete()
)boolean
isPaused()
boolean
If true, pipeline is forbidden to resume even if it can.boolean
True if executing with groovy-sandbox, false if executing with approval.loadActions
(org.jenkinsci.plugins.workflow.graph.FlowNode node) void
loadProgramAsync
(File programDataFile) DeserializesCpsThreadGroup
fromgetProgramDataFile()
if necessary.static void
maybeAutoPersistNode
(org.jenkinsci.plugins.workflow.graph.FlowNode node) Invoke me to toggle autopersist back on for steps that delay it.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
void
setResumeBlocked
(boolean resumeBlocked) void
start()
static void
toString()
void
Deprecated.Methods inherited from class org.jenkinsci.plugins.workflow.flow.FlowExecution
findAllEnclosingBlockStarts, findEnclosingBlockStart, getCauseOfFailure, getCurrentExecutions, getDurabilityHint, getEndNode, getInternalGraphLookup, getUrl, isActive, iterateEnclosingBlocks, notifyShutdown, onLoad
-
Field Details
-
OPTIMIZE_STORAGE_UPON_COMPLETION
public static boolean OPTIMIZE_STORAGE_UPON_COMPLETIONIftrue
, then when the execution completes, we migrate the flow node storage fromSimpleXStreamFlowNodeStorage
toBulkFlowNodeStorage
. -
programPromise
public transient volatile com.google.common.util.concurrent.ListenableFuture<CpsThreadGroup> programPromiseLoading of the program is asynchronous because it requires us to re-obtain stateful objects. This object represents aFuture
for filling inCpsThreadGroup
. TODO: provide a mechanism to diagnose how far along this process is.- See Also:
-
runInCpsVmThread(FutureCallback)
-
-
Constructor Details
-
CpsFlowExecution
@Deprecated public CpsFlowExecution(String script, org.jenkinsci.plugins.workflow.flow.FlowExecutionOwner owner) throws IOException Deprecated.- Throws:
IOException
-
CpsFlowExecution
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 - Throws:
IOException
-
CpsFlowExecution
public CpsFlowExecution(String script, boolean sandbox, org.jenkinsci.plugins.workflow.flow.FlowExecutionOwner owner) throws IOException - Throws:
IOException
-
-
Method Details
-
isResumeBlocked
public boolean isResumeBlocked()If true, pipeline is forbidden to resume even if it can.- Specified by:
isResumeBlocked
in interfaceorg.jenkinsci.plugins.workflow.flow.BlockableResume
-
setResumeBlocked
public void setResumeBlocked(boolean resumeBlocked) - Specified by:
setResumeBlocked
in interfaceorg.jenkinsci.plugins.workflow.flow.BlockableResume
-
getShell
public groovy.lang.GroovyShell getShell()Returns a groovy compiler used to load the script.- See Also:
-
- "doc/classloader.md"
GroovyShell.getClassLoader()
-
getTrustedShell
public groovy.lang.GroovyShell getTrustedShell()Returns a groovy compiler used to load the trusted script.- See Also:
-
- "doc/classloader.md"
-
getStorage
public org.jenkinsci.plugins.workflow.support.storage.FlowNodeStorage getStorage() -
getScript
-
getLoadedScripts
-
isSandbox
public boolean isSandbox()True if executing with groovy-sandbox, false if executing with approval. -
getOwner
public org.jenkinsci.plugins.workflow.flow.FlowExecutionOwner getOwner()- Specified by:
getOwner
in classorg.jenkinsci.plugins.workflow.flow.FlowExecution
-
getStorageDir
Directory where workflow stores its state.- Throws:
IOException
-
start
- Specified by:
start
in classorg.jenkinsci.plugins.workflow.flow.FlowExecution
- Throws:
IOException
-
iotaStr
Assigns a new ID. -
iota
@Restricted(org.kohsuke.accmod.restrictions.NoExternalUse.class) public int iota() -
initializeStorage
- Throws:
IOException
-
canResume
public boolean canResume()If true, we are allowed to resume the build because resume is enabled AND we shut down cleanly. -
onLoad
- Overrides:
onLoad
in classorg.jenkinsci.plugins.workflow.flow.FlowExecution
- Throws:
IOException
-
loadProgramAsync
DeserializesCpsThreadGroup
fromgetProgramDataFile()
if necessary. This moves us into the PREPARING state.- Parameters:
programDataFile
-
-
afterStepExecutionsResumed
protected void afterStepExecutionsResumed()- Overrides:
afterStepExecutionsResumed
in classorg.jenkinsci.plugins.workflow.flow.FlowExecution
-
blocksRestart
public boolean blocksRestart()See JENKINS-22941 for why this exists.- Overrides:
blocksRestart
in classorg.jenkinsci.plugins.workflow.flow.FlowExecution
-
waitForSuspension
Deprecated.Use some other idiom, likeSemaphoreStep
.Waits for the workflow to move into the SUSPENDED state. -
getFlowHead
@CheckForNull public org.jenkinsci.plugins.workflow.cps.FlowHead getFlowHead(int id) -
getCurrentHeads
- Specified by:
getCurrentHeads
in classorg.jenkinsci.plugins.workflow.flow.FlowExecution
-
getCurrentExecutions
public com.google.common.util.concurrent.ListenableFuture<List<org.jenkinsci.plugins.workflow.steps.StepExecution>> getCurrentExecutions(boolean innerMostOnly) - Overrides:
getCurrentExecutions
in classorg.jenkinsci.plugins.workflow.flow.FlowExecution
-
getThreadDump
Synchronously obtain the current state of the workflow program.The workflow can be already completed, or it can still be running.
-
isCurrentHead
public boolean isCurrentHead(org.jenkinsci.plugins.workflow.graph.FlowNode n) - Specified by:
isCurrentHead
in classorg.jenkinsci.plugins.workflow.flow.FlowExecution
-
addListener
public void addListener(org.jenkinsci.plugins.workflow.flow.GraphListener listener) - Specified by:
addListener
in classorg.jenkinsci.plugins.workflow.flow.FlowExecution
-
removeListener
public void removeListener(org.jenkinsci.plugins.workflow.flow.GraphListener listener) - Overrides:
removeListener
in classorg.jenkinsci.plugins.workflow.flow.FlowExecution
-
interrupt
public void interrupt(Result result, CauseOfInterruption... causes) throws IOException, InterruptedException - Specified by:
interrupt
in classorg.jenkinsci.plugins.workflow.flow.FlowExecution
- Throws:
IOException
InterruptedException
-
getNode
- Specified by:
getNode
in classorg.jenkinsci.plugins.workflow.flow.FlowExecution
- Throws:
IOException
-
setResult
-
getResult
-
loadActions
public List<Action> loadActions(org.jenkinsci.plugins.workflow.graph.FlowNode node) throws IOException - Specified by:
loadActions
in interfaceorg.jenkinsci.plugins.workflow.graph.FlowActionStorage
- Throws:
IOException
-
saveActions
public void saveActions(org.jenkinsci.plugins.workflow.graph.FlowNode node, List<Action> actions) throws IOException - Specified by:
saveActions
in interfaceorg.jenkinsci.plugins.workflow.graph.FlowActionStorage
- Throws:
IOException
-
maybeAutoPersistNode
public static void maybeAutoPersistNode(@NonNull org.jenkinsci.plugins.workflow.graph.FlowNode node) Invoke me to toggle autopersist back on for steps that delay it. -
isComplete
public boolean isComplete()- Overrides:
isComplete
in classorg.jenkinsci.plugins.workflow.flow.FlowExecution
-
getAuthentication
- Specified by:
getAuthentication
in classorg.jenkinsci.plugins.workflow.flow.FlowExecution
-
getNextScriptName
@Restricted(org.kohsuke.accmod.restrictions.NoExternalUse.class) public String getNextScriptName(String path) Finds the expected next loaded script name, likeScript1
.- Parameters:
path
- a file path being loaded (currently ignored)
-
isDoneFlagSet
public 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()
andFlowExecution.isComplete()
) -
isPaused
public boolean isPaused() -
pause
Pause or unpause the execution.- Parameters:
v
- true to pause, false to unpause.- Throws:
IOException
-
toString
-
suspendAll
@Restricted(org.kohsuke.accmod.restrictions.DoNotUse.class) @Terminator(attains="FlowExecutionList.EXECUTIONS_SUSPENDED") public static void suspendAll()
-
SemaphoreStep
.