Skip to content

Commit b9351b2

Browse files
fjtiradoCopilot
andauthored
[Fix_#1198] Fix exception propagation (#1204)
* [Fix_#1198] Fix exception propagation Fixes #1198 Signed-off-by: fjtirado <ftirados@redhat.com> * [Fix #1198] Fixing details comparison typo Signed-off-by: fjtirado <ftirados@redhat.com> * [Fix #1198] Adding error variable Signed-off-by: fjtirado <ftirados@redhat.com> * [Fix #1198] Copilot comments Signed-off-by: fjtirado <ftirados@redhat.com> Update impl/test/src/test/resources/workflows-samples/try-catch-not-match-details.yaml Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Update impl/test/src/test/resources/workflows-samples/try-catch-match-status.yaml Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Update impl/test/src/test/resources/workflows-samples/try-catch-match-details.yaml Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Update impl/test/src/test/java/io/serverlessworkflow/impl/test/RetryTimeoutTest.java Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Update impl/test/src/test/resources/workflows-samples/try-catch-error-variable.yaml Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --------- Signed-off-by: fjtirado <ftirados@redhat.com> Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
1 parent 60a4ff4 commit b9351b2

File tree

12 files changed

+241
-28
lines changed

12 files changed

+241
-28
lines changed

impl/core/src/main/java/io/serverlessworkflow/impl/executors/RaiseExecutor.java

Lines changed: 30 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,9 @@
1616
package io.serverlessworkflow.impl.executors;
1717

1818
import io.serverlessworkflow.api.types.Error;
19+
import io.serverlessworkflow.api.types.ErrorDetails;
1920
import io.serverlessworkflow.api.types.ErrorInstance;
21+
import io.serverlessworkflow.api.types.ErrorTitle;
2022
import io.serverlessworkflow.api.types.ErrorType;
2123
import io.serverlessworkflow.api.types.RaiseTask;
2224
import io.serverlessworkflow.api.types.RaiseTaskError;
@@ -25,6 +27,7 @@
2527
import io.serverlessworkflow.impl.WorkflowContext;
2628
import io.serverlessworkflow.impl.WorkflowDefinition;
2729
import io.serverlessworkflow.impl.WorkflowError;
30+
import io.serverlessworkflow.impl.WorkflowError.Builder;
2831
import io.serverlessworkflow.impl.WorkflowException;
2932
import io.serverlessworkflow.impl.WorkflowModel;
3033
import io.serverlessworkflow.impl.WorkflowMutablePosition;
@@ -44,8 +47,8 @@ public static class RaiseExecutorBuilder extends RegularTaskExecutorBuilder<Rais
4447
private final BiFunction<WorkflowContext, TaskContext, WorkflowError> errorBuilder;
4548
private final WorkflowValueResolver<String> typeFilter;
4649
private final Optional<WorkflowValueResolver<String>> instanceFilter;
47-
private final WorkflowValueResolver<String> titleFilter;
48-
private final WorkflowValueResolver<String> detailFilter;
50+
private final Optional<WorkflowValueResolver<String>> titleFilter;
51+
private final Optional<WorkflowValueResolver<String>> detailFilter;
4952

5053
protected RaiseExecutorBuilder(
5154
WorkflowMutablePosition position, RaiseTask task, WorkflowDefinition definition) {
@@ -57,30 +60,38 @@ protected RaiseExecutorBuilder(
5760
: findError(raiseError.getRaiseErrorReference());
5861
this.typeFilter = getTypeFunction(application, error.getType());
5962
this.instanceFilter = getInstanceFunction(application, error.getInstance());
63+
ErrorTitle title = error.getTitle();
6064
this.titleFilter =
61-
WorkflowUtils.buildStringFilter(
62-
application,
63-
error.getTitle().getExpressionErrorTitle(),
64-
error.getTitle().getLiteralErrorTitle());
65+
title == null
66+
? Optional.empty()
67+
: Optional.of(
68+
WorkflowUtils.buildStringFilter(
69+
application, title.getExpressionErrorTitle(), title.getLiteralErrorTitle()));
70+
ErrorDetails details = error.getDetail();
6571
this.detailFilter =
66-
WorkflowUtils.buildStringFilter(
67-
application,
68-
error.getDetail().getExpressionErrorDetails(),
69-
error.getTitle().getExpressionErrorTitle());
72+
details == null
73+
? Optional.empty()
74+
: Optional.of(
75+
WorkflowUtils.buildStringFilter(
76+
application,
77+
details.getExpressionErrorDetails(),
78+
details.getLiteralErrorDetails()));
7079
this.errorBuilder = (w, t) -> buildError(error, w, t);
7180
}
7281

7382
private WorkflowError buildError(
7483
Error error, WorkflowContext context, TaskContext taskContext) {
75-
return WorkflowError.error(
76-
typeFilter.apply(context, taskContext, taskContext.input()), error.getStatus())
77-
.instance(
78-
instanceFilter
79-
.map(f -> f.apply(context, taskContext, taskContext.input()))
80-
.orElseGet(() -> taskContext.position().jsonPointer()))
81-
.title(titleFilter.apply(context, taskContext, taskContext.input()))
82-
.details(detailFilter.apply(context, taskContext, taskContext.input()))
83-
.build();
84+
Builder builder =
85+
WorkflowError.error(
86+
typeFilter.apply(context, taskContext, taskContext.input()), error.getStatus())
87+
.instance(
88+
instanceFilter
89+
.map(f -> f.apply(context, taskContext, taskContext.input()))
90+
.orElseGet(() -> taskContext.position().jsonPointer()));
91+
titleFilter.ifPresent(f -> builder.title(f.apply(context, taskContext, taskContext.input())));
92+
detailFilter.ifPresent(
93+
f -> builder.details(f.apply(context, taskContext, taskContext.input())));
94+
return builder.build();
8495
}
8596

8697
private Optional<WorkflowValueResolver<String>> getInstanceFunction(

impl/core/src/main/java/io/serverlessworkflow/impl/executors/TryExecutor.java

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ public class TryExecutor extends RegularTaskExecutor<TryTask> {
5252
private final TaskExecutor<?> taskExecutor;
5353
private final Optional<TaskExecutor<?>> catchTaskExecutor;
5454
private final Optional<RetryExecutor> retryIntervalExecutor;
55+
private final String errorVariable;
5556

5657
public static class TryExecutorBuilder extends RegularTaskExecutorBuilder<TryTask> {
5758

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

6567
protected TryExecutorBuilder(
6668
WorkflowMutablePosition position, TryTask task, WorkflowDefinition definition) {
@@ -73,8 +75,8 @@ protected TryExecutorBuilder(
7375
TaskExecutorHelper.createExecutorList(position, task.getTry(), definition);
7476
TryTaskCatch catchTask = task.getCatch();
7577
if (catchTask != null) {
78+
this.errorVariable = catchTask.getAs();
7679
List<TaskItem> catchTaskDo = catchTask.getDo();
77-
7880
this.catchTaskExecutor =
7981
catchTaskDo != null && !catchTaskDo.isEmpty()
8082
? Optional.of(
@@ -144,6 +146,7 @@ protected TryExecutor(TryExecutorBuilder builder) {
144146
this.taskExecutor = builder.taskExecutor;
145147
this.catchTaskExecutor = builder.catchTaskExecutor;
146148
this.retryIntervalExecutor = builder.retryIntervalExecutor;
149+
this.errorVariable = builder.errorVariable;
147150
}
148151

149152
@Override
@@ -168,9 +171,17 @@ private CompletableFuture<WorkflowModel> handleException(
168171
WorkflowException exception = (WorkflowException) e;
169172
CompletableFuture<WorkflowModel> completable =
170173
CompletableFuture.completedFuture(taskContext.rawOutput());
171-
if (errorFilter.map(f -> f.test(exception.getWorkflowError())).orElse(true)
174+
WorkflowError error = exception.getWorkflowError();
175+
if (errorFilter.map(f -> f.test(error)).orElse(true)
172176
&& WorkflowUtils.whenExceptTest(
173-
whenFilter, exceptFilter, workflow, taskContext, taskContext.rawOutput())) {
177+
whenFilter,
178+
exceptFilter,
179+
workflow,
180+
taskContext,
181+
workflow.definition().application().modelFactory().fromAny(error))) {
182+
if (errorVariable != null) {
183+
taskContext.variables().put(errorVariable, error);
184+
}
174185
if (catchTaskExecutor.isPresent()) {
175186
completable =
176187
completable.thenCompose(
@@ -189,11 +200,10 @@ private CompletableFuture<WorkflowModel> handleException(
189200
.orElse(CompletableFuture.failedFuture(e)))
190201
.thenCompose(model -> doIt(workflow, taskContext, model));
191202
}
203+
return completable;
192204
}
193-
return completable;
194-
} else {
195-
return CompletableFuture.failedFuture(e);
196205
}
206+
return CompletableFuture.failedFuture(e);
197207
}
198208

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

213223
private static boolean compareString(String one, String other) {

impl/test/src/test/java/io/serverlessworkflow/impl/test/RetryTimeoutTest.java

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,4 +121,54 @@ void testTimeout() throws IOException {
121121
.orElseThrow();
122122
assertThat(result.get("message")).isEqualTo("Viva er Beti Balompie");
123123
}
124+
125+
@ParameterizedTest
126+
@ValueSource(
127+
strings = {
128+
"workflows-samples/try-catch-match-when.yaml",
129+
"workflows-samples/try-catch-match-status.yaml",
130+
"workflows-samples/try-catch-match-details.yaml"
131+
})
132+
void testDoesMatch(String path) throws IOException {
133+
assertThat(
134+
app.workflowDefinition(readWorkflowFromClasspath(path))
135+
.instance(Map.of())
136+
.start()
137+
.join()
138+
.asMap()
139+
.map(m -> m.get("recovered"))
140+
.orElseThrow())
141+
.isEqualTo(true);
142+
}
143+
144+
@ParameterizedTest
145+
@ValueSource(
146+
strings = {
147+
"workflows-samples/try-catch-not-match-when.yaml",
148+
"workflows-samples/try-catch-not-match-status.yaml",
149+
"workflows-samples/try-catch-not-match-details.yaml"
150+
})
151+
void testDoesNotMatch(String path) {
152+
assertThatThrownBy(
153+
() ->
154+
app.workflowDefinition(readWorkflowFromClasspath(path))
155+
.instance(Map.of())
156+
.start()
157+
.join())
158+
.hasCauseInstanceOf(WorkflowException.class);
159+
}
160+
161+
@Test
162+
void testErrorVariable() throws IOException {
163+
assertThat(
164+
app.workflowDefinition(
165+
readWorkflowFromClasspath("workflows-samples/try-catch-error-variable.yaml"))
166+
.instance(Map.of())
167+
.start()
168+
.join()
169+
.asMap()
170+
.map(m -> m.get("errorMessage"))
171+
.orElseThrow())
172+
.isEqualTo("Javierito was here!");
173+
}
124174
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
document:
2+
dsl: '1.0.0'
3+
namespace: test
4+
name: try-catch-error-variable
5+
version: '0.1.0'
6+
do:
7+
- attemptTask:
8+
try:
9+
- failingTask:
10+
raise:
11+
error:
12+
type: https://example.com/errors/transient
13+
detail: Javierito was here!
14+
status: 503
15+
catch:
16+
as: caughtError
17+
do:
18+
- handleError:
19+
set:
20+
errorMessage: ${$caughtError.details}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
document:
2+
dsl: '1.0.0'
3+
namespace: test
4+
name: try-catch-match-details
5+
version: '0.1.0'
6+
do:
7+
- attemptTask:
8+
try:
9+
- failingTask:
10+
raise:
11+
error:
12+
type: https://example.com/errors/transient
13+
status: 503
14+
detail: Enforcement Failure - invalid email
15+
catch:
16+
errors:
17+
with:
18+
type: https://example.com/errors/transient
19+
status: 503
20+
details: Enforcement Failure - invalid email
21+
do:
22+
- handleError:
23+
set:
24+
recovered: true
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
document:
2+
dsl: '1.0.0'
3+
namespace: test
4+
name: try-catch-match-status
5+
version: '0.1.0'
6+
do:
7+
- attemptTask:
8+
try:
9+
- failingTask:
10+
raise:
11+
error:
12+
type: https://example.com/errors/transient
13+
status: 503
14+
catch:
15+
errors:
16+
with:
17+
type: https://example.com/errors/transient
18+
status: 503
19+
do:
20+
- handleError:
21+
set:
22+
recovered: true
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
document:
2+
dsl: '1.0.0'
3+
namespace: test
4+
name: try-catch-match-when
5+
version: '0.1.0'
6+
do:
7+
- attemptTask:
8+
try:
9+
- failingTask:
10+
raise:
11+
error:
12+
type: https://example.com/errors/transient
13+
status: 503
14+
catch:
15+
when: ${ .status == 503 }
16+
do:
17+
- handleError:
18+
set:
19+
recovered: true
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
document:
2+
dsl: '1.0.0'
3+
namespace: test
4+
name: try-catch-not-match-details
5+
version: '0.1.0'
6+
do:
7+
- attemptTask:
8+
try:
9+
- failingTask:
10+
raise:
11+
error:
12+
type: https://example.com/errors/security
13+
status: 403
14+
detail: Enforcement Failure - invalid email
15+
catch:
16+
errors:
17+
with:
18+
type: https://example.com/errors/security
19+
status: 403
20+
details: User not found in tenant catalog
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
document:
2+
dsl: '1.0.0'
3+
namespace: test
4+
name: try-catch-not-match-status
5+
version: '0.1.0'
6+
do:
7+
- attemptTask:
8+
try:
9+
- failingTask:
10+
raise:
11+
error:
12+
type: https://example.com/errors/transient
13+
status: 503
14+
catch:
15+
errors:
16+
with:
17+
type: https://example.com/errors/transient
18+
status: 403
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
document:
2+
dsl: '1.0.0'
3+
namespace: test
4+
name: try-catch-not-match-when
5+
version: '0.1.0'
6+
do:
7+
- attemptTask:
8+
try:
9+
- failingTask:
10+
raise:
11+
error:
12+
type: https://example.com/errors/transient
13+
status: 503
14+
catch:
15+
when: ${ .status == 400 }
16+
do:
17+
- handleError:
18+
set:
19+
recovered: true

0 commit comments

Comments
 (0)