7. Decision, Terminate, Message
Requirements
- You have done the User inputs tutorial
What you will learn
- How to model a if... then... else ...
- How to force a job to terminate in particular status.
- How to display a message to a user.
What are they used for?
- Decision task allows to model if... then... else ...
- Terminate task allows to terminate a Job in error or in success.
- Display message tasks allows to display a message to the user that executed a Job.
In this tutorial
We will use the Decision and Terminate tasks to stop the Job Export excel in the case a user try to export products which are invalid.
In the case he has selected invalid products we will display this message:
Info
As you can see, the Job ends in success, but the message says that there is a functional error. As you will read it below, the message is fully customizable.
In the case he has only selected valid products we will not display any message, the Job will just end in success like before.
Other examples of use
- Detect when a file is missing on a sFTP server and send an email to an administrator.
- Detect when a REST or SOAP api call fails and send an email to an administrator.
- Any other case where you need to detect and take actions on errors.
Setup
Functionally we will enrich the Job Export excel like this:
User inputs
- Type = SELECT Select language
Tasks
- Export Items Export items from a user selection
- Transform XSLT Test if only valid products have been selected
- Decision Only valid products selected?
- Case = NO
- Display message Display an error message to user
- Terminate Terminate the Job in success
error_message Outputmessage
of the the task Display an error message to user
- Case = NO
- Transform XSLT Transform items for the Generate Excel file
- Generate Excel Generate the Excel file
User outputs
- excel_files Output
files
of the task Generate the Excel file
To do so, first add a new transform XSLT like below to test if products exported contain invalid products. In this XSLT we will write code to force the XSLT to through an error when there are invalid products.
json
{
"schema": "1.0",
"key": "my_first_job",
"title": "Export excel",
"icon": "file-excel",
"userInputs": [
{
"key": "language",
"title": "Language",
"description": "Select language",
"required": true,
"type": "SELECT",
"options": [
{
"key": "french",
"title": "French"
},
{
"key": "english",
"title": "English"
}
],
"default": "english"
}
],
"tasks": [
{
"name": "table-export-items",
"taskReferenceName": "table_export_items",
"description": "Export items from a user selection",
"optional": false,
"type": "SUB_WORKFLOW",
"inputParameters": {
"tableKey": "PL_DEMO_PRODUCTS",
"mode": "USER_SELECTION",
"fileName": "items.xml"
}
},
{
"name": "file-transformation-xslt",
"taskReferenceName": "test_xslt",
"description": "Test if only valid products have been selected",
"optional": true,
"type": "SUB_WORKFLOW",
"inputParameters": {
"mode": "FILE",
"file": "${table_export_items.output.file}",
"xslt": "file://assets/",
"fileName": "result.xml"
}
},
{
"name": "file-transformation-xslt",
"taskReferenceName": "file_transformation_xslt",
"description": "Transform items for the Generate Excel file",
"optional": false,
"type": "SUB_WORKFLOW",
"inputParameters": {
"mode": "FILE",
"file": "${table_export_items.output.file}",
"params": [
{
"name": "language",
"select": "${workflow.input.language}"
}
],
"xslt": "file://assets/transform.xslt",
"fileName": "result.xml"
}
},
{
"name": "file-generation-xlsx",
"taskReferenceName": "file_generation_xlsx",
"description": "Generate the Excel file",
"optional": false,
"type": "SUB_WORKFLOW",
"inputParameters": {
"request": "${file_transformation_xslt.output.file}",
"templates": [
{
"key": "template-tutorial",
"file": "file://assets/template-tutorial.xlsx"
}
]
}
}
],
"outputParameters": {
"excel_files": "${file_generation_xlsx.output.files}"
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
Important
You must set optional: true
for this task because we don't want that the job stop here in case of error. If a task is set to optional: false
then if the task as an error, the Job stop on this task, but if a task is set to optional: true
, then if the task fails, the Job continues.
Notice also that the taskReferenceName has the different name test_xslt
from the next xslt task file_transformation_xslt
. The value of the property taskReferenceName of each task must be unique in your job.
Then add a new test-invalid-items.xslt
file in the assets
folder, and add these lines of code within this file:
xml
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:fn="fn"
xmlns:pl="http://product-live.com"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
version="3.0"
exclude-result-prefixes="xs fn pl">
<xsl:output method="xml" indent="yes" encoding="UTF-8" cdata-section-elements="" />
<xsl:template match="/">
<xsl:if test="exists(/Table/Items/Item/Conditional-Formatting[@key='DATA_COMPLIANCE' and .='UNVALID'])">
<xsl:message terminate="yes">Invalid items found</xsl:message>
</xsl:if>
<Empty/>
</xsl:template>
</xsl:stylesheet>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
Here we use xsl:message
with the attribute terminate="yes"
to force the task to end in error if there are invalid items.
We are also adding a root xml tag <Empty/>
. A root xml tag is always required when generating XML files.
Best practice for later
To debug your XSLT files locally you can use xsl:message
to display within the output panel of VS Code. We will see it later in the ninth tutorial.
Then link this file in the test_xslt
task like this using the autocomplete:
json
{
"name": "file-transformation-xslt",
"taskReferenceName": "test_xslt",
"description": "Test if only valid products have been selected",
"optional": true,
"type": "SUB_WORKFLOW",
"inputParameters": {
"mode": "FILE",
"file": "${table_export_items.output.file}",
"xslt": "file://assets/test-invalid-items.xslt",
"fileName": "result.xml"
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
2
3
4
5
6
7
8
9
10
11
12
13
Important
Check that you have updated the right XSLT task. It must be the test_xslt
task.
Now we will add the Decision task like this (use the autocomplete and start typing de...):
Add the description Only valid products selected? to the Decision task and you must have:
json
{
"schema": "1.0",
"key": "my_first_job",
"title": "Export excel",
"icon": "file-excel",
"userInputs": [
{
"key": "language",
"title": "Language",
"description": "Select language",
"required": true,
"type": "SELECT",
"options": [
{
"key": "french",
"title": "French"
},
{
"key": "english",
"title": "English"
}
],
"default": "english"
}
],
"tasks": [
{
"name": "table-export-items",
"taskReferenceName": "table_export_items",
"description": "Export items from a user selection",
"optional": false,
"type": "SUB_WORKFLOW",
"inputParameters": {
"tableKey": "PL_DEMO_PRODUCTS",
"mode": "USER_SELECTION",
"fileName": "items.xml"
}
},
{
"name": "file-transformation-xslt",
"taskReferenceName": "test_xslt",
"description": "Test if only valid products have been selected",
"optional": true,
"type": "SUB_WORKFLOW",
"inputParameters": {
"mode": "FILE",
"file": "${table_export_items.output.file}",
"xslt": "file://assets/test-invalid-items.xslt",
"fileName": "result.xml"
}
},
{
"name": "decision",
"taskReferenceName": "decision",
"description": "Only valid products selected?",
"optional": false,
"type": "DECISION",
"inputParameters": {
"case_value_param": ""
},
"caseValueParam": "case_value_param",
"decisionCases": {
"YES": [],
"NO": []
}
},
{
"name": "file-transformation-xslt",
"taskReferenceName": "file_transformation_xslt",
"description": "Transform items for the Generate Excel file",
"optional": false,
"type": "SUB_WORKFLOW",
"inputParameters": {
"mode": "FILE",
"file": "${table_export_items.output.file}",
"params": [
{
"name": "language",
"select": "${workflow.input.language}"
}
],
"xslt": "file://assets/transform.xslt",
"fileName": "result.xml"
}
},
{
"name": "file-generation-xlsx",
"taskReferenceName": "file_generation_xlsx",
"description": "Generate the Excel file",
"optional": false,
"type": "SUB_WORKFLOW",
"inputParameters": {
"request": "${file_transformation_xslt.output.file}",
"templates": [
{
"key": "template-tutorial",
"file": "file://assets/template-tutorial.xlsx"
}
]
}
}
],
"outputParameters": {
"excel_files": "${file_generation_xlsx.output.files}"
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
Now we will test the output allFilesTransformed
from the task Transform XSLT, you can read more about the outputs of the Transform XSLT task here.
This output can have two values: YES
| NO
. YES
: all files have been transformed. NO
: at least one file has an error.
We will only deal with the case where allFilesTransformed
= NO
. For this we will update the properties case_value_param
using the autocomplete like below, and only keep the cas NO
. You must have:
json
{
"name": "decision",
"taskReferenceName": "decision",
"description": "Only valid products selected?",
"optional": false,
"type": "DECISION",
"inputParameters": {
"case_value_param": "${test_xslt.output.allFilesTransformed}"
},
"caseValueParam": "case_value_param",
"decisionCases": {
"NO": []
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
2
3
4
5
6
7
8
9
10
11
12
13
14
Now we will define what tasks must be done in the case allFilesTransformed
= NO
. Here you can chain tasks like you have previously done in the Job: use the autocomplete to select the tasks Display message and Terminate, you must have:
json
{
"name": "decision",
"taskReferenceName": "decision",
"description": "Only valid products selected?",
"optional": false,
"type": "DECISION",
"inputParameters": {
"case_value_param": "${test_xslt.output.allFilesTransformed}"
},
"caseValueParam": "case_value_param",
"decisionCases": {
"NO": [
{
"name": "notification-display-message",
"taskReferenceName": "notification_display_message",
"description": "",
"optional": false,
"type": "SUB_WORKFLOW",
"inputParameters": {
"request": "",
"height": 40
}
},
{
"name": "terminate",
"taskReferenceName": "terminate",
"description": "",
"optional": false,
"type": "TERMINATE",
"inputParameters": {
"terminationStatus": "COMPLETED"
}
}
]
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
The task Display message expect an html file in the request property. In the assets
folder create a file named invalid-products.html
and copy and save this code:
html
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<style>
body {
margin: 0;
padding: 0;
font-size: 14px;
font-family: -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Noto Sans",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";
}
</style>
</head>
<body>
<div>❌ You have selected invalid products. Only valid products can be exported. Please retry by selecting only valid products.</div>
</body>
</html>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
Then update the Display message task like this using the autocomplete for the request parameter:
json
{
"name": "notification-display-message",
"taskReferenceName": "notification_display_message",
"description": "Display an error message to user",
"optional": false,
"type": "SUB_WORKFLOW",
"inputParameters": {
"request": "file://assets/invalid-products.html",
"height": 40
}
}
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
Now update the Terminate task like below to display the message:
json
{
"name": "terminate",
"taskReferenceName": "terminate",
"description": "Terminate the Job in success",
"optional": false,
"type": "TERMINATE",
"inputParameters": {
"terminationStatus": "COMPLETED",
"outputParameters": {
"error_message": "${notification_display_message.output.message}"
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
2
3
4
5
6
7
8
9
10
11
12
13
What happen if I don't put the Terminate task?
The Job will continue, which means that the Excel file will be generated.
Can I set the message on the outputParameters of the Job instead of the task?
If you do this the Job will ends in success but the user will not view the outputs. When you terminate a Job you must explicitly define which outputParameters must be displayed.
Why the rest of the Job is not in the YES section of the Decision task?
Both solutions are technically valid, you can imbricate tasks within multiple Decision. But the best practice is to only use the Decision as a test for the cases that you want to detect. For more complex Jobs it will be easier to read the json: to understand what a Job do, you just have to read the first level of the Job, and if there is Decision tasks you can read what functional errors are captured.
Do I need to use a decision task after each task?
No! Do not over engineer your Jobs.
Your final Job must be:
json
{
"schema": "1.0",
"key": "my_first_job",
"title": "Export excel",
"icon": "file-excel",
"userInputs": [
{
"key": "language",
"title": "Language",
"description": "Select language",
"required": true,
"type": "SELECT",
"options": [
{
"key": "french",
"title": "French"
},
{
"key": "english",
"title": "English"
}
],
"default": "english"
}
],
"tasks": [
{
"name": "table-export-items",
"taskReferenceName": "table_export_items",
"description": "Export items from a user selection",
"optional": false,
"type": "SUB_WORKFLOW",
"inputParameters": {
"tableKey": "PL_DEMO_PRODUCTS",
"mode": "USER_SELECTION",
"fileName": "items.xml"
}
},
{
"name": "file-transformation-xslt",
"taskReferenceName": "test_xslt",
"description": "Test if only valid products have been selected",
"optional": true,
"type": "SUB_WORKFLOW",
"inputParameters": {
"mode": "FILE",
"file": "${table_export_items.output.file}",
"xslt": "file://assets/test-invalid-items.xslt",
"fileName": "result.xml"
}
},
{
"name": "decision",
"taskReferenceName": "decision",
"description": "Only valid products selected?",
"optional": false,
"type": "DECISION",
"inputParameters": {
"case_value_param": "${test_xslt.output.allFilesTransformed}"
},
"caseValueParam": "case_value_param",
"decisionCases": {
"NO": [
{
"name": "notification-display-message",
"taskReferenceName": "notification_display_message",
"description": "Display an error message to user",
"optional": false,
"type": "SUB_WORKFLOW",
"inputParameters": {
"request": "file://assets/invalid-products.html",
"height": 40
}
},
{
"name": "terminate",
"taskReferenceName": "terminate",
"description": "Terminate the Job in success",
"optional": false,
"type": "TERMINATE",
"inputParameters": {
"terminationStatus": "COMPLETED",
"outputParameters": {
"error_message": "${notification_display_message.output.message}"
}
}
}
]
}
},
{
"name": "file-transformation-xslt",
"taskReferenceName": "file_transformation_xslt",
"description": "Transform items for the Generate Excel file",
"optional": false,
"type": "SUB_WORKFLOW",
"inputParameters": {
"mode": "FILE",
"file": "${table_export_items.output.file}",
"params": [
{
"name": "language",
"select": "${workflow.input.language}"
}
],
"xslt": "file://assets/transform.xslt",
"fileName": "result.xml"
}
},
{
"name": "file-generation-xlsx",
"taskReferenceName": "file_generation_xlsx",
"description": "Generate the Excel file",
"optional": false,
"type": "SUB_WORKFLOW",
"inputParameters": {
"request": "${file_transformation_xslt.output.file}",
"templates": [
{
"key": "template-tutorial",
"file": "file://assets/template-tutorial.xlsx"
}
]
}
}
],
"outputParameters": {
"excel_files": "${file_generation_xlsx.output.files}"
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
And your assets folder must be:
Great! Now the case where there are invalid products selected is handled.
Info
The file expected in the request parameter of the task Display message is an HTML file. This file can be a static file stored in the assets
folder, or an HTML file generated by a previous task. For example you can use a Transform XSLT task before the display message to count the number of invalid products selected, and generate the HTML from the XSLT. For this do not forget to set method="html"
in xsl:output
element of the XSLT, and rename the inputParameter fileName
with a .html
extension.
Save all your opened files and package your Job. Go to update your Job in Settings, and go to https://app.product-live.com to test your Job (refresh your page with Ctrl + Shift + R
).
Try to select at least one invalid product, you must have this message:
Another practical example
Let's say that you want to recover a CSV file from a SFTP. For this you can create a Job that can simply recover the file with the FTP Get task, then you will face two cases:
- There is a file on the SFTP server
- There is no file on the SFTP server
By default the SFTP task ends in error if a file is expected and there is no file that can be recovered. So in the second case the Job will stop in error in the task FTP Get. But may be it's a normal case, or may be it's not an expected case and you want to notify an administrator.
The Job will look like this:
json
{
"schema": "1.0",
"key": "import_items_from_a_csv_file_stored_on_a_sFTP_server",
"title": "Import items from a CSV file stored on a sFTP server",
"tasks": [
{
"name": "protocol-ftp-get",
"taskReferenceName": "ftp_get",
"description": "Get the csv file from the sFTP server",
"type": "SUB_WORKFLOW",
"optional": true,
"inputParameters": {
"connection": "SFTP",
"host": "",
"username": "",
"password": "",
"port": 21,
"mode": "PARAMETERS",
"remoteFolder": "/input/",
"sort": "LAST_MODIFIED_DESC",
"filter": "",
"maxFiles": 1
}
},
{
"name": "decision",
"taskReferenceName": "decision",
"description": "No file recovered?",
"type": "DECISION",
"inputParameters": {
"case_value_param": "${ftp_get.output.noFile}"
},
"caseValueParam": "case_value_param",
"decisionCases": {
"YES": [
{
"name": "notification-send-email",
"taskReferenceName": "send_email",
"description": "Send an email to the administrator",
"type": "SUB_WORKFLOW",
"optional": false,
"inputParameters": {
"mode": "FILE",
"file": "file://assets/email-error.html"
}
},
{
"name": "terminate",
"taskReferenceName": "terminate",
"description": "Terminate in success",
"optional": false,
"type": "TERMINATE",
"inputParameters": {
"terminationStatus": "COMPLETED"
}
}
]
}
},
{
"name": "file-conversion-csv-to-xml",
"taskReferenceName": "csv_to_xml",
"description": "Convert the CSV file to XML",
"type": "SUB_WORKFLOW",
"optional": false,
"inputParameters": {
"mode": "FILE",
"file": "${ftp_get.output.file}",
"columnSeparator": ";",
"textDelimiter": "\"",
"escapeCharacter": "\""
}
},
{
"name": "file-transformation-xslt",
"taskReferenceName": "transform_xslt",
"description": "Transform the file to the Product-Live expected format",
"type": "SUB_WORKFLOW",
"optional": false,
"inputParameters": {
"mode": "FILE",
"file": "${csv_to_xml.output.file}",
"xslt": "file://assets/transform.xslt",
"fileName": "result.xml"
}
},
{
"name": "table-import-items",
"taskReferenceName": "import_items",
"description": "Import products as items",
"type": "SUB_WORKFLOW",
"optional": false,
"inputParameters": {
"request": "${transform_xslt.output.file}"
}
}
]
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
Best practice
Use the Decision task to detect functional errors and alert administrators.
What you have learned
For your Jobs you will need to simply differentiate technical errors and functional errors, and most of the time when you have functional errors you don't want that the Job ends in errors. Using Decision, Terminate and Display message tasks allow to handle these problems.
Next
You will learn how to setup Periodicity for your Jobs.