Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,9 @@
package io.serverlessworkflow.impl.executors;

import io.serverlessworkflow.api.types.Error;
import io.serverlessworkflow.api.types.ErrorDetails;
import io.serverlessworkflow.api.types.ErrorInstance;
import io.serverlessworkflow.api.types.ErrorTitle;
import io.serverlessworkflow.api.types.ErrorType;
import io.serverlessworkflow.api.types.RaiseTask;
import io.serverlessworkflow.api.types.RaiseTaskError;
Expand All @@ -25,6 +27,7 @@
import io.serverlessworkflow.impl.WorkflowContext;
import io.serverlessworkflow.impl.WorkflowDefinition;
import io.serverlessworkflow.impl.WorkflowError;
import io.serverlessworkflow.impl.WorkflowError.Builder;
import io.serverlessworkflow.impl.WorkflowException;
import io.serverlessworkflow.impl.WorkflowModel;
import io.serverlessworkflow.impl.WorkflowMutablePosition;
Expand All @@ -44,8 +47,8 @@ public static class RaiseExecutorBuilder extends RegularTaskExecutorBuilder<Rais
private final BiFunction<WorkflowContext, TaskContext, WorkflowError> errorBuilder;
private final WorkflowValueResolver<String> typeFilter;
private final Optional<WorkflowValueResolver<String>> instanceFilter;
private final WorkflowValueResolver<String> titleFilter;
private final WorkflowValueResolver<String> detailFilter;
private final Optional<WorkflowValueResolver<String>> titleFilter;
private final Optional<WorkflowValueResolver<String>> detailFilter;

protected RaiseExecutorBuilder(
WorkflowMutablePosition position, RaiseTask task, WorkflowDefinition definition) {
Expand All @@ -57,30 +60,38 @@ protected RaiseExecutorBuilder(
: findError(raiseError.getRaiseErrorReference());
this.typeFilter = getTypeFunction(application, error.getType());
this.instanceFilter = getInstanceFunction(application, error.getInstance());
ErrorTitle title = error.getTitle();
this.titleFilter =
WorkflowUtils.buildStringFilter(
application,
error.getTitle().getExpressionErrorTitle(),
error.getTitle().getLiteralErrorTitle());
title == null
? Optional.empty()
: Optional.of(
WorkflowUtils.buildStringFilter(
application, title.getExpressionErrorTitle(), title.getLiteralErrorTitle()));
ErrorDetails details = error.getDetail();
this.detailFilter =
WorkflowUtils.buildStringFilter(
application,
error.getDetail().getExpressionErrorDetails(),
error.getTitle().getExpressionErrorTitle());
details == null
? Optional.empty()
: Optional.of(
WorkflowUtils.buildStringFilter(
application,
details.getExpressionErrorDetails(),
details.getLiteralErrorDetails()));
this.errorBuilder = (w, t) -> buildError(error, w, t);
}

private WorkflowError buildError(
Error error, WorkflowContext context, TaskContext taskContext) {
return WorkflowError.error(
typeFilter.apply(context, taskContext, taskContext.input()), error.getStatus())
.instance(
instanceFilter
.map(f -> f.apply(context, taskContext, taskContext.input()))
.orElseGet(() -> taskContext.position().jsonPointer()))
.title(titleFilter.apply(context, taskContext, taskContext.input()))
.details(detailFilter.apply(context, taskContext, taskContext.input()))
.build();
Builder builder =
WorkflowError.error(
typeFilter.apply(context, taskContext, taskContext.input()), error.getStatus())
.instance(
instanceFilter
.map(f -> f.apply(context, taskContext, taskContext.input()))
.orElseGet(() -> taskContext.position().jsonPointer()));
titleFilter.ifPresent(f -> builder.title(f.apply(context, taskContext, taskContext.input())));
detailFilter.ifPresent(
f -> builder.details(f.apply(context, taskContext, taskContext.input())));
return builder.build();
}

private Optional<WorkflowValueResolver<String>> getInstanceFunction(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ public class TryExecutor extends RegularTaskExecutor<TryTask> {
private final TaskExecutor<?> taskExecutor;
private final Optional<TaskExecutor<?>> catchTaskExecutor;
private final Optional<RetryExecutor> retryIntervalExecutor;
private final String errorVariable;

public static class TryExecutorBuilder extends RegularTaskExecutorBuilder<TryTask> {

Expand All @@ -61,6 +62,7 @@ public static class TryExecutorBuilder extends RegularTaskExecutorBuilder<TryTas
private final TaskExecutor<?> taskExecutor;
private final Optional<TaskExecutor<?>> catchTaskExecutor;
private final Optional<RetryExecutor> retryIntervalExecutor;
private String errorVariable;

protected TryExecutorBuilder(
WorkflowMutablePosition position, TryTask task, WorkflowDefinition definition) {
Expand All @@ -73,8 +75,8 @@ protected TryExecutorBuilder(
TaskExecutorHelper.createExecutorList(position, task.getTry(), definition);
TryTaskCatch catchTask = task.getCatch();
if (catchTask != null) {
this.errorVariable = catchTask.getAs();
List<TaskItem> catchTaskDo = catchTask.getDo();

this.catchTaskExecutor =
catchTaskDo != null && !catchTaskDo.isEmpty()
? Optional.of(
Expand Down Expand Up @@ -144,6 +146,7 @@ protected TryExecutor(TryExecutorBuilder builder) {
this.taskExecutor = builder.taskExecutor;
this.catchTaskExecutor = builder.catchTaskExecutor;
this.retryIntervalExecutor = builder.retryIntervalExecutor;
this.errorVariable = builder.errorVariable;
}

@Override
Expand All @@ -168,9 +171,17 @@ private CompletableFuture<WorkflowModel> handleException(
WorkflowException exception = (WorkflowException) e;
CompletableFuture<WorkflowModel> completable =
CompletableFuture.completedFuture(taskContext.rawOutput());
if (errorFilter.map(f -> f.test(exception.getWorkflowError())).orElse(true)
WorkflowError error = exception.getWorkflowError();
if (errorFilter.map(f -> f.test(error)).orElse(true)
&& WorkflowUtils.whenExceptTest(
whenFilter, exceptFilter, workflow, taskContext, taskContext.rawOutput())) {
whenFilter,
exceptFilter,
workflow,
taskContext,
workflow.definition().application().modelFactory().fromAny(error))) {
if (errorVariable != null) {
taskContext.variables().put(errorVariable, error);
}
if (catchTaskExecutor.isPresent()) {
completable =
completable.thenCompose(
Expand All @@ -189,11 +200,10 @@ private CompletableFuture<WorkflowModel> handleException(
.orElse(CompletableFuture.failedFuture(e)))
.thenCompose(model -> doIt(workflow, taskContext, model));
}
return completable;
}
return completable;
} else {
return CompletableFuture.failedFuture(e);
}
return CompletableFuture.failedFuture(e);
}

private static Optional<Predicate<WorkflowError>> buildErrorFilter(CatchErrors errors) {
Expand All @@ -207,7 +217,7 @@ private static boolean filterError(WorkflowError error, ErrorFilter errorFilter)
&& (errorFilter.getStatus() <= 0 || error.status() == errorFilter.getStatus())
&& compareString(errorFilter.getInstance(), error.instance())
&& compareString(errorFilter.getTitle(), error.title())
&& compareString(errorFilter.getDetails(), errorFilter.getDetails());
&& compareString(errorFilter.getDetails(), error.details());
}

private static boolean compareString(String one, String other) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -121,4 +121,54 @@ void testTimeout() throws IOException {
.orElseThrow();
assertThat(result.get("message")).isEqualTo("Viva er Beti Balompie");
}

@ParameterizedTest
@ValueSource(
strings = {
"workflows-samples/try-catch-match-when.yaml",
"workflows-samples/try-catch-match-status.yaml",
"workflows-samples/try-catch-match-details.yaml"
})
void testDoesMatch(String path) throws IOException {
assertThat(
app.workflowDefinition(readWorkflowFromClasspath(path))
.instance(Map.of())
.start()
.join()
.asMap()
.map(m -> m.get("recovered"))
.orElseThrow())
.isEqualTo(true);
}

@ParameterizedTest
@ValueSource(
strings = {
"workflows-samples/try-catch-not-match-when.yaml",
"workflows-samples/try-catch-not-match-status.yaml",
"workflows-samples/try-catch-not-match-details.yaml"
})
void testDoesNotMatch(String path) {
assertThatThrownBy(
() ->
app.workflowDefinition(readWorkflowFromClasspath(path))
.instance(Map.of())
.start()
.join())
.hasCauseInstanceOf(WorkflowException.class);
}

@Test
void testErrorVariable() throws IOException {
assertThat(
app.workflowDefinition(
readWorkflowFromClasspath("workflows-samples/try-catch-error-variable.yaml"))
.instance(Map.of())
.start()
.join()
.asMap()
.map(m -> m.get("errorMessage"))
.orElseThrow())
.isEqualTo("Javierito was here!");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
document:
dsl: '1.0.0'
namespace: test
name: try-catch-error-variable
version: '0.1.0'
do:
- attemptTask:
try:
- failingTask:
raise:
error:
type: https://example.com/errors/transient
detail: Javierito was here!
status: 503
catch:
as: caughtError
do:
- handleError:
set:
errorMessage: ${$caughtError.details}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
document:
dsl: '1.0.0'
namespace: test
name: try-catch-match-details
version: '0.1.0'
do:
- attemptTask:
try:
- failingTask:
raise:
error:
type: https://example.com/errors/transient
status: 503
detail: Enforcement Failure - invalid email
catch:
errors:
with:
type: https://example.com/errors/transient
status: 503
details: Enforcement Failure - invalid email
do:
- handleError:
set:
recovered: true
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
document:
dsl: '1.0.0'
namespace: test
name: try-catch-match-status
version: '0.1.0'
do:
- attemptTask:
try:
- failingTask:
raise:
error:
type: https://example.com/errors/transient
status: 503
catch:
errors:
with:
type: https://example.com/errors/transient
status: 503
do:
- handleError:
set:
recovered: true
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
document:
dsl: '1.0.0'
namespace: test
name: try-catch-match-when
version: '0.1.0'
do:
- attemptTask:
try:
- failingTask:
raise:
error:
type: https://example.com/errors/transient
status: 503
catch:
when: ${ .status == 503 }
do:
- handleError:
set:
recovered: true
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
document:
dsl: '1.0.0'
namespace: test
name: try-catch-not-match-details
version: '0.1.0'
do:
- attemptTask:
try:
- failingTask:
raise:
error:
type: https://example.com/errors/security
status: 403
detail: Enforcement Failure - invalid email
catch:
errors:
with:
type: https://example.com/errors/security
status: 403
details: User not found in tenant catalog
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
document:
dsl: '1.0.0'
namespace: test
name: try-catch-not-match-status
version: '0.1.0'
do:
- attemptTask:
try:
- failingTask:
raise:
error:
type: https://example.com/errors/transient
status: 503
catch:
errors:
with:
type: https://example.com/errors/transient
status: 403
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
document:
dsl: '1.0.0'
namespace: test
name: try-catch-not-match-when
version: '0.1.0'
do:
- attemptTask:
try:
- failingTask:
raise:
error:
type: https://example.com/errors/transient
status: 503
catch:
when: ${ .status == 400 }
do:
- handleError:
set:
recovered: true
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
document:
dsl: '1.0.0'
namespace: default
namespace: test
name: try-catch-retry-inline
version: '0.1.0'
do:
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
document:
dsl: '1.0.0'
namespace: default
namespace: test
name: try-catch-retry-reusable
version: '0.1.0'
use:
Expand Down