Skip to content

Commit 2a65ac4

Browse files
authored
Added support for server side retry of workflows (#228)
* Removed minimum attempts to match thrift definition of RetryPolicy * Added RetryOptions to WorkflowOptions * Added workflow retry support to TestWorkflowService
1 parent 23fbcbd commit 2a65ac4

19 files changed

+703
-230
lines changed

src/main/java/com/uber/cadence/client/WorkflowOptions.java

Lines changed: 55 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,17 @@
2121

2222
import com.uber.cadence.ChildPolicy;
2323
import com.uber.cadence.WorkflowIdReusePolicy;
24+
import com.uber.cadence.common.MethodRetry;
25+
import com.uber.cadence.common.RetryOptions;
2426
import com.uber.cadence.internal.common.OptionsUtils;
2527
import com.uber.cadence.workflow.WorkflowMethod;
2628
import java.time.Duration;
29+
import java.util.Objects;
2730

2831
public final class WorkflowOptions {
2932

30-
public static WorkflowOptions merge(WorkflowMethod a, WorkflowOptions o) {
33+
public static WorkflowOptions merge(
34+
WorkflowMethod a, MethodRetry methodRetry, WorkflowOptions o) {
3135
if (a == null) {
3236
return new WorkflowOptions.Builder(o).validateBuildWithDefaults();
3337
}
@@ -48,6 +52,7 @@ public static WorkflowOptions merge(WorkflowMethod a, WorkflowOptions o) {
4852
a.executionStartToCloseTimeoutSeconds(), o.getExecutionStartToCloseTimeout()))
4953
.setTaskList(OptionsUtils.merge(a.taskList(), o.getTaskList(), String.class))
5054
.setChildPolicy(o.getChildPolicy())
55+
.setRetryOptions(RetryOptions.merge(methodRetry, o.getRetryOptions()))
5156
.validateBuildWithDefaults();
5257
}
5358

@@ -65,6 +70,8 @@ public static final class Builder {
6570

6671
private ChildPolicy childPolicy;
6772

73+
private RetryOptions retryOptions;
74+
6875
public Builder() {}
6976

7077
public Builder(WorkflowOptions o) {
@@ -77,6 +84,7 @@ public Builder(WorkflowOptions o) {
7784
this.executionStartToCloseTimeout = o.executionStartToCloseTimeout;
7885
this.taskList = o.taskList;
7986
this.childPolicy = o.childPolicy;
87+
this.retryOptions = o.retryOptions;
8088
}
8189

8290
/**
@@ -151,14 +159,20 @@ public Builder setChildPolicy(ChildPolicy childPolicy) {
151159
return this;
152160
}
153161

162+
public Builder setRetryOptions(RetryOptions retryOptions) {
163+
this.retryOptions = retryOptions;
164+
return this;
165+
}
166+
154167
public WorkflowOptions build() {
155168
return new WorkflowOptions(
156169
workflowId,
157170
workflowIdReusePolicy,
158171
executionStartToCloseTimeout,
159172
taskStartToCloseTimeout,
160173
taskList,
161-
childPolicy);
174+
childPolicy,
175+
retryOptions);
162176
}
163177

164178
/**
@@ -170,20 +184,31 @@ public WorkflowOptions validateBuildWithDefaults() {
170184
"Required property executionStartToCloseTimeout is not set");
171185
}
172186
if (taskList == null) {
173-
throw new IllegalStateException("Required property taskList is not set");
187+
throw new IllegalArgumentException("Required property taskList is not set");
174188
}
175189
WorkflowIdReusePolicy policy = workflowIdReusePolicy;
176190
if (policy == null) {
177191
policy = WorkflowIdReusePolicy.AllowDuplicateFailedOnly;
178192
}
193+
if (retryOptions != null) {
194+
if (retryOptions.getInitialInterval() == null) {
195+
throw new IllegalArgumentException(
196+
"RetryOptions missing required initialInterval property");
197+
}
198+
if (retryOptions.getExpiration() == null && retryOptions.getMaximumAttempts() == 0) {
199+
throw new IllegalArgumentException(
200+
"RetryOptions must specify either expiration or maximum attempts");
201+
}
202+
}
179203
return new WorkflowOptions(
180204
workflowId,
181205
policy,
182206
roundUpToSeconds(executionStartToCloseTimeout),
183207
roundUpToSeconds(
184208
taskStartToCloseTimeout, OptionsUtils.DEFAULT_TASK_START_TO_CLOSE_TIMEOUT),
185209
taskList,
186-
childPolicy);
210+
childPolicy,
211+
retryOptions);
187212
}
188213
}
189214

@@ -199,19 +224,23 @@ public WorkflowOptions validateBuildWithDefaults() {
199224

200225
private final ChildPolicy childPolicy;
201226

227+
private RetryOptions retryOptions;
228+
202229
private WorkflowOptions(
203230
String workflowId,
204231
WorkflowIdReusePolicy workflowIdReusePolicy,
205232
Duration executionStartToCloseTimeout,
206233
Duration taskStartToCloseTimeout,
207234
String taskList,
208-
ChildPolicy childPolicy) {
235+
ChildPolicy childPolicy,
236+
RetryOptions retryOptions) {
209237
this.workflowId = workflowId;
210238
this.workflowIdReusePolicy = workflowIdReusePolicy;
211239
this.executionStartToCloseTimeout = executionStartToCloseTimeout;
212240
this.taskStartToCloseTimeout = taskStartToCloseTimeout;
213241
this.taskList = taskList;
214242
this.childPolicy = childPolicy;
243+
this.retryOptions = retryOptions;
215244
}
216245

217246
public String getWorkflowId() {
@@ -238,38 +267,34 @@ public ChildPolicy getChildPolicy() {
238267
return childPolicy;
239268
}
240269

270+
public RetryOptions getRetryOptions() {
271+
return retryOptions;
272+
}
273+
241274
@Override
242275
public boolean equals(Object o) {
243276
if (this == o) return true;
244277
if (o == null || getClass() != o.getClass()) return false;
245-
246278
WorkflowOptions that = (WorkflowOptions) o;
247-
248-
if (workflowId != null ? !workflowId.equals(that.workflowId) : that.workflowId != null)
249-
return false;
250-
if (workflowIdReusePolicy != that.workflowIdReusePolicy) return false;
251-
if (executionStartToCloseTimeout != null
252-
? !executionStartToCloseTimeout.equals(that.executionStartToCloseTimeout)
253-
: that.executionStartToCloseTimeout != null) return false;
254-
if (taskStartToCloseTimeout != null
255-
? !taskStartToCloseTimeout.equals(that.taskStartToCloseTimeout)
256-
: that.taskStartToCloseTimeout != null) return false;
257-
if (taskList != null ? !taskList.equals(that.taskList) : that.taskList != null) return false;
258-
return childPolicy == that.childPolicy;
279+
return Objects.equals(workflowId, that.workflowId)
280+
&& workflowIdReusePolicy == that.workflowIdReusePolicy
281+
&& Objects.equals(executionStartToCloseTimeout, that.executionStartToCloseTimeout)
282+
&& Objects.equals(taskStartToCloseTimeout, that.taskStartToCloseTimeout)
283+
&& Objects.equals(taskList, that.taskList)
284+
&& childPolicy == that.childPolicy
285+
&& Objects.equals(retryOptions, that.retryOptions);
259286
}
260287

261288
@Override
262289
public int hashCode() {
263-
int result = workflowId != null ? workflowId.hashCode() : 0;
264-
result = 31 * result + (workflowIdReusePolicy != null ? workflowIdReusePolicy.hashCode() : 0);
265-
result =
266-
31 * result
267-
+ (executionStartToCloseTimeout != null ? executionStartToCloseTimeout.hashCode() : 0);
268-
result =
269-
31 * result + (taskStartToCloseTimeout != null ? taskStartToCloseTimeout.hashCode() : 0);
270-
result = 31 * result + (taskList != null ? taskList.hashCode() : 0);
271-
result = 31 * result + (childPolicy != null ? childPolicy.hashCode() : 0);
272-
return result;
290+
return Objects.hash(
291+
workflowId,
292+
workflowIdReusePolicy,
293+
executionStartToCloseTimeout,
294+
taskStartToCloseTimeout,
295+
taskList,
296+
childPolicy,
297+
retryOptions);
273298
}
274299

275300
@Override
@@ -289,6 +314,8 @@ public String toString() {
289314
+ '\''
290315
+ ", childPolicy="
291316
+ childPolicy
317+
+ ", retryOptions="
318+
+ retryOptions
292319
+ '}';
293320
}
294321
}

src/main/java/com/uber/cadence/common/MethodRetry.java

Lines changed: 6 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -37,15 +37,16 @@
3737
public @interface MethodRetry {
3838

3939
/**
40-
* Interval of the first retry. If coefficient is 1.0 then it is used for all retries. Required.
41-
* Can be overridden through {@link
40+
* Interval of the first retry. If coefficient is 1.0 then it is used for all retries. If not
41+
* specified here must be provided through {@link
4242
* com.uber.cadence.common.RetryOptions.Builder#setInitialInterval(Duration)}.
4343
*/
44-
long initialIntervalSeconds();
44+
long initialIntervalSeconds() default 0;
4545

4646
/**
47-
* Maximum time to retry. Default is forever. When exceeded the retries stop even if maximum
48-
* retries is not reached yet.
47+
* Maximum time to retry. When exceeded the retries stop even if maximum retries is not reached
48+
* yet. If not specified here must be provided through {@link
49+
* com.uber.cadence.common.RetryOptions.Builder#setExpiration(Duration)}.
4950
*/
5051
long expirationSeconds() default 0;
5152

@@ -61,12 +62,6 @@
6162
*/
6263
int maximumAttempts() default 0;
6364

64-
/**
65-
* Minimum number of retries. Even if expired will retry until this number is reached. Must be 1
66-
* or bigger. Default is 0.
67-
*/
68-
int minimumAttempts() default 0;
69-
7065
/**
7166
* Maximum interval between retries. Exponential backoff leads to interval increase. This value is
7267
* the cap of the increase. Default is 100x {@link #initialIntervalSeconds()}.

0 commit comments

Comments
 (0)