orbit-code-ai 0.1.20 → 0.1.23
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/_agent_reference/components/audit-logging.md +12 -6
- package/_agent_reference/components/common-utils.md +253 -84
- package/_agent_reference/components/error-handling.md +142 -81
- package/_agent_reference/components/http-adapters.md +11 -20
- package/_agent_reference/components/input-adapters.md +26 -16
- package/_agent_reference/components/output-adapters.md +23 -16
- package/_agent_reference/components/property-reader.md +24 -12
- package/_agent_reference/components/retry.md +32 -27
- package/_agent_reference/config/naming-conventions.md +8 -5
- package/_agent_reference/config/properties-template.md +2 -1
- package/_agent_reference/esql-coding-standards.md +2 -2
- package/_agent_reference/msgflow-xml-reference.md +31 -10
- package/_agent_reference/templates/file-flow.md +7 -4
- package/_agent_reference/templates/http-flow.md +29 -28
- package/_agent_reference/templates/mq-flow.md +35 -33
- package/dist/cli.mjs +46 -23
- package/package.json +1 -1
- package/skills/apic-api/SKILL.md +1 -1
|
@@ -1,117 +1,178 @@
|
|
|
1
1
|
# Error Handling
|
|
2
2
|
|
|
3
|
-
Central error handling is provided by `ErrorHandler.subflow` + `ErrorHandler.esql
|
|
3
|
+
Central error handling is provided by `ErrorHandler.subflow` (+ `ErrorHandler.esql`, ~43 KB). Every flow wires its node **failure/catch terminals** to the matching `ErrorHandler` input terminal. The handler classifies the error, logs it for audit, and builds a standardized ESB response.
|
|
4
4
|
|
|
5
5
|
---
|
|
6
6
|
|
|
7
|
-
##
|
|
7
|
+
## Two error channels
|
|
8
|
+
|
|
9
|
+
There are two distinct mechanisms — don't confuse them:
|
|
10
|
+
|
|
11
|
+
1. **Business errors** (validation, expected error codes) — set the code yourself and let the
|
|
12
|
+
business-error path build the response:
|
|
13
|
+
```esql
|
|
14
|
+
SET Environment.Variables.MWResponse.status = '<error_code>'; -- e.g. an ESB_ERROR_CODES value
|
|
15
|
+
```
|
|
16
|
+
`ESBBusinessErrorResponse` reads `Environment.Variables.MWResponse.status` (defaulting to
|
|
17
|
+
`'99999999'`) and calls `CreateEsbXMLResponseHeaderFromRoot(...)` to emit the response header.
|
|
18
|
+
Do **not** `THROW USER EXCEPTION` for business validation.
|
|
19
|
+
|
|
20
|
+
2. **Technical exceptions** — wire the node's **failure** terminal to `ErrorHandler`. The exception
|
|
21
|
+
list is parsed, logged, and turned into a fault/response. The handler distinguishes the error
|
|
22
|
+
class via `Environment.Variables.esb.errorType`, set by the small `ErrorHandler_Handle*` compute
|
|
23
|
+
modules (one per input terminal):
|
|
24
|
+
|
|
25
|
+
| Input terminal | Handler module | `esb.errorType` set |
|
|
26
|
+
|---|---|---|
|
|
27
|
+
| `Failure` (`WSFailure`) | `ErrorHandler_HandleFailure` | `Failure` |
|
|
28
|
+
| `Fault` (`WSFault`) | `ErrorHandler_HandleFault` | `Fault` |
|
|
29
|
+
| `ValidationFailure` | `ErrorHandler_HandleValidationFailure` | `ValidationFailure` |
|
|
30
|
+
| `FileFailure` | `ErrorHandler_HandleFileFailure` | `FileFailure` |
|
|
31
|
+
| `MQInputFailure` | `ErrorHandler_HandleMQInputFailure` | `MQInputFailure` |
|
|
32
|
+
| `MQInputCatch` | `ErrorHandler_HandleMQInputCatch` | `MQInputCatch` (sets `EXCEPTION_CAUGHT`) |
|
|
33
|
+
| `FileInputCatch` | `ErrorHandler_HandleFileInputCatch` | `FileInputCatch` (sets `EXCEPTION_CAUGHT`) |
|
|
34
|
+
|
|
35
|
+
`ErrorHandler_CreateGeniricRs` then builds the response from `esb.errorType` + the active backend
|
|
36
|
+
adapter flag (below).
|
|
8
37
|
|
|
9
|
-
|
|
38
|
+
---
|
|
39
|
+
|
|
40
|
+
## ErrorHandler.subflow terminals
|
|
41
|
+
|
|
42
|
+
Wire to the input terminal that matches the failing node:
|
|
10
43
|
|
|
11
|
-
**Internal flow**:
|
|
12
44
|
```
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
├── MQ_Dead_Output_Node (async flows)
|
|
23
|
-
└── MWBusinessErrorResponse (sync/HTTP flows)
|
|
45
|
+
InTerminal.Input -- generic
|
|
46
|
+
InTerminal.ValidationFailure / InTerminal.FileValidationFailure
|
|
47
|
+
InTerminal.WSFailure / InTerminal.WSFault
|
|
48
|
+
InTerminal.MQInputFailure / InTerminal.MQInputCatch
|
|
49
|
+
InTerminal.FileFailure / InTerminal.FileInputCatch
|
|
50
|
+
InTerminal.SystemDown
|
|
51
|
+
InTerminal.httphandlefail / InTerminal.httphandlefault
|
|
52
|
+
↓
|
|
53
|
+
OutTerminal.Output
|
|
24
54
|
```
|
|
25
55
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
| `ErrorHandler_IsExceptionCaught.esql` | Filter: prevent double-handling |
|
|
32
|
-
| `ErrorHandler_SetExceptionCaught.esql` | Mark exception as handled |
|
|
33
|
-
| `ErrorHandler_IsFileSchemaValidationOccured.esql` | Detect file schema validation errors |
|
|
34
|
-
| `ErrorHandler_PrepareFileDataForAudit.esql` | Prepare file error data for audit |
|
|
35
|
-
| `ESBBusinessErrorResponse.esql` | Build ESB-standard business error response |
|
|
56
|
+
Internally it routes through:
|
|
57
|
+
- `LogError.subflow` — audit-logs the error (uses `ErrorPoint` to build the error/audit record).
|
|
58
|
+
- `MWBusinessErrorResponse.subflow` — emits the synchronous ESB error response to the caller.
|
|
59
|
+
- `MQ_Dynamic_Output_Node.subflow` — async/dead routing.
|
|
60
|
+
- `ErrorHandler_IsAtomicService` (FILTER, gated by `IsAtomic EXTERNAL BOOLEAN`).
|
|
36
61
|
|
|
37
62
|
---
|
|
38
63
|
|
|
39
|
-
##
|
|
64
|
+
## ESQL modules
|
|
40
65
|
|
|
41
|
-
|
|
66
|
+
| Module | Type | Purpose |
|
|
67
|
+
|---|---|---|
|
|
68
|
+
| `ErrorHandler.esql` › `ErrorHandler_CreateGeniricRs` | COMPUTE | Builds the error response from `esb.errorType` + backend flag |
|
|
69
|
+
| `ErrorHandler.esql` › `ErrorHandler_Handle*` | COMPUTE | Tag `esb.errorType` per terminal (table above) |
|
|
70
|
+
| `ErrorHandler.esql` › `ErrorHandler_IsAtomicService` | FILTER | Routes atomic vs non-atomic (`IsAtomic`) |
|
|
71
|
+
| `ErrorHandler_IsExceptionCaught.esql` | FILTER | Returns the `EXCEPTION_CAUGHT` SHARED flag (prevent double-handling) |
|
|
72
|
+
| `ErrorHandler_SetExceptionCaught.esql` | COMPUTE | Resets `EXCEPTION_CAUGHT = FALSE` |
|
|
73
|
+
| `ErrorHandler_IsFileSchemaValidationOccured.esql` | — | Detect file schema-validation errors |
|
|
74
|
+
| `ErrorHandler_PrepareFileDataForAudit.esql` | COMPUTE | Prepare file error data for audit |
|
|
75
|
+
| `ErrorPoint.esql` › `ErrorPoint_PrepareErrorMsg` | COMPUTE | Build the error/audit record (see below) |
|
|
76
|
+
| `ESBBusinessErrorResponse.esql` › `ESBBusinessErrorResponse_handleRs` | COMPUTE | Business-error response from `MWResponse.status` |
|
|
77
|
+
|
|
78
|
+
`EXCEPTION_CAUGHT` is a `SHARED BOOLEAN` set by the `*Catch` handlers; `ErrorHandler_IsExceptionCaught`
|
|
79
|
+
reads it and `ErrorHandler_SetExceptionCaught` clears it, so an MQ/File input catch isn't processed twice.
|
|
42
80
|
|
|
43
|
-
|
|
81
|
+
---
|
|
44
82
|
|
|
45
|
-
|
|
46
|
-
```xml
|
|
47
|
-
<ResponseStatus>
|
|
48
|
-
<Code>XXXXXXXX</Code>
|
|
49
|
-
<Status>Error</Status>
|
|
50
|
-
<EnglishMsg>Human readable message</EnglishMsg>
|
|
51
|
-
</ResponseStatus>
|
|
52
|
-
```
|
|
83
|
+
## Backend adapter flags
|
|
53
84
|
|
|
54
|
-
|
|
85
|
+
Which backend produced the error is selected by an `EXTERNAL BOOLEAN` flag, set `TRUE` at the
|
|
86
|
+
node/BAR level for the adapter in use (all default `FALSE`). `ErrorHandler_CreateGeniricRs` branches
|
|
87
|
+
on these:
|
|
55
88
|
|
|
56
|
-
|
|
89
|
+
```esql
|
|
90
|
+
DECLARE IsFrotEndAdapter EXTERNAL BOOLEAN FALSE; -- front-end SOAP fault
|
|
91
|
+
DECLARE IsFrontEndJSONAdapter EXTERNAL BOOLEAN FALSE; -- front-end JSON fault
|
|
92
|
+
DECLARE IsT24Adapter EXTERNAL BOOLEAN FALSE;
|
|
93
|
+
DECLARE IsT24OFENQAdapter EXTERNAL BOOLEAN FALSE;
|
|
94
|
+
DECLARE IsODMWSAdapter EXTERNAL BOOLEAN FALSE;
|
|
95
|
+
DECLARE IsNICAdapter EXTERNAL BOOLEAN FALSE;
|
|
96
|
+
DECLARE IsNIWSAdapter EXTERNAL BOOLEAN FALSE;
|
|
97
|
+
DECLARE IsMEPSWSAdapter EXTERNAL BOOLEAN FALSE;
|
|
98
|
+
DECLARE IsICBSWSAdapter EXTERNAL BOOLEAN FALSE;
|
|
99
|
+
DECLARE IsA2AWSAdapter EXTERNAL BOOLEAN FALSE;
|
|
100
|
+
DECLARE IsACHWSAdapter EXTERNAL BOOLEAN FALSE;
|
|
101
|
+
DECLARE IsUnifonicAdapter EXTERNAL BOOLEAN FALSE;
|
|
102
|
+
DECLARE IsMLSDWSAdapter EXTERNAL BOOLEAN FALSE;
|
|
103
|
+
DECLARE IsCapptionsWSAdapter EXTERNAL BOOLEAN FALSE;
|
|
104
|
+
DECLARE IsHyperpayWSAdapter EXTERNAL BOOLEAN FALSE;
|
|
105
|
+
DECLARE IsAtomic EXTERNAL BOOLEAN TRUE;
|
|
106
|
+
```
|
|
57
107
|
|
|
58
|
-
|
|
108
|
+
For each backend, the response code is taken from properties with a hardcoded fallback, using four
|
|
109
|
+
severities gated by an availability check:
|
|
59
110
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
111
|
+
```
|
|
112
|
+
Environment.Properties.<Adapter>.<Flow>.Variables.IsSystemAvailable -- false → SystemDown code
|
|
113
|
+
Environment.Properties.<Adapter>.<Flow>.Variables.<BE>SystemDownErrorCode -- e.g. 'ODM99996'
|
|
114
|
+
Environment.Properties.<Adapter>.<Flow>.Variables.<BE>FailureErrorCode -- esb.errorType='Failure'
|
|
115
|
+
Environment.Properties.<Adapter>.<Flow>.Variables.<BE>FaultErrorCode -- esb.errorType='Fault'
|
|
116
|
+
Environment.Properties.<Adapter>.<Flow>.Variables.<BE>TechnicalErrorCode -- else
|
|
117
|
+
```
|
|
65
118
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
- **MLSD**: Ministry of Labor and Social Development
|
|
72
|
-
- **ICBS**: Core banking system
|
|
119
|
+
Backend code prefixes seen in defaults: T24 (`Create_esbXML_Response_Header_Using_Backend_Code('T24'…)`),
|
|
120
|
+
`ODM999xx`, `UNI999xx`, `NIC999xx`, `MLSD999x`, `CAPP999x`, `HYPP00xx`, `NI9999xx`, `MEPS999x`,
|
|
121
|
+
`ICBS999x`, `A2A999x`, `ACH999x`. SOAP-fault backends map via `..._Using_Backend_Code('<BE>WS', code, …)`
|
|
122
|
+
against `ESB_ERROR_CODES`. When `Header.DebugFlag = '1'`, the raw backend error + parsed exception
|
|
123
|
+
text are surfaced under `Header.BackendError.ErrorCode` / `.ErrorDescription`.
|
|
73
124
|
|
|
74
|
-
|
|
125
|
+
The response itself is built with the CommonUtils procedures `Create_esbXML_Response_Header`,
|
|
126
|
+
`Create_esbXML_Response_Header_Using_Backend_Code`, and `CreateEsbXMLResponseHeaderFromRoot`, setting
|
|
127
|
+
`Header.ResponseStatus.{Status='Error', Code, EnglishMsg, ArabicMsg}`. Front-end adapters instead emit
|
|
128
|
+
a SOAP/JSON fault (`GenerateSOAPFault` / `GenerateJSONFault`) with HTTP reply status `500`.
|
|
75
129
|
|
|
76
130
|
---
|
|
77
131
|
|
|
78
|
-
##
|
|
132
|
+
## Error codes
|
|
79
133
|
|
|
80
|
-
|
|
134
|
+
ESB codes are `EXTERNAL CHARACTER` constants in `CommonUtils.esql` (see [common-utils](common-utils.md)):
|
|
135
|
+
`ESB_SUCCESS_RESPONSE_CODE` `'00000000'`, `ESB_RUNTIME_TECHNICAL_ERROR_CODE` `'99999999'`,
|
|
136
|
+
`ESB_MIDDLEWARE_RUNTIME_ERROR_RESPONSE_CODE` `'99999999'`, `ESB_MIDDLEWARE_DATABASE_ERROR_RESPONSE_CODE`
|
|
137
|
+
`'E0199998'`, plus channel codes `'E9009999'`/`'55555555'`/`'44444444'` and `'E5500003'`. Localized
|
|
138
|
+
descriptions come from `dbo.ESB_ERROR_CODES` via `getEsbErrorCodeDescriptionFrom` /
|
|
139
|
+
`getEsbChannlsErrorCodeDescriptionFrom` / `getBackendEsb_MapErrorCode`. Per-backend default codes live
|
|
140
|
+
in the adapter's properties (above), not in CommonUtils.
|
|
81
141
|
|
|
82
|
-
|
|
83
|
-
[Any Node]
|
|
84
|
-
│ failure terminal
|
|
85
|
-
↓
|
|
86
|
-
ErrorHandler.subflow
|
|
87
|
-
│
|
|
88
|
-
├──[MQ flow]──→ MQ_Dead_Output_Node
|
|
89
|
-
└──[HTTP flow]─→ MWBusinessErrorResponse
|
|
90
|
-
```
|
|
142
|
+
---
|
|
91
143
|
|
|
92
|
-
|
|
93
|
-
```esql
|
|
94
|
-
-- Set which backend adapter this flow uses (controls error code mapping)
|
|
95
|
-
DECLARE IsT24Adapter EXTERNAL BOOLEAN FALSE;
|
|
96
|
-
DECLARE IsODMWSAdapter EXTERNAL BOOLEAN FALSE;
|
|
97
|
-
DECLARE IsFrontEndJSONAdapter EXTERNAL BOOLEAN FALSE;
|
|
98
|
-
DECLARE IsNIWSAdapter EXTERNAL BOOLEAN FALSE;
|
|
99
|
-
DECLARE IsUniFonicAdapter EXTERNAL BOOLEAN FALSE;
|
|
100
|
-
DECLARE IsMLSDAdapter EXTERNAL BOOLEAN FALSE;
|
|
101
|
-
DECLARE IsICBSAdapter EXTERNAL BOOLEAN FALSE;
|
|
102
|
-
```
|
|
144
|
+
## ErrorPoint (error/audit record)
|
|
103
145
|
|
|
104
|
-
|
|
146
|
+
`ErrorPoint_PrepareErrorMsg` is the **internal** module the error/audit path uses — it is not a
|
|
147
|
+
user-set API. It builds `OutputRoot.XMLNSC.Error` with:
|
|
148
|
+
|
|
149
|
+
- `errorName` = `'Error in Application: ' || ApplicationLabel || ' in Message Flow: ' || MessageFlowLabel`
|
|
150
|
+
- `errorMessage` = parsed exception text (via `PARSEExceptionList`), or the raw bitstream when no exception list
|
|
151
|
+
- `auditHeader` = requestId, timestamp, applicationName, messageFlowName, brokerName, executionGroupName,
|
|
152
|
+
logType `'Error'`, channelId, userName, serviceCode, sessionId, channelReqTime, requestMessage
|
|
153
|
+
|
|
154
|
+
It falls back to `Environment.ESB.Framework.ErrorHandler.Header.*` for header fields when the inbound
|
|
155
|
+
message header is absent.
|
|
105
156
|
|
|
106
157
|
---
|
|
107
158
|
|
|
108
|
-
##
|
|
159
|
+
## Wiring a new flow
|
|
160
|
+
|
|
161
|
+
```
|
|
162
|
+
[Any processing node]
|
|
163
|
+
│ failure terminal
|
|
164
|
+
↓
|
|
165
|
+
ErrorHandler.subflow (InTerminal matching the node/error class)
|
|
166
|
+
├─ LogError.subflow → audit
|
|
167
|
+
├─ MWBusinessErrorResponse.subflow → sync ESB response to caller
|
|
168
|
+
└─ MQ_Dynamic_Output_Node.subflow → async/dead routing
|
|
169
|
+
```
|
|
109
170
|
|
|
110
|
-
|
|
171
|
+
For an expected business/validation error, prefer the business channel:
|
|
111
172
|
|
|
112
173
|
```esql
|
|
113
|
-
--
|
|
114
|
-
SET Environment.
|
|
115
|
-
|
|
116
|
-
|
|
174
|
+
-- validation failed: set the ESB code and let the business-error path respond
|
|
175
|
+
SET Environment.Variables.MWResponse.status = 'E5500003';
|
|
176
|
+
PROPAGATE TO TERMINAL 'out2'; -- route to the business-error branch
|
|
177
|
+
RETURN FALSE;
|
|
117
178
|
```
|
|
@@ -10,26 +10,15 @@ Used for outbound HTTP calls (to backends or internal services) and for chaining
|
|
|
10
10
|
|
|
11
11
|
**Supported backends**: T24, NIWS, ODM, Unifonic, MLSD, ICBS, and any REST/SOAP service.
|
|
12
12
|
|
|
13
|
-
**
|
|
14
|
-
| Module | Purpose |
|
|
15
|
-
|---|---|
|
|
16
|
-
| `HTTPResponseAdapter_CheckCallType.esql` | Determine INTERNAL vs EXTERNAL call |
|
|
17
|
-
| `InternalHTTPRequestAdapter_Remove_MQRFH2.esql` | Strip MQRFH2 headers before HTTP call |
|
|
18
|
-
|
|
19
|
-
**ESQL DECLARE flags** (set at node level):
|
|
20
|
-
```esql
|
|
21
|
-
DECLARE IsT24Adapter EXTERNAL BOOLEAN FALSE;
|
|
22
|
-
DECLARE IsODMWSAdapter EXTERNAL BOOLEAN FALSE;
|
|
23
|
-
DECLARE IsFrontEndJSONAdapter EXTERNAL BOOLEAN FALSE;
|
|
24
|
-
DECLARE IsNIWSAdapter EXTERNAL BOOLEAN FALSE;
|
|
25
|
-
DECLARE IsUniFonicAdapter EXTERNAL BOOLEAN FALSE;
|
|
26
|
-
DECLARE IsMLSDAdapter EXTERNAL BOOLEAN FALSE;
|
|
27
|
-
DECLARE IsICBSAdapter EXTERNAL BOOLEAN FALSE;
|
|
28
|
-
```
|
|
13
|
+
**Node properties** (EXTERNAL): `ServiceURL`, `TimeoutInSec`.
|
|
29
14
|
|
|
30
|
-
|
|
15
|
+
**URL/endpoint**: set the node `ServiceURL`, or read the target from the
|
|
16
|
+
`BankIdForRoutingService` properties group (see below).
|
|
31
17
|
|
|
32
|
-
|
|
18
|
+
> The per-backend `Is<Backend>Adapter` flags (`IsT24Adapter`, `IsODMWSAdapter`, `IsUnifonicAdapter`,
|
|
19
|
+
> `IsMLSDWSAdapter`, `IsICBSWSAdapter`, …) are **not** declared on `HTTPRequestAdapter`. They live on
|
|
20
|
+
> the error path (`ErrorHandler_CreateGeniricRs`) where they select backend-specific error-code mapping.
|
|
21
|
+
> See [error-handling](error-handling.md) for the full, correctly-named list.
|
|
33
22
|
|
|
34
23
|
---
|
|
35
24
|
|
|
@@ -37,8 +26,10 @@ Set exactly ONE of these to `TRUE` to get correct request formatting and error c
|
|
|
37
26
|
|
|
38
27
|
**Purpose**: Processes the HTTP response from a backend call, normalizes it to the standard ESB response structure.
|
|
39
28
|
|
|
40
|
-
**ESQL helper**: `HTTPResponseAdapter_CheckCallType.esql`
|
|
41
|
-
-
|
|
29
|
+
**ESQL helper**: `HTTPResponseAdapter_CheckCallType.esql` (FILTER)
|
|
30
|
+
- Reads `Root.MQRFH2.usr.http.reply.callType`: returns FALSE for `'EXTERNAL'`, TRUE otherwise.
|
|
31
|
+
- The call type is stamped upstream by `InternalHTTPRequestAdapter_SetCallType.esql`, which sets
|
|
32
|
+
`MQRFH2.usr.http.reply.callType = 'INTERNAL'` (and the reply id) for internal calls.
|
|
42
33
|
|
|
43
34
|
**Always pair with** `HTTPRequestAdapter` — use both or neither.
|
|
44
35
|
|
|
@@ -18,25 +18,35 @@ All input adapters live in `Qiwa/Framework/Lib/`. Use them as the entry point of
|
|
|
18
18
|
**ESQL helper modules used**:
|
|
19
19
|
| Module | Purpose |
|
|
20
20
|
|---|---|
|
|
21
|
-
| `
|
|
22
|
-
| `
|
|
23
|
-
| `
|
|
24
|
-
| `
|
|
25
|
-
| `
|
|
21
|
+
| `MQ_Input_Node.esql` (`MQ_Input_Node_Compute`, `Filter_IS_Audit_Enabled_Input_Node`) | Main compute + input audit gate (`ENABLE_AUDIT_INPUT`) |
|
|
22
|
+
| `MQ_Input_Node_IsAuditEnabled.esql` | Filter: `Logging.LogEnabled OR Logging.AuditEnabled` |
|
|
23
|
+
| `MQ_Input_Node_IsPropertiesEnabled.esql` | Filter: is PropertyReader enabled (`PROPERTIES_ENABLED`) |
|
|
24
|
+
| `MQ_Input_Node_IsRetryEnabled.esql` | Filter: `Retry.RetryEnabled` |
|
|
25
|
+
| `MQ_Input_Node_IsRollBackEnabled.esql` | Filter: `ROLL_BACK_TRANSACTION` |
|
|
26
|
+
| `MQ_Input_Node_SetMsgUIDinEnv.esql` | Compute: stash message UID in Environment |
|
|
27
|
+
| `MQ_Input_Node_PrepareAuditMessage.esql` | Compute: build audit payload → `LogAudit` |
|
|
26
28
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
29
|
+
(`MQ_Input_Node_IsAuditEnabled.esql` also defines `MQ_Input_Node_IsSchemaValidationEnabled` and `MQ_OutputNode_IsServiceOut`.)
|
|
30
|
+
|
|
31
|
+
**Configuration (Properties XML)** — each filter reads its property, and if the flow's property group
|
|
32
|
+
is absent it falls back to the node EXTERNAL default:
|
|
33
|
+
|
|
34
|
+
| Property (group) | EXTERNAL fallback |
|
|
35
|
+
|---|---|
|
|
36
|
+
| `Logging.LogEnabled` / `Logging.AuditEnabled` | `LOG_ENABLED` (also `ENABLE_AUDIT_INPUT`) |
|
|
37
|
+
| `Retry.RetryEnabled` | `RETRY_ENABLED` |
|
|
38
|
+
| `SchemaValidation.ValidationEnabled` | `SCHEMA_VALIDATION_ENABLED` |
|
|
39
|
+
| (rollback — flag only) | `ROLL_BACK_TRANSACTION` |
|
|
40
|
+
| (PropertyReader on/off — flag only) | `PROPERTIES_ENABLED` |
|
|
34
41
|
|
|
35
|
-
**ESQL
|
|
42
|
+
**ESQL EXTERNAL flags on this node** (real names — all default as noted):
|
|
36
43
|
```esql
|
|
37
|
-
DECLARE
|
|
38
|
-
DECLARE
|
|
39
|
-
DECLARE
|
|
44
|
+
DECLARE PROPERTIES_ENABLED EXTERNAL BOOLEAN FALSE;
|
|
45
|
+
DECLARE LOG_ENABLED EXTERNAL BOOLEAN FALSE;
|
|
46
|
+
DECLARE SCHEMA_VALIDATION_ENABLED EXTERNAL BOOLEAN FALSE;
|
|
47
|
+
DECLARE RETRY_ENABLED EXTERNAL BOOLEAN FALSE;
|
|
48
|
+
DECLARE ROLL_BACK_TRANSACTION EXTERNAL BOOLEAN FALSE;
|
|
49
|
+
DECLARE ENABLE_AUDIT_INPUT EXTERNAL BOOLEAN TRUE;
|
|
40
50
|
```
|
|
41
51
|
|
|
42
52
|
**When to use**: Any flow that reads from an IBM MQ queue asynchronously.
|
|
@@ -8,9 +8,13 @@ All output adapters live in `Qiwa/Framework/Lib/`. Use them as the exit point of
|
|
|
8
8
|
|
|
9
9
|
**Purpose**: Standard MQ output. Writes message to a target queue.
|
|
10
10
|
|
|
11
|
-
**ESQL module**: `MQ_Output_Node.esql`
|
|
12
|
-
- Copies
|
|
13
|
-
-
|
|
11
|
+
**ESQL module**: `MQ_Output_Node.esql` (`MQ_Output_Node_Compute` + `Filter_Is_Audit_Enabled_Output_Node`)
|
|
12
|
+
- Copies headers, then defaults `MQMD.CorrelId` to `MQMD.MsgId` when empty/zero
|
|
13
|
+
- Applies `MQMD.Priority` from `Environment.Properties.{ApplicationLabel}.{flowName}.Priority.Priority` when present
|
|
14
|
+
- Optional output audit gated by EXTERNAL `ENABLE_AUDIT_OUTPUT` (default `TRUE`)
|
|
15
|
+
- It does **not** choose the destination queue — that is set upstream on
|
|
16
|
+
`LocalEnvironment.Destination.MQ.DestinationData[1].queueName` (by `SetQueues`,
|
|
17
|
+
`MQ_OutputNode_IsServiceOut`, or `MQ_OutputNode_IsDeadFlow`)
|
|
14
18
|
|
|
15
19
|
**When to use**: Standard async MQ output for any request or response message.
|
|
16
20
|
|
|
@@ -20,11 +24,14 @@ All output adapters live in `Qiwa/Framework/Lib/`. Use them as the exit point of
|
|
|
20
24
|
|
|
21
25
|
**Purpose**: Routes failed/unprocessable messages to a backout/dead-letter queue.
|
|
22
26
|
|
|
23
|
-
**ESQL module**: `MQ_OutputNode_IsDeadFlow.esql`
|
|
27
|
+
**ESQL module**: `MQ_OutputNode_IsDeadFlow.esql` (FILTER, EXTERNAL `DEAD_FLOW BOOLEAN FALSE`)
|
|
28
|
+
- When `DEAD_FLOW` is TRUE → dead path. Otherwise it sets the destination from
|
|
29
|
+
`Root.MQRFH2.usr.queue.distinationQueue` (sic) and returns FALSE.
|
|
24
30
|
|
|
25
31
|
**When to use**: Always wire this as the terminal node on the error path of every MQ flow.
|
|
26
32
|
|
|
27
|
-
**Queue naming**: `<ORIGINAL_QUEUE_NAME>.BACKOUT`
|
|
33
|
+
**Queue naming**: backout/dead queues follow the `<ORIGINAL_QUEUE_NAME>.BACKOUT` convention (see
|
|
34
|
+
[naming-conventions](../config/naming-conventions.md)).
|
|
28
35
|
|
|
29
36
|
---
|
|
30
37
|
|
|
@@ -34,7 +41,7 @@ All output adapters live in `Qiwa/Framework/Lib/`. Use them as the exit point of
|
|
|
34
41
|
|
|
35
42
|
**When to use**: Flows where the destination queue varies per message (e.g., routing based on `ServiceCode`).
|
|
36
43
|
|
|
37
|
-
**How it works**: Reads queue name from `
|
|
44
|
+
**How it works**: Reads the queue name from `LocalEnvironment.Destination.MQ.DestinationData[1].queueName` — set this dynamically in your compute ESQL (via `OutputLocalEnvironment.Destination...`) before this subflow.
|
|
38
45
|
|
|
39
46
|
---
|
|
40
47
|
|
|
@@ -66,8 +73,8 @@ All output adapters live in `Qiwa/Framework/Lib/`. Use them as the exit point of
|
|
|
66
73
|
|
|
67
74
|
**Purpose**: Makes outbound HTTP/SOAP calls to backend services.
|
|
68
75
|
|
|
69
|
-
**
|
|
70
|
-
|
|
76
|
+
**Node properties**: EXTERNAL `ServiceURL`, `TimeoutInSec`. (Call-type detection lives in
|
|
77
|
+
`HTTPResponseAdapter`, not here — see [http-adapters](http-adapters.md).)
|
|
71
78
|
|
|
72
79
|
**When to use**: Any flow that calls an external REST or SOAP service (T24, NIWS, ODM, Unifonic, MLSD, etc.).
|
|
73
80
|
|
|
@@ -109,16 +116,16 @@ All output adapters live in `Qiwa/Framework/Lib/`. Use them as the exit point of
|
|
|
109
116
|
|
|
110
117
|
---
|
|
111
118
|
|
|
112
|
-
## ESQL Copy Utilities
|
|
119
|
+
## ESQL Copy Utilities
|
|
113
120
|
|
|
114
|
-
Every
|
|
121
|
+
Every framework module defines its own `CopyMessageHeaders()` and `CopyEntireMessage()` procedures
|
|
122
|
+
inline (they are not imported from a shared module):
|
|
115
123
|
|
|
116
124
|
```esql
|
|
117
|
-
--
|
|
118
|
-
CALL
|
|
119
|
-
|
|
120
|
-
-- Copy entire message tree
|
|
121
|
-
CALL CopyEntireMessage();
|
|
125
|
+
CALL CopyMessageHeaders(); -- copy header folders 1..N-1 (preserves MQMD, MQRFH2)
|
|
126
|
+
CALL CopyEntireMessage(); -- SET OutputRoot = InputRoot;
|
|
122
127
|
```
|
|
123
128
|
|
|
124
|
-
|
|
129
|
+
`copy_Compute.esql` is a ready-made generic copy COMPUTE node — it calls both procedures and also
|
|
130
|
+
copies `LocalEnvironment.Wildcard.WildcardMatch`. Use it when you just need a pass-through copy node.
|
|
131
|
+
Always copy headers before modifying output to preserve MQ metadata.
|
|
@@ -26,8 +26,12 @@
|
|
|
26
26
|
|
|
27
27
|
Properties are accessed via the path:
|
|
28
28
|
```
|
|
29
|
-
Environment.Properties.{ApplicationLabel}.{
|
|
29
|
+
Environment.Properties.{ApplicationLabel}.{flowName}.{Group}.{PropertyName}
|
|
30
30
|
```
|
|
31
|
+
where `ApplicationLabel` is the broker built-in (application name) and `flowName` is derived from the
|
|
32
|
+
built-in `MessageFlowLabel` via `getFlowNameWithouSchema(Environment.FlowNameSplit)` — both are
|
|
33
|
+
resolved at runtime, not hardcoded. Framework filters guard against the group being absent and fall
|
|
34
|
+
back to the node's EXTERNAL default (e.g. `LOG_ENABLED`, `RETRY_ENABLED`).
|
|
31
35
|
|
|
32
36
|
Examples:
|
|
33
37
|
```esql
|
|
@@ -66,24 +70,32 @@ These tokens in property values are replaced at runtime:
|
|
|
66
70
|
|
|
67
71
|
| Token | Replaced With |
|
|
68
72
|
|---|---|
|
|
69
|
-
| `${broker.name}` | ACE broker/integration node name |
|
|
70
|
-
| `${execution.group}` | Execution group / integration server name |
|
|
71
|
-
| `${flow.name}` | Message flow name |
|
|
72
|
-
|
|
73
|
+
| `${broker.name}` | ACE broker/integration node name (`BrokerName`) |
|
|
74
|
+
| `${execution.group}` | Execution group / integration server name (`ExecutionGroupLabel`) |
|
|
75
|
+
| `${flow.name}` | Message flow name (`MessageFlowLabel`) |
|
|
76
|
+
|
|
77
|
+
(Only these three tokens are substituted by `PropertyReader_LoadProperties`.)
|
|
73
78
|
|
|
74
79
|
---
|
|
75
80
|
|
|
76
|
-
##
|
|
81
|
+
## PropertyReader node properties
|
|
82
|
+
|
|
83
|
+
`PropertyReader_LoadProperties.esql` declares these EXTERNAL (user-defined) properties — set them on the PropertyReader subflow node:
|
|
77
84
|
|
|
78
85
|
```esql
|
|
79
|
-
|
|
80
|
-
DECLARE
|
|
81
|
-
DECLARE
|
|
86
|
+
DECLARE PropertyFilename EXTERNAL CHARACTER '*'; -- the XML config file
|
|
87
|
+
DECLARE PropertiesGroup EXTERNAL CHARACTER '*'; -- which group(s) to load
|
|
88
|
+
DECLARE LogicalTreePath EXTERNAL CHARACTER 'Environment'; -- target tree (must start Environment. or OutputLocalEnvironment.)
|
|
82
89
|
```
|
|
83
90
|
|
|
84
|
-
|
|
85
|
-
- `
|
|
86
|
-
- `
|
|
91
|
+
Typical node values (note the `${broker.name}` token):
|
|
92
|
+
- `PropertyFilename`: `${broker.name}/ACCOUNT.xml`
|
|
93
|
+
- `PropertiesGroup`: the property group, e.g. `BS_Account.GetAccountDetails`
|
|
94
|
+
- `LogicalTreePath`: leave as `Environment` (default) → properties land under `Environment.Properties`
|
|
95
|
+
|
|
96
|
+
It reads the file via the external `readerProperties(configFile, PropertiesGroup)` routine and builds
|
|
97
|
+
the tree under `LogicalTreePath`. `ApplicationLabel` is **not** a PropertyReader external — it is a
|
|
98
|
+
broker built-in correlation name (the application/library name), used when reading properties back.
|
|
87
99
|
|
|
88
100
|
---
|
|
89
101
|
|
|
@@ -8,19 +8,22 @@ The framework provides configurable retry for MQ-based flows using `RetryPoint.s
|
|
|
8
8
|
|
|
9
9
|
| Component | Type | Purpose |
|
|
10
10
|
|---|---|---|
|
|
11
|
-
| `RetryPoint.subflow` | subflow | Re-queue message after failure with delay |
|
|
12
|
-
| `SetRetryProperties.esql` | esql |
|
|
11
|
+
| `RetryPoint.subflow` | subflow | Re-queue message after failure with delay (runs `SetRetryProperties`) |
|
|
12
|
+
| `SetRetryProperties.esql` | esql | Seed the `MQRFH2.usr.retry` struct from `Retry` properties (or node externals) |
|
|
13
|
+
| `MQ_Input_Node_IsRetryEnabled.esql` | esql | FILTER: `Retry.RetryEnabled` (fallback EXTERNAL `RETRY_ENABLED`) |
|
|
13
14
|
|
|
14
15
|
---
|
|
15
16
|
|
|
16
17
|
## How It Works
|
|
17
18
|
|
|
18
|
-
1. On failure, message is caught
|
|
19
|
-
2.
|
|
20
|
-
3. If enabled, routes to `RetryPoint`
|
|
21
|
-
4. `SetRetryProperties
|
|
22
|
-
|
|
23
|
-
|
|
19
|
+
1. On failure, the message is caught on the MQ input error path
|
|
20
|
+
2. Retry is gated by `Retry.RetryEnabled` (filter `MQ_Input_Node_IsRetryEnabled`; fallback EXTERNAL `RETRY_ENABLED`)
|
|
21
|
+
3. If enabled, routes to `RetryPoint`, which runs `SetRetryProperties`
|
|
22
|
+
4. `SetRetryProperties` seeds the `MQRFH2.usr.retry` struct **only when not already present**:
|
|
23
|
+
`maxRetryCount`, `minWaitDurationSec`, and `sourceQueue` (= `InputRoot.MQMD.SourceQueue`).
|
|
24
|
+
The attempt counter is `MQRFH2.usr.retry.count` (read by `AuditPoint`)
|
|
25
|
+
5. The message is re-queued to `MQRFH2.usr.retry.sourceQueue` after `minWaitDurationSec`
|
|
26
|
+
6. When the attempt count reaches `maxRetryCount` → route to `MQ_Dead_Output_Node`
|
|
24
27
|
|
|
25
28
|
---
|
|
26
29
|
|
|
@@ -36,39 +39,41 @@ Under the `Retry` group for each flow:
|
|
|
36
39
|
</group>
|
|
37
40
|
```
|
|
38
41
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
|
43
|
-
|
|
42
|
+
When the flow's `Retry` property group is present, values come from properties; otherwise
|
|
43
|
+
`SetRetryProperties` falls back to the node EXTERNAL defaults:
|
|
44
|
+
|
|
45
|
+
| Property (group `Retry`) | EXTERNAL fallback | Default | Description |
|
|
46
|
+
|---|---|---|---|
|
|
47
|
+
| `RetryEnabled` | `RETRY_ENABLED` | `FALSE` | Enable/disable retry |
|
|
48
|
+
| `maxRetryCount` | `MAX_RETRY_COUNT` | `0` | Max attempts before dead-lettering |
|
|
49
|
+
| `minWaitDurationSec` | `MIN_WAIT_TIME_SEC` | `60` | Seconds to wait before re-queue |
|
|
44
50
|
|
|
45
51
|
---
|
|
46
52
|
|
|
47
|
-
## MQRFH2
|
|
53
|
+
## MQRFH2 retry struct
|
|
48
54
|
|
|
49
|
-
|
|
55
|
+
`SetRetryProperties` writes a **struct** under `MQRFH2.usr.retry` (not a scalar):
|
|
56
|
+
|
|
57
|
+
| Field | Purpose |
|
|
50
58
|
|---|---|
|
|
51
|
-
| `MQRFH2.usr.retry` | Current
|
|
52
|
-
| `MQRFH2.usr.
|
|
59
|
+
| `MQRFH2.usr.retry.count` | Current attempt count (read by `AuditPoint`) |
|
|
60
|
+
| `MQRFH2.usr.retry.maxRetryCount` | Max attempts for this message |
|
|
61
|
+
| `MQRFH2.usr.retry.minWaitDurationSec` | Delay before re-queue |
|
|
62
|
+
| `MQRFH2.usr.retry.sourceQueue` | Original queue (`MQMD.SourceQueue`) to re-queue to |
|
|
53
63
|
|
|
54
64
|
---
|
|
55
65
|
|
|
56
66
|
## ESQL for Retry Check
|
|
57
67
|
|
|
58
68
|
```esql
|
|
59
|
-
--
|
|
60
|
-
DECLARE retryCount INT;
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
-- Get max from properties
|
|
64
|
-
DECLARE maxRetry INT;
|
|
65
|
-
SET maxRetry = Environment.Properties.{AppLabel}.{flowName}.Retry.maxRetryCount;
|
|
69
|
+
-- Current attempt count and limit
|
|
70
|
+
DECLARE retryCount INT CAST(InputRoot.MQRFH2.usr.retry.count AS INT);
|
|
71
|
+
DECLARE maxRetry INT CAST(InputRoot.MQRFH2.usr.retry.maxRetryCount AS INT);
|
|
66
72
|
|
|
67
73
|
IF retryCount >= maxRetry THEN
|
|
68
|
-
-- route to
|
|
74
|
+
-- limit reached → route to MQ_Dead_Output_Node
|
|
69
75
|
ELSE
|
|
70
|
-
|
|
71
|
-
SET OutputRoot.MQRFH2.usr.retry = retryCount + 1;
|
|
76
|
+
SET OutputRoot.MQRFH2.usr.retry.count = retryCount + 1; -- re-queue to .sourceQueue
|
|
72
77
|
END IF;
|
|
73
78
|
```
|
|
74
79
|
|
|
@@ -7,13 +7,16 @@ All naming in this framework follows strict conventions. The agent MUST follow t
|
|
|
7
7
|
## ESQL Broker Schema
|
|
8
8
|
|
|
9
9
|
```esql
|
|
10
|
-
BROKER SCHEMA
|
|
10
|
+
BROKER SCHEMA com.qiwa.esb.<msgflowname-lower>
|
|
11
11
|
-- Examples:
|
|
12
|
-
BROKER SCHEMA
|
|
13
|
-
BROKER SCHEMA
|
|
14
|
-
BROKER SCHEMA Qiwa.Framework.Lib ← shared
|
|
12
|
+
BROKER SCHEMA com.qiwa.esb.getaccountdetails
|
|
13
|
+
BROKER SCHEMA com.qiwa.esb.createtransfer
|
|
14
|
+
BROKER SCHEMA Qiwa.Framework.Lib ← shared framework library only, never use for app code
|
|
15
15
|
```
|
|
16
16
|
|
|
17
|
+
The schema is the message-flow name, lowercased, with no separators. App ESQL must also
|
|
18
|
+
`PATH Qiwa.Framework.Lib;` to resolve the shared framework routines.
|
|
19
|
+
|
|
17
20
|
---
|
|
18
21
|
|
|
19
22
|
## ESQL Module Naming
|
|
@@ -174,7 +177,7 @@ Standard terminal names used in the framework:
|
|
|
174
177
|
|
|
175
178
|
| Artifact | Format | Example |
|
|
176
179
|
|---|---|---|
|
|
177
|
-
| ESQL schema | `
|
|
180
|
+
| ESQL schema | `com.qiwa.esb.<msgflowname-lower>` | `com.qiwa.esb.getaccountdetails` |
|
|
178
181
|
| ESQL module | `<Flow>_<Purpose>.esql` | `GetAccountDetails_Compute.esql` |
|
|
179
182
|
| Message flow | `<FlowName>.msgflow` | `GetAccountDetails.msgflow` |
|
|
180
183
|
| Application | `<Tier>_<Domain>` | `BS_Account` |
|
|
@@ -27,8 +27,9 @@ Use ALL-CAPS domain name.
|
|
|
27
27
|
|
|
28
28
|
<!--
|
|
29
29
|
Group name format: {ApplicationLabel}.{FlowName}
|
|
30
|
-
ApplicationLabel:
|
|
30
|
+
ApplicationLabel: the broker built-in application/library name, e.g. "BS_MyService"
|
|
31
31
|
FlowName: the message flow name, e.g. "GetMyData"
|
|
32
|
+
This whole group name is what you pass as PropertiesGroup on the PropertyReader node.
|
|
32
33
|
-->
|
|
33
34
|
<group name="BS_MyService.GetMyData">
|
|
34
35
|
|