Skip to content

Commit 8ee3300

Browse files
author
Tihomir Surdilovic
authored
Merge pull request #21 from tsurdilo/errorhandlingupdate2
Error Handling updates
2 parents e29d8ee + 6a8a8cc commit 8ee3300

28 files changed

+302
-75
lines changed
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
/*
2+
* Copyright 2020-Present The Serverless Workflow Specification Authors
3+
* <p>
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
* <p>
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
* <p>
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*
16+
*/
17+
package io.serverlessworkflow.api.deserializers;
18+
19+
import com.fasterxml.jackson.core.JsonParser;
20+
import com.fasterxml.jackson.databind.DeserializationContext;
21+
import com.fasterxml.jackson.databind.JsonNode;
22+
import com.fasterxml.jackson.databind.ObjectMapper;
23+
import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
24+
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
25+
import io.serverlessworkflow.api.interfaces.WorkflowPropertySource;
26+
import io.serverlessworkflow.api.retry.RetryDefinition;
27+
import io.serverlessworkflow.api.utils.Utils;
28+
import io.serverlessworkflow.api.workflow.Retries;
29+
import org.json.JSONObject;
30+
import org.slf4j.Logger;
31+
import org.slf4j.LoggerFactory;
32+
33+
import java.io.IOException;
34+
import java.util.ArrayList;
35+
import java.util.List;
36+
37+
public class RetriesDeserializer extends StdDeserializer<Retries> {
38+
39+
private static final long serialVersionUID = 510l;
40+
private static Logger logger = LoggerFactory.getLogger(RetriesDeserializer.class);
41+
42+
private WorkflowPropertySource context;
43+
44+
public RetriesDeserializer() {
45+
this(Retries.class);
46+
}
47+
48+
public RetriesDeserializer(Class<?> vc) {
49+
super(vc);
50+
}
51+
52+
public RetriesDeserializer(WorkflowPropertySource context) {
53+
this(Retries.class);
54+
this.context = context;
55+
}
56+
57+
@Override
58+
public Retries deserialize(JsonParser jp,
59+
DeserializationContext ctxt) throws IOException {
60+
61+
ObjectMapper mapper = (ObjectMapper) jp.getCodec();
62+
JsonNode node = jp.getCodec().readTree(jp);
63+
64+
Retries retries = new Retries();
65+
List<RetryDefinition> retryDefinitions = new ArrayList<>();
66+
67+
if (node.isArray()) {
68+
for (final JsonNode nodeEle : node) {
69+
retryDefinitions.add(mapper.treeToValue(nodeEle, RetryDefinition.class));
70+
}
71+
} else {
72+
String retriesFileDef = node.asText();
73+
String retriesFileSrc = Utils.getResourceFileAsString(retriesFileDef);
74+
JsonNode retriesRefNode;
75+
ObjectMapper jsonWriter = new ObjectMapper();
76+
if (retriesFileSrc != null && retriesFileSrc.trim().length() > 0) {
77+
// if its a yaml def convert to json first
78+
if (!retriesFileSrc.trim().startsWith("{")) {
79+
// convert yaml to json to validate
80+
ObjectMapper yamlReader = new ObjectMapper(new YAMLFactory());
81+
Object obj = yamlReader.readValue(retriesFileSrc, Object.class);
82+
83+
retriesRefNode = jsonWriter.readTree(new JSONObject(jsonWriter.writeValueAsString(obj)).toString());
84+
} else {
85+
retriesRefNode = jsonWriter.readTree(new JSONObject(retriesFileSrc).toString());
86+
}
87+
88+
JsonNode refRetries = retriesRefNode.get("retries");
89+
if (refRetries != null) {
90+
for (final JsonNode nodeEle : refRetries) {
91+
retryDefinitions.add(mapper.treeToValue(nodeEle, RetryDefinition.class));
92+
}
93+
} else {
94+
logger.error("Unable to find retries definitions in reference file: {}", retriesFileSrc);
95+
}
96+
97+
} else {
98+
logger.error("Unable to load retries defs reference file: {}", retriesFileSrc);
99+
}
100+
101+
}
102+
retries.setRetryDefs(retryDefinitions);
103+
return retries;
104+
105+
}
106+
}

api/src/main/java/io/serverlessworkflow/api/interfaces/State.java

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@
1919
import io.serverlessworkflow.api.end.End;
2020
import io.serverlessworkflow.api.error.Error;
2121
import io.serverlessworkflow.api.filters.StateDataFilter;
22-
import io.serverlessworkflow.api.retry.Retry;
2322
import io.serverlessworkflow.api.start.Start;
2423
import io.serverlessworkflow.api.states.DefaultState.Type;
2524
import io.serverlessworkflow.api.transitions.Transition;
@@ -47,9 +46,7 @@ public interface State {
4746

4847
Transition getTransition();
4948

50-
List<Error> getOnError();
51-
52-
List<Retry> getRetry();
49+
List<Error> getOnErrors();
5350

5451
Map<String, String> getMetadata();
5552
}

api/src/main/java/io/serverlessworkflow/api/mapper/WorkflowModule.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
import io.serverlessworkflow.api.states.ParallelState;
3131
import io.serverlessworkflow.api.workflow.Events;
3232
import io.serverlessworkflow.api.workflow.Functions;
33+
import io.serverlessworkflow.api.workflow.Retries;
3334

3435
public class WorkflowModule extends SimpleModule {
3536

@@ -80,6 +81,7 @@ private void addDefaultDeserializers() {
8081
addDeserializer(EventDefinition.Kind.class, new EventDefinitionKindDeserializer(workflowPropertySource));
8182
addDeserializer(ParallelState.CompletionType.class, new ParallelStateCompletionTypeDeserializer(workflowPropertySource));
8283
addDeserializer(Schedule.DirectInvoke.class, new ScheduleDirectInvokeDeserializer(workflowPropertySource));
84+
addDeserializer(Retries.class, new RetriesDeserializer(workflowPropertySource));
8385
addDeserializer(Functions.class, new FunctionsDeserializer(workflowPropertySource));
8486
addDeserializer(Events.class, new EventsDeserializer(workflowPropertySource));
8587
addDeserializer(Extension.class, extensionDeserializer);

api/src/main/java/io/serverlessworkflow/api/serializers/WorkflowSerializer.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import io.serverlessworkflow.api.functions.FunctionDefinition;
2525
import io.serverlessworkflow.api.interfaces.Extension;
2626
import io.serverlessworkflow.api.interfaces.State;
27+
import io.serverlessworkflow.api.retry.RetryDefinition;
2728

2829
import java.io.IOException;
2930
import java.security.MessageDigest;
@@ -111,6 +112,17 @@ public void serialize(Workflow workflow,
111112
gen.writeEndArray();
112113
}
113114

115+
if (workflow.getRetries() != null && !workflow.getRetries().getRetryDefs().isEmpty()) {
116+
gen.writeArrayFieldStart("retries");
117+
for (RetryDefinition retry : workflow.getRetries().getRetryDefs()) {
118+
gen.writeObject(retry);
119+
}
120+
gen.writeEndArray();
121+
} else {
122+
gen.writeArrayFieldStart("retries");
123+
gen.writeEndArray();
124+
}
125+
114126
if (workflow.getStates() != null && !workflow.getStates().isEmpty()) {
115127
gen.writeArrayFieldStart("states");
116128
for (State state : workflow.getStates()) {

api/src/main/java/io/serverlessworkflow/api/workflow/BaseWorkflow.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ public static Workflow fromSource(String source) {
4343
return jsonObjectMapper.readValue(source,
4444
Workflow.class);
4545
} catch (Exception e) {
46+
logger.info("Unable to convert as json markup, trying as yaml");
4647
try {
4748
return yamlObjectMapper.readValue(source,
4849
Workflow.class);
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
/*
2+
* Copyright 2020-Present The Serverless Workflow Specification Authors
3+
* <p>
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
* <p>
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
* <p>
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*
16+
*/
17+
package io.serverlessworkflow.api.workflow;
18+
19+
import io.serverlessworkflow.api.retry.RetryDefinition;
20+
21+
import java.util.List;
22+
23+
public class Retries {
24+
private String refValue;
25+
private List<RetryDefinition> retryDefs;
26+
27+
public Retries() {}
28+
29+
public Retries(List<RetryDefinition> retryDefs) {
30+
this.retryDefs = retryDefs;
31+
}
32+
33+
public Retries(String refValue) {
34+
this.refValue = refValue;
35+
}
36+
37+
public String getRefValue() {
38+
return refValue;
39+
}
40+
41+
public void setRefValue(String refValue) {
42+
this.refValue = refValue;
43+
}
44+
45+
public List<RetryDefinition> getRetryDefs() {
46+
return retryDefs;
47+
}
48+
49+
public void setRetryDefs(List<RetryDefinition> retryDefs) {
50+
this.retryDefs = retryDefs;
51+
}
52+
}

api/src/main/resources/schema/error/error.json

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,21 +2,32 @@
22
"type": "object",
33
"javaType": "io.serverlessworkflow.api.error.Error",
44
"properties": {
5-
"expression": {
5+
"error": {
66
"type": "string",
7-
"description": "Common Expression Language (CEL) expression. Should be evaluated against error data. Must evaluate to true."
7+
"description": "Domain-specific error name, or '*' to indicate all possible errors",
8+
"minLength": 1
89
},
9-
"errorDataFilter": {
10-
"$ref": "../filters/errordatafilter.json",
11-
"description": "Error data filter definition "
10+
"code": {
11+
"type": "string",
12+
"description": "Error code. Can be used in addition to the name to help runtimes resolve to technical errors/exceptions. Should not be defined if error is set to '*'",
13+
"minLength": 1
14+
},
15+
"retryRef": {
16+
"type": "string",
17+
"description": "References a unique name of a retry definition.",
18+
"minLength": 1
1219
},
1320
"transition": {
1421
"$ref": "../transitions/transition.json",
15-
"description": "Next transition of the workflow when 'expression' is true"
22+
"description": "Transition to next state to handle the error. If retryRef is defined, this transition is taken only if retries were unsuccessful."
23+
},
24+
"end": {
25+
"description": "End workflow execution in case of this error. If retryRef is defined, this ends workflow only if retries were unsuccessful.",
26+
"$ref": "../end/end.json"
1627
}
1728
},
1829
"required": [
19-
"expression",
30+
"error",
2031
"transition"
2132
]
2233
}

api/src/main/resources/schema/filters/errordatafilter.json

Lines changed: 0 additions & 11 deletions
This file was deleted.

api/src/main/resources/schema/retry/retry.json renamed to api/src/main/resources/schema/retry/retrydef.json

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,16 @@
11
{
22
"type": "object",
3-
"javaType": "io.serverlessworkflow.api.retry.Retry",
3+
"javaType": "io.serverlessworkflow.api.retry.RetryDefinition",
44
"description": "Retry Definition",
55
"properties": {
6-
"expression": {
6+
"name": {
77
"type": "string",
8-
"description": "Common Expression Language (CEL) expression. Should be evaluated against state data. Must evaluate to true for retry to execute"
8+
"description": "Unique retry strategy name",
9+
"minLength": 1
910
},
10-
"interval": {
11+
"delay": {
1112
"type": "string",
12-
"description": "Specifies the amount of time between retries (ISO 8601 format)"
13+
"description": "Time delay between retry attempts (ISO 8601 duration format)"
1314
},
1415
"multiplier": {
1516
"type": "string",
@@ -28,6 +29,7 @@
2829
}
2930
},
3031
"required": [
31-
"expression"
32+
"name",
33+
"maxAttempts"
3234
]
3335
}

api/src/main/resources/schema/states/defaultstate.json

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -57,21 +57,13 @@
5757
"type": "string",
5858
"description": "URI to JSON Schema that state data output adheres to"
5959
},
60-
"onError": {
60+
"onErrors": {
6161
"type": "array",
62-
"description": "State onError definition",
62+
"description": "State error handling definitions",
6363
"items": {
6464
"type": "object",
6565
"$ref": "../error/error.json"
6666
}
67-
},
68-
"retry": {
69-
"type": "array",
70-
"description": "State retry definition",
71-
"items": {
72-
"type": "object",
73-
"$ref": "../retry/retry.json"
74-
}
7567
}
7668
},
7769
"required": [

0 commit comments

Comments
 (0)