Reputation: 2264
I have a SWF workflow and activity. Below is structure:
WorkflowClientImpl Class:
class TempWorkflowImpl() {
@Override
public void execute() {
new TryCatchFinallly {
@Override
protected void doTry() throws Throwable {
activityClient.invoke();
}
@Override
protected void doFinally() throws Throwable {
// Clean up code
}
@Override
protected void doCatch() throws Throwable {
// Handle Exception
}
}
}
}
ActivityClientImpl Class:
class TempActivityImpl() {
@Override
public void invoke() {
// Perform some logic
// Check if API call (API_Call_A) is made previously
// If not Invoke API_Call_A.
// If yes, throw exception
}
}
The activity class makes an API call which an asynchronous method. The action defined in the API call takes approx an hour to complete. Sometimes the action can fail while it is executing due to certain reasons. This API call is defined on service that I do not have access to. Is there a way I can sleep the activity so that it can check after an hour whether the action was successful or not. If not successful, I would be re-invoking the API call. Let us assume that this time the action will succeed and we do not end up in an infinite loop of the API call attempts.
Thread.sleep()
appears to be one way, though I am not sure that is most appropriate way. I also found we can restart the entire workflow using
Promise<Void> timer = decisionContextProvider.getDecisionContext().getWorkflowClock().createTimer(TimeUnit.MINUTES.toSeconds(TimeinMinutes));
continueAsNew(timer);
To use the above, I can return from the activity method a value for TimeinMinutes
after API call and then restart the workflow after an hour.
Is the above approach most appropriate? Or is there a better way to do this?
Thanks
Upvotes: 0
Views: 537
Reputation: 6870
There is no need to call continueAsNew unless your workflow history is large (like after calling activity 100 times). Just use @Asynchronous method or Task to wait on promises. I would model your workflow as two activties: invoke and checkResult and execute checkResult after delay and use @ExponentialResult to retry it until result is available.
class TempWorkflowImpl() {
private final WorkflowClock clock = decisionContextProvider.getDecisionContext().getWorkflowClock()
@Override
public void execute() {
new TryCatchFinallly {
@Override
protected void doTry() throws Throwable {
invoke();
}
@Override
protected void doFinally() throws Throwable {
// Clean up code
}
@Override
protected void doCatch() throws Throwable {
// Handle Exception
}
}
}
@Asynchronous
// On ServiceFailureException retry from the beginning
@ExponentialRetry(initialRetryIntervalSeconds=300, exceptionsToRetry=ServiceFailureException.class)
private Promise<ResultType> invoke() {
Promise<Void> invoked = activityClient.invoke();
Promise<ResultType> result = checkResultAfterDelay(invoked);
processResult(result);
}
@Asynchronous
private Promise<ResultType> checkResultAfterDelay(Promise<Void> invoked) {
Promise<Void> timer = clock.createTimer(TimeUnit.MINUTES.toSeconds(60));
return checkResult(timer);
}
@Asynchronous
// Automatically retry on ResultUnavailableException
@ExponentialRetry(initialRetryIntervalSeconds=300, exceptionsToRetry=ResultUnavailableException.class)
private Promise<ResultType> checkResult(Promise<Void> timer) {
return activityClient.checkResult();
}
@Asynchronous
private processResult(Promise<ResultType> result) {
....
}
}
Upvotes: 1