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
Nested Classes Modifier and Type Class Description static class
CpsFlowExecution.ConverterImpl
static class
CpsFlowExecution.PipelineInternalCalls
static class
CpsFlowExecution.PipelineTimings
-
Field Summary
Fields Modifier and Type Field Description static boolean
OPTIMIZE_STORAGE_UPON_COMPLETION
Iftrue
, then when the execution completes, we migrate the flow node storage fromSimpleXStreamFlowNodeStorage
toBulkFlowNodeStorage
.com.google.common.util.concurrent.ListenableFuture<CpsThreadGroup>
programPromise
Loading of the program is asynchronous because it requires us to re-obtain stateful objects.
-
Constructor Summary
Constructors Constructor 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.
-
Method Summary
All Methods Static Methods Instance Methods Concrete Methods Deprecated Methods Modifier and Type Method Description void
addListener(org.jenkinsci.plugins.workflow.flow.GraphListener listener)
protected void
afterStepExecutionsResumed()
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.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, likeScript1
.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()
andFlowExecution.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)
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
setResult(Result v)
void
setResumeBlocked(boolean resumeBlocked)
void
start()
static void
suspendAll()
String
toString()
void
waitForSuspension()
Deprecated.Use some other idiom, likeSemaphoreStep
.
-
-
-
Field Detail
-
OPTIMIZE_STORAGE_UPON_COMPLETION
public static boolean OPTIMIZE_STORAGE_UPON_COMPLETION
Iftrue
, then when the execution completes, we migrate the flow node storage fromSimpleXStreamFlowNodeStorage
toBulkFlowNodeStorage
.
-
programPromise
public transient volatile com.google.common.util.concurrent.ListenableFuture<CpsThreadGroup> programPromise
Loading 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 Detail
-
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 Detail
-
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
public String getScript()
-
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
public File getStorageDir() throws IOException
Directory where workflow stores its state.- Throws:
IOException
-
start
public void start() throws IOException
- Specified by:
start
in classorg.jenkinsci.plugins.workflow.flow.FlowExecution
- Throws:
IOException
-
iotaStr
@Restricted(org.kohsuke.accmod.restrictions.NoExternalUse.class) public String iotaStr()
Assigns a new ID.
-
iota
@Restricted(org.kohsuke.accmod.restrictions.NoExternalUse.class) public int iota()
-
initializeStorage
protected void initializeStorage() throws IOException
- 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
public void onLoad(org.jenkinsci.plugins.workflow.flow.FlowExecutionOwner owner) throws IOException
- Overrides:
onLoad
in classorg.jenkinsci.plugins.workflow.flow.FlowExecution
- Throws:
IOException
-
loadProgramAsync
public void loadProgramAsync(File programDataFile)
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 public void waitForSuspension() throws InterruptedException, ExecutionException
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
public List<org.jenkinsci.plugins.workflow.graph.FlowNode> 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
public CpsThreadDump 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
public org.jenkinsci.plugins.workflow.graph.FlowNode getNode(String id) throws IOException
- Specified by:
getNode
in classorg.jenkinsci.plugins.workflow.flow.FlowExecution
- Throws:
IOException
-
setResult
public void setResult(Result v)
-
getResult
public Result 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
public Authentication 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
public void pause(boolean v) throws IOException
Pause or unpause the execution.- Parameters:
v
- true to pause, false to unpause.- Throws:
IOException
-
suspendAll
@Restricted(org.kohsuke.accmod.restrictions.DoNotUse.class) @Terminator(attains="FlowExecutionList.EXECUTIONS_SUSPENDED") public static void suspendAll()
-
-