-
Notifications
You must be signed in to change notification settings - Fork 128
/
RetryStepExecution.java
99 lines (84 loc) · 3.19 KB
/
RetryStepExecution.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
package org.jenkinsci.plugins.workflow.steps;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import hudson.AbortException;
import hudson.model.Run;
import hudson.model.TaskListener;
import jenkins.model.CauseOfInterruption;
import jenkins.model.InterruptedBuildAction;
/**
* @author Kohsuke Kawaguchi
*/
public class RetryStepExecution extends AbstractStepExecutionImpl {
@SuppressFBWarnings(value="SE_TRANSIENT_FIELD_NOT_RESTORED", justification="Only used when starting.")
private transient final int count;
private volatile BodyExecution body;
RetryStepExecution(int count, StepContext context) {
super(context);
this.count = count;
}
@Override
public boolean start() throws Exception {
StepContext context = getContext();
body = context.newBodyInvoker()
.withCallback(new Callback(count))
.start();
return false; // execution is asynchronous
}
@Override
public void stop(Throwable cause) throws Exception {
if (body!=null)
body.cancel(cause);
}
@Override public void onResume() {}
private static class Callback extends BodyExecutionCallback {
private int left;
Callback(int count) {
left = count;
}
/* Could be added, but seems unnecessary, given the message already printed in onFailure:
@Override public void onStart(StepContext context) {
try {
context.get(TaskListener.class).getLogger().println(left + " tries left");
} catch (Exception x) {
context.onFailure(x);
}
}
*/
@Override
public void onSuccess(StepContext context, Object result) {
context.onSuccess(result);
}
@Override
public void onFailure(StepContext context, Throwable t) {
try {
Run run = context.get(Run.class);
if (run != null && t instanceof FlowInterruptedException) {
for (CauseOfInterruption cause : ((FlowInterruptedException) t).getCauses()) {
if (cause instanceof CauseOfInterruption.UserInterruption) {
context.onFailure(t);
return;
}
}
}
left--;
if (left>0) {
TaskListener l = context.get(TaskListener.class);
if (t instanceof AbortException) {
l.error(t.getMessage());
} else {
t.printStackTrace(l.error("Execution failed"));
}
l.getLogger().println("Retrying");
context.newBodyInvoker().withCallback(this).start();
} else {
// No need to print anything in this case, since it will be thrown up anyway.
context.onFailure(t);
}
} catch (Throwable p) {
context.onFailure(p);
}
}
private static final long serialVersionUID = 1L;
}
private static final long serialVersionUID = 1L;
}