@onlineapps/conn-orch-orchestrator 1.0.1 → 1.0.3
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/API.md +0 -0
- package/README.md +97 -544
- package/jest.config.js +3 -3
- package/jest.setup.js +0 -0
- package/onlineapps-conn-orch-orchestrator-1.0.1.tgz +0 -0
- package/package.json +3 -3
- package/src/WorkflowOrchestrator.js +99 -17
- package/src/index.js +0 -0
- package/{test → tests}/component/orchestrator.component.test.js +1 -1
- package/{test → tests}/integration/orchestrator.integration.test.js +4 -3
- package/{test → tests}/unit/WorkflowOrchestrator.test.js +1 -1
package/API.md
CHANGED
|
File without changes
|
package/README.md
CHANGED
|
@@ -1,585 +1,138 @@
|
|
|
1
|
-
|
|
1
|
+
# @onlineapps/conn-orch-orchestrator
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
Workflow orchestration coordinator managing complete workflow execution.
|
|
5
|
-
Provides centralized control flow handling, step routing, and workflow state management
|
|
6
|
-
for OA Drive microservices.
|
|
3
|
+
Workflow orchestration coordinator managing complete workflow execution for OA Drive microservices.
|
|
7
4
|
|
|
8
|
-
|
|
9
|
-
**Since**: 1.0.0
|
|
10
|
-
**Author**: OA Drive Team
|
|
11
|
-
**License**: MIT
|
|
5
|
+
## Features
|
|
12
6
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
* [new OrchestratorConnector(config)](#new_module_@onlineapps/conn-orch-orchestrator..OrchestratorConnector_new)
|
|
20
|
-
* [~OrchestratorConnector](#module_@onlineapps/conn-orch-orchestrator..OrchestratorConnector)
|
|
21
|
-
* [new OrchestratorConnector()](#new_module_@onlineapps/conn-orch-orchestrator..OrchestratorConnector_new)
|
|
22
|
-
* [new OrchestratorConnector(config)](#new_module_@onlineapps/conn-orch-orchestrator..OrchestratorConnector_new)
|
|
23
|
-
* [~processWorkflowMessage(message)](#module_@onlineapps/conn-orch-orchestrator..processWorkflowMessage) ⇒ <code>Promise.<WorkflowResult></code> \| <code>boolean</code> \| <code>string</code> \| <code>number</code>
|
|
24
|
-
* [~processStep(message)](#module_@onlineapps/conn-orch-orchestrator..processStep) ⇒ <code>Promise.<\*></code>
|
|
25
|
-
* [~handleControlFlow(step, message)](#module_@onlineapps/conn-orch-orchestrator..handleControlFlow) ⇒ <code>Promise.<\*></code>
|
|
26
|
-
* [~handleIfStep(step, message)](#module_@onlineapps/conn-orch-orchestrator..handleIfStep) ⇒ <code>Promise.<\*></code>
|
|
27
|
-
* [~handleForeachStep(step, message)](#module_@onlineapps/conn-orch-orchestrator..handleForeachStep) ⇒ <code>Promise.<Array></code>
|
|
28
|
-
* [~handleForkJoinStep(step, message)](#module_@onlineapps/conn-orch-orchestrator..handleForkJoinStep) ⇒ <code>Promise.<\*></code>
|
|
29
|
-
* [~handleSwitchStep(step, message)](#module_@onlineapps/conn-orch-orchestrator..handleSwitchStep) ⇒ <code>Promise.<\*></code>
|
|
30
|
-
* [~routeToNextService(message, nextService, stepResult, nextIndex)](#module_@onlineapps/conn-orch-orchestrator..routeToNextService) ⇒ <code>Promise.<void></code>
|
|
31
|
-
* [~completeWorkflow(message, finalResult)](#module_@onlineapps/conn-orch-orchestrator..completeWorkflow) ⇒ <code>Promise.<void></code>
|
|
32
|
-
* [~handleWorkflowFailure(message, error)](#module_@onlineapps/conn-orch-orchestrator..handleWorkflowFailure) ⇒ <code>Promise.<void></code>
|
|
33
|
-
* [~getStats()](#module_@onlineapps/conn-orch-orchestrator..getStats) ⇒ <code>OrchestratorStats</code> \| <code>number</code> \| <code>number</code> \| <code>number</code> \| <code>number</code> \| <code>number</code> \| <code>number</code>
|
|
34
|
-
* [~resetStats()](#module_@onlineapps/conn-orch-orchestrator..resetStats) ⇒ <code>void</code>
|
|
35
|
-
* [~create(config)](#module_@onlineapps/conn-orch-orchestrator..create) ⇒ <code>OrchestratorConnector</code>
|
|
36
|
-
* [~WorkflowMessage](#module_@onlineapps/conn-orch-orchestrator..WorkflowMessage) : <code>Object</code>
|
|
37
|
-
* [~WorkflowResult](#module_@onlineapps/conn-orch-orchestrator..WorkflowResult) : <code>Object</code>
|
|
38
|
-
* [~ControlFlowStep](#module_@onlineapps/conn-orch-orchestrator..ControlFlowStep) : <code>Object</code>
|
|
39
|
-
* [~OrchestratorStats](#module_@onlineapps/conn-orch-orchestrator..OrchestratorStats) : <code>Object</code>
|
|
7
|
+
- 🎯 **Workflow coordination** - Complete workflow execution management
|
|
8
|
+
- 🔀 **Control flow handling** - If/else, switch, foreach, fork-join patterns
|
|
9
|
+
- 📊 **State management** - Workflow state tracking and persistence
|
|
10
|
+
- 🚦 **Step routing** - Intelligent routing to next services
|
|
11
|
+
- 📈 **Statistics tracking** - Workflow execution metrics
|
|
12
|
+
- ⚡ **Async processing** - Non-blocking workflow execution
|
|
40
13
|
|
|
41
|
-
|
|
14
|
+
## Installation
|
|
42
15
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
**Kind**: static constant of [<code>@onlineapps/conn-orch-orchestrator</code>](#module_@onlineapps/conn-orch-orchestrator)
|
|
47
|
-
<a name="module_@onlineapps/conn-orch-orchestrator..OrchestratorConnector"></a>
|
|
48
|
-
|
|
49
|
-
### @onlineapps/conn-orch-orchestrator~OrchestratorConnector
|
|
50
|
-
**Kind**: inner class of [<code>@onlineapps/conn-orch-orchestrator</code>](#module_@onlineapps/conn-orch-orchestrator)
|
|
51
|
-
|
|
52
|
-
* [~OrchestratorConnector](#module_@onlineapps/conn-orch-orchestrator..OrchestratorConnector)
|
|
53
|
-
* [new OrchestratorConnector()](#new_module_@onlineapps/conn-orch-orchestrator..OrchestratorConnector_new)
|
|
54
|
-
* [new OrchestratorConnector(config)](#new_module_@onlineapps/conn-orch-orchestrator..OrchestratorConnector_new)
|
|
55
|
-
|
|
56
|
-
<a name="new_module_@onlineapps/conn-orch-orchestrator..OrchestratorConnector_new"></a>
|
|
57
|
-
|
|
58
|
-
#### new OrchestratorConnector()
|
|
59
|
-
Workflow orchestration connector managing complete workflow execution
|
|
60
|
-
|
|
61
|
-
**Example** *(Basic Usage)*
|
|
62
|
-
```js
|
|
63
|
-
const orchestrator = new OrchestratorConnector({
|
|
64
|
-
mqClient: mqConnector,
|
|
65
|
-
cookbook: cookbookConnector,
|
|
66
|
-
apiMapper: apiMapperConnector,
|
|
67
|
-
serviceName: 'invoice-service'
|
|
68
|
-
});
|
|
69
|
-
|
|
70
|
-
await orchestrator.processWorkflowMessage(message);
|
|
71
|
-
```
|
|
72
|
-
**Example** *(With Caching)*
|
|
73
|
-
```js
|
|
74
|
-
const orchestrator = new OrchestratorConnector({
|
|
75
|
-
mqClient: mqConnector,
|
|
76
|
-
cookbook: cookbookConnector,
|
|
77
|
-
apiMapper: apiMapperConnector,
|
|
78
|
-
cache: cacheConnector,
|
|
79
|
-
serviceName: 'invoice-service',
|
|
80
|
-
defaultTimeout: 60000
|
|
81
|
-
});
|
|
82
|
-
```
|
|
83
|
-
<a name="new_module_@onlineapps/conn-orch-orchestrator..OrchestratorConnector_new"></a>
|
|
84
|
-
|
|
85
|
-
#### new OrchestratorConnector(config)
|
|
86
|
-
Creates a new OrchestratorConnector instance
|
|
87
|
-
|
|
88
|
-
**Throws**:
|
|
89
|
-
|
|
90
|
-
- <code>TypeError</code> If required dependencies are missing
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
| Param | Type | Default | Description |
|
|
94
|
-
| --- | --- | --- | --- |
|
|
95
|
-
| config | <code>Object</code> | | Configuration object |
|
|
96
|
-
| config.mqClient | <code>Object</code> | | MQ client connector for message routing |
|
|
97
|
-
| config.cookbook | <code>Object</code> | | Cookbook connector for workflow parsing |
|
|
98
|
-
| [config.apiMapper] | <code>Object</code> | | API mapper for HTTP calls |
|
|
99
|
-
| [config.cache] | <code>Object</code> | | Cache connector for step caching |
|
|
100
|
-
| [config.logger] | <code>Object</code> | <code>console</code> | Logger instance |
|
|
101
|
-
| [config.serviceName] | <code>string</code> | <code>"'unknown'"</code> | Service name for tracing |
|
|
102
|
-
| [config.defaultTimeout] | <code>number</code> | <code>30000</code> | Default timeout in ms |
|
|
103
|
-
| [config.maxStepRetries] | <code>number</code> | <code>3</code> | Maximum retries per step |
|
|
104
|
-
|
|
105
|
-
**Example** *(Full Configuration)*
|
|
106
|
-
```js
|
|
107
|
-
const orchestrator = new OrchestratorConnector({
|
|
108
|
-
mqClient: mqConnector,
|
|
109
|
-
cookbook: cookbookConnector,
|
|
110
|
-
apiMapper: apiMapperConnector,
|
|
111
|
-
cache: cacheConnector,
|
|
112
|
-
logger: loggerConnector,
|
|
113
|
-
serviceName: 'invoice-service',
|
|
114
|
-
defaultTimeout: 60000,
|
|
115
|
-
maxStepRetries: 5
|
|
116
|
-
});
|
|
117
|
-
```
|
|
118
|
-
<a name="module_@onlineapps/conn-orch-orchestrator..OrchestratorConnector"></a>
|
|
119
|
-
|
|
120
|
-
### @onlineapps/conn-orch-orchestrator~OrchestratorConnector
|
|
121
|
-
**Kind**: inner class of [<code>@onlineapps/conn-orch-orchestrator</code>](#module_@onlineapps/conn-orch-orchestrator)
|
|
122
|
-
|
|
123
|
-
* [~OrchestratorConnector](#module_@onlineapps/conn-orch-orchestrator..OrchestratorConnector)
|
|
124
|
-
* [new OrchestratorConnector()](#new_module_@onlineapps/conn-orch-orchestrator..OrchestratorConnector_new)
|
|
125
|
-
* [new OrchestratorConnector(config)](#new_module_@onlineapps/conn-orch-orchestrator..OrchestratorConnector_new)
|
|
126
|
-
|
|
127
|
-
<a name="new_module_@onlineapps/conn-orch-orchestrator..OrchestratorConnector_new"></a>
|
|
128
|
-
|
|
129
|
-
#### new OrchestratorConnector()
|
|
130
|
-
Workflow orchestration connector managing complete workflow execution
|
|
131
|
-
|
|
132
|
-
**Example** *(Basic Usage)*
|
|
133
|
-
```js
|
|
134
|
-
const orchestrator = new OrchestratorConnector({
|
|
135
|
-
mqClient: mqConnector,
|
|
136
|
-
cookbook: cookbookConnector,
|
|
137
|
-
apiMapper: apiMapperConnector,
|
|
138
|
-
serviceName: 'invoice-service'
|
|
139
|
-
});
|
|
140
|
-
|
|
141
|
-
await orchestrator.processWorkflowMessage(message);
|
|
142
|
-
```
|
|
143
|
-
**Example** *(With Caching)*
|
|
144
|
-
```js
|
|
145
|
-
const orchestrator = new OrchestratorConnector({
|
|
146
|
-
mqClient: mqConnector,
|
|
147
|
-
cookbook: cookbookConnector,
|
|
148
|
-
apiMapper: apiMapperConnector,
|
|
149
|
-
cache: cacheConnector,
|
|
150
|
-
serviceName: 'invoice-service',
|
|
151
|
-
defaultTimeout: 60000
|
|
152
|
-
});
|
|
16
|
+
```bash
|
|
17
|
+
npm install @onlineapps/conn-orch-orchestrator
|
|
153
18
|
```
|
|
154
|
-
<a name="new_module_@onlineapps/conn-orch-orchestrator..OrchestratorConnector_new"></a>
|
|
155
19
|
|
|
156
|
-
|
|
157
|
-
Creates a new OrchestratorConnector instance
|
|
20
|
+
## Quick Start
|
|
158
21
|
|
|
159
|
-
|
|
22
|
+
```javascript
|
|
23
|
+
const { OrchestratorConnector } = require('@onlineapps/conn-orch-orchestrator');
|
|
160
24
|
|
|
161
|
-
- <code>TypeError</code> If required dependencies are missing
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
| Param | Type | Default | Description |
|
|
165
|
-
| --- | --- | --- | --- |
|
|
166
|
-
| config | <code>Object</code> | | Configuration object |
|
|
167
|
-
| config.mqClient | <code>Object</code> | | MQ client connector for message routing |
|
|
168
|
-
| config.cookbook | <code>Object</code> | | Cookbook connector for workflow parsing |
|
|
169
|
-
| [config.apiMapper] | <code>Object</code> | | API mapper for HTTP calls |
|
|
170
|
-
| [config.cache] | <code>Object</code> | | Cache connector for step caching |
|
|
171
|
-
| [config.logger] | <code>Object</code> | <code>console</code> | Logger instance |
|
|
172
|
-
| [config.serviceName] | <code>string</code> | <code>"'unknown'"</code> | Service name for tracing |
|
|
173
|
-
| [config.defaultTimeout] | <code>number</code> | <code>30000</code> | Default timeout in ms |
|
|
174
|
-
| [config.maxStepRetries] | <code>number</code> | <code>3</code> | Maximum retries per step |
|
|
175
|
-
|
|
176
|
-
**Example** *(Full Configuration)*
|
|
177
|
-
```js
|
|
178
25
|
const orchestrator = new OrchestratorConnector({
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
apiMapper: apiMapperConnector,
|
|
182
|
-
cache: cacheConnector,
|
|
183
|
-
logger: loggerConnector,
|
|
184
|
-
serviceName: 'invoice-service',
|
|
185
|
-
defaultTimeout: 60000,
|
|
186
|
-
maxStepRetries: 5
|
|
26
|
+
amqpUrl: process.env.AMQP_URL,
|
|
27
|
+
storageUrl: process.env.MINIO_URL
|
|
187
28
|
});
|
|
188
|
-
```
|
|
189
|
-
<a name="module_@onlineapps/conn-orch-orchestrator..processWorkflowMessage"></a>
|
|
190
29
|
|
|
191
|
-
|
|
192
|
-
Process workflow message - main entry point
|
|
193
|
-
|
|
194
|
-
**Kind**: inner method of [<code>@onlineapps/conn-orch-orchestrator</code>](#module_@onlineapps/conn-orch-orchestrator)
|
|
195
|
-
**Returns**: <code>Promise.<WorkflowResult></code> - Processing result<code>boolean</code> - result.success - Whether processing succeeded<code>string</code> - result.workflowId - Workflow ID<code>number</code> - result.duration - Processing duration in ms
|
|
196
|
-
**Throws**:
|
|
197
|
-
|
|
198
|
-
- <code>Error</code> If cookbook validation fails
|
|
199
|
-
- <code>Error</code> If step processing fails
|
|
200
|
-
|
|
201
|
-
**Emits**: [<code>completed</code>](#OrchestratorConnector+workflow.event_completed), [<code>failed</code>](#OrchestratorConnector+workflow.event_failed)
|
|
202
|
-
|
|
203
|
-
| Param | Type | Default | Description |
|
|
204
|
-
| --- | --- | --- | --- |
|
|
205
|
-
| message | <code>WorkflowMessage</code> | | Workflow message to process |
|
|
206
|
-
| [message.workflow_id] | <code>string</code> | | Unique workflow ID |
|
|
207
|
-
| message.cookbook | <code>Object</code> | | Cookbook definition |
|
|
208
|
-
| [message.current_step] | <code>number</code> | <code>0</code> | Current step index |
|
|
209
|
-
| [message.context] | <code>Object</code> | <code>{}</code> | Workflow context data |
|
|
210
|
-
| [message.trace] | <code>Array</code> | <code>[]</code> | Execution trace |
|
|
211
|
-
|
|
212
|
-
**Example** *(Process Workflow)*
|
|
213
|
-
```js
|
|
30
|
+
// Process workflow message
|
|
214
31
|
const result = await orchestrator.processWorkflowMessage({
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
32
|
+
workflowId: 'wf-123',
|
|
33
|
+
steps: [
|
|
34
|
+
{ service: 'validation', operation: 'validate' },
|
|
35
|
+
{ service: 'processing', operation: 'process' },
|
|
36
|
+
{ service: 'notification', operation: 'notify' }
|
|
37
|
+
],
|
|
38
|
+
currentStep: 0,
|
|
39
|
+
context: { /* workflow data */ }
|
|
219
40
|
});
|
|
220
41
|
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
}
|
|
224
|
-
```
|
|
225
|
-
**Example** *(With Error Handling)*
|
|
226
|
-
```js
|
|
227
|
-
try {
|
|
228
|
-
await orchestrator.processWorkflowMessage(message);
|
|
229
|
-
} catch (error) {
|
|
230
|
-
console.error('Workflow failed:', error);
|
|
231
|
-
// Message sent to DLQ automatically
|
|
232
|
-
}
|
|
233
|
-
```
|
|
234
|
-
<a name="module_@onlineapps/conn-orch-orchestrator..processStep"></a>
|
|
235
|
-
|
|
236
|
-
### @onlineapps/conn-orch-orchestrator~processStep(message) ⇒ <code>Promise.<\*></code>
|
|
237
|
-
Process single workflow step
|
|
238
|
-
|
|
239
|
-
**Kind**: inner method of [<code>@onlineapps/conn-orch-orchestrator</code>](#module_@onlineapps/conn-orch-orchestrator)
|
|
240
|
-
**Returns**: <code>Promise.<\*></code> - Step execution result
|
|
241
|
-
**Throws**:
|
|
242
|
-
|
|
243
|
-
- <code>Error</code> If step not found in cookbook
|
|
244
|
-
- <code>Error</code> If API call fails and onError is not 'continue'
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
| Param | Type | Description |
|
|
248
|
-
| --- | --- | --- |
|
|
249
|
-
| message | <code>WorkflowMessage</code> | Workflow message with step info |
|
|
250
|
-
|
|
251
|
-
**Example** *(Process Regular Step)*
|
|
252
|
-
```js
|
|
253
|
-
const result = await orchestrator.processStep({
|
|
254
|
-
cookbook: cookbook,
|
|
255
|
-
current_step: 2,
|
|
256
|
-
context: { data: 'value' }
|
|
257
|
-
});
|
|
258
|
-
```
|
|
259
|
-
**Example** *(Process Control Flow Step)*
|
|
260
|
-
```js
|
|
261
|
-
const result = await orchestrator.processStep({
|
|
262
|
-
cookbook: { steps: [{ type: 'foreach', items: [...] }] },
|
|
263
|
-
current_step: 0
|
|
264
|
-
});
|
|
42
|
+
// Get statistics
|
|
43
|
+
const stats = orchestrator.getStats();
|
|
44
|
+
console.log(`Processed: ${stats.processed}, Failed: ${stats.failed}`);
|
|
265
45
|
```
|
|
266
|
-
<a name="module_@onlineapps/conn-orch-orchestrator..handleControlFlow"></a>
|
|
267
|
-
|
|
268
|
-
### @onlineapps/conn-orch-orchestrator~handleControlFlow(step, message) ⇒ <code>Promise.<\*></code>
|
|
269
|
-
Handle control flow steps (if, foreach, fork_join, switch)
|
|
270
46
|
|
|
271
|
-
|
|
272
|
-
**Returns**: <code>Promise.<\*></code> - Control flow execution result
|
|
273
|
-
**Throws**:
|
|
47
|
+
## Configuration
|
|
274
48
|
|
|
275
|
-
|
|
49
|
+
| Variable | Description | Default |
|
|
50
|
+
|----------|-------------|---------|
|
|
51
|
+
| `AMQP_URL` | RabbitMQ connection URL | required |
|
|
52
|
+
| `STORAGE_URL` | MinIO storage URL | required |
|
|
53
|
+
| `WORKFLOW_TIMEOUT` | Max workflow execution time (ms) | 300000 |
|
|
54
|
+
| `MAX_RETRIES` | Maximum retry attempts | 3 |
|
|
276
55
|
|
|
56
|
+
## Control Flow Patterns
|
|
277
57
|
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
| step.type | <code>string</code> | Type: 'if', 'foreach', 'fork_join', 'switch' |
|
|
282
|
-
| message | <code>WorkflowMessage</code> | Workflow message |
|
|
283
|
-
|
|
284
|
-
**Example** *(If/Else Flow)*
|
|
285
|
-
```js
|
|
286
|
-
await orchestrator.handleControlFlow({
|
|
58
|
+
### If/Else
|
|
59
|
+
```javascript
|
|
60
|
+
{
|
|
287
61
|
type: 'if',
|
|
288
|
-
condition:
|
|
289
|
-
then: { service: '
|
|
290
|
-
else: { service: '
|
|
291
|
-
}
|
|
292
|
-
```
|
|
293
|
-
**Example** *(Foreach Iteration)*
|
|
294
|
-
```js
|
|
295
|
-
await orchestrator.handleControlFlow({
|
|
296
|
-
type: 'foreach',
|
|
297
|
-
items: '${invoices}',
|
|
298
|
-
do: { service: 'invoice', operation: 'process' }
|
|
299
|
-
}, message);
|
|
300
|
-
```
|
|
301
|
-
**Example** *(Fork-Join Parallel)*
|
|
302
|
-
```js
|
|
303
|
-
await orchestrator.handleControlFlow({
|
|
304
|
-
type: 'fork_join',
|
|
305
|
-
branches: [
|
|
306
|
-
{ service: 'inventory', operation: 'check' },
|
|
307
|
-
{ service: 'pricing', operation: 'calculate' }
|
|
308
|
-
],
|
|
309
|
-
joinStrategy: 'merge'
|
|
310
|
-
}, message);
|
|
311
|
-
```
|
|
312
|
-
<a name="module_@onlineapps/conn-orch-orchestrator..handleIfStep"></a>
|
|
313
|
-
|
|
314
|
-
### @onlineapps/conn-orch-orchestrator~handleIfStep(step, message) ⇒ <code>Promise.<\*></code>
|
|
315
|
-
Handle if/else control flow
|
|
316
|
-
|
|
317
|
-
**Kind**: inner method of [<code>@onlineapps/conn-orch-orchestrator</code>](#module_@onlineapps/conn-orch-orchestrator)
|
|
318
|
-
**Returns**: <code>Promise.<\*></code> - Branch execution result or null
|
|
319
|
-
|
|
320
|
-
| Param | Type | Description |
|
|
321
|
-
| --- | --- | --- |
|
|
322
|
-
| step | <code>IfStep</code> | If step definition |
|
|
323
|
-
| step.condition | <code>string</code> | Condition expression |
|
|
324
|
-
| [step.then] | <code>Object</code> | Branch for true condition |
|
|
325
|
-
| [step.else] | <code>Object</code> | Branch for false condition |
|
|
326
|
-
| message | <code>WorkflowMessage</code> | Workflow message |
|
|
327
|
-
|
|
328
|
-
**Example**
|
|
329
|
-
```js
|
|
330
|
-
await orchestrator.handleIfStep({
|
|
331
|
-
condition: '${status} === "pending"',
|
|
332
|
-
then: { service: 'approval', operation: 'request' },
|
|
333
|
-
else: { service: 'notification', operation: 'send' }
|
|
334
|
-
}, message);
|
|
62
|
+
condition: { field: 'status', operator: 'equals', value: 'active' },
|
|
63
|
+
then: { service: 'activeHandler' },
|
|
64
|
+
else: { service: 'inactiveHandler' }
|
|
65
|
+
}
|
|
335
66
|
```
|
|
336
|
-
<a name="module_@onlineapps/conn-orch-orchestrator..handleForeachStep"></a>
|
|
337
|
-
|
|
338
|
-
### @onlineapps/conn-orch-orchestrator~handleForeachStep(step, message) ⇒ <code>Promise.<Array></code>
|
|
339
|
-
Handle foreach iteration
|
|
340
|
-
|
|
341
|
-
**Kind**: inner method of [<code>@onlineapps/conn-orch-orchestrator</code>](#module_@onlineapps/conn-orch-orchestrator)
|
|
342
|
-
**Returns**: <code>Promise.<Array></code> - Array of results from each iteration
|
|
343
|
-
**Throws**:
|
|
344
|
-
|
|
345
|
-
- <code>Error</code> If items is not an array
|
|
346
|
-
|
|
347
67
|
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
}, message);
|
|
68
|
+
### Switch/Case
|
|
69
|
+
```javascript
|
|
70
|
+
{
|
|
71
|
+
type: 'switch',
|
|
72
|
+
field: 'priority',
|
|
73
|
+
cases: {
|
|
74
|
+
'high': { service: 'urgentHandler' },
|
|
75
|
+
'normal': { service: 'standardHandler' },
|
|
76
|
+
'low': { service: 'batchHandler' }
|
|
77
|
+
},
|
|
78
|
+
default: { service: 'defaultHandler' }
|
|
79
|
+
}
|
|
361
80
|
```
|
|
362
|
-
<a name="module_@onlineapps/conn-orch-orchestrator..handleForkJoinStep"></a>
|
|
363
|
-
|
|
364
|
-
### @onlineapps/conn-orch-orchestrator~handleForkJoinStep(step, message) ⇒ <code>Promise.<\*></code>
|
|
365
|
-
Handle fork-join parallel execution
|
|
366
|
-
|
|
367
|
-
**Kind**: inner method of [<code>@onlineapps/conn-orch-orchestrator</code>](#module_@onlineapps/conn-orch-orchestrator)
|
|
368
|
-
**Returns**: <code>Promise.<\*></code> - Joined results based on strategy
|
|
369
|
-
**Throws**:
|
|
370
|
-
|
|
371
|
-
- <code>Error</code> If MQ client doesn't support fork-join
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
| Param | Type | Default | Description |
|
|
375
|
-
| --- | --- | --- | --- |
|
|
376
|
-
| step | <code>ForkJoinStep</code> | | Fork-join step definition |
|
|
377
|
-
| step.branches | <code>Array.<Object></code> | | Parallel branches to execute |
|
|
378
|
-
| [step.joinStrategy] | <code>string</code> | <code>"'merge'"</code> | Join strategy: 'merge', 'array', 'first' |
|
|
379
|
-
| [step.timeout] | <code>number</code> | | Overall timeout for all branches |
|
|
380
|
-
| message | <code>WorkflowMessage</code> | | Workflow message |
|
|
381
81
|
|
|
382
|
-
|
|
383
|
-
```
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
],
|
|
390
|
-
joinStrategy: 'merge',
|
|
391
|
-
timeout: 10000
|
|
392
|
-
}, message);
|
|
82
|
+
### Foreach
|
|
83
|
+
```javascript
|
|
84
|
+
{
|
|
85
|
+
type: 'foreach',
|
|
86
|
+
items: 'context.items',
|
|
87
|
+
step: { service: 'itemProcessor' }
|
|
88
|
+
}
|
|
393
89
|
```
|
|
394
|
-
<a name="module_@onlineapps/conn-orch-orchestrator..handleSwitchStep"></a>
|
|
395
|
-
|
|
396
|
-
### @onlineapps/conn-orch-orchestrator~handleSwitchStep(step, message) ⇒ <code>Promise.<\*></code>
|
|
397
|
-
Handle switch statement
|
|
398
90
|
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
| [step.default] | <code>Object</code> | Default case |
|
|
408
|
-
| message | <code>WorkflowMessage</code> | Workflow message |
|
|
409
|
-
|
|
410
|
-
**Example**
|
|
411
|
-
```js
|
|
412
|
-
await orchestrator.handleSwitchStep({
|
|
413
|
-
value: '${order.type}',
|
|
414
|
-
cases: [
|
|
415
|
-
{ value: 'standard', do: { service: 'shipping', operation: 'standard' } },
|
|
416
|
-
{ value: 'express', do: { service: 'shipping', operation: 'express' } }
|
|
91
|
+
### Fork-Join
|
|
92
|
+
```javascript
|
|
93
|
+
{
|
|
94
|
+
type: 'fork-join',
|
|
95
|
+
parallel: [
|
|
96
|
+
{ service: 'validator' },
|
|
97
|
+
{ service: 'enricher' },
|
|
98
|
+
{ service: 'scorer' }
|
|
417
99
|
],
|
|
418
|
-
|
|
419
|
-
}
|
|
420
|
-
```
|
|
421
|
-
<a name="module_@onlineapps/conn-orch-orchestrator..routeToNextService"></a>
|
|
422
|
-
|
|
423
|
-
### @onlineapps/conn-orch-orchestrator~routeToNextService(message, nextService, stepResult, nextIndex) ⇒ <code>Promise.<void></code>
|
|
424
|
-
Route to next service in workflow
|
|
425
|
-
|
|
426
|
-
**Kind**: inner method of [<code>@onlineapps/conn-orch-orchestrator</code>](#module_@onlineapps/conn-orch-orchestrator)
|
|
427
|
-
**Emits**: <code>MQClient#event:publish - Publishes to next service queue</code>
|
|
428
|
-
|
|
429
|
-
| Param | Type | Description |
|
|
430
|
-
| --- | --- | --- |
|
|
431
|
-
| message | <code>WorkflowMessage</code> | Current workflow message |
|
|
432
|
-
| nextService | <code>string</code> | Next service name |
|
|
433
|
-
| stepResult | <code>\*</code> | Current step result |
|
|
434
|
-
| nextIndex | <code>number</code> | Next step index |
|
|
435
|
-
|
|
436
|
-
**Example**
|
|
437
|
-
```js
|
|
438
|
-
await orchestrator.routeToNextService(
|
|
439
|
-
message,
|
|
440
|
-
'invoice-service',
|
|
441
|
-
{ processed: true, total: 1500 },
|
|
442
|
-
3
|
|
443
|
-
);
|
|
444
|
-
// Message published to 'invoice-service.workflow' queue
|
|
100
|
+
join: { service: 'aggregator' }
|
|
101
|
+
}
|
|
445
102
|
```
|
|
446
|
-
<a name="module_@onlineapps/conn-orch-orchestrator..completeWorkflow"></a>
|
|
447
103
|
|
|
448
|
-
|
|
449
|
-
Complete workflow
|
|
104
|
+
## API Reference
|
|
450
105
|
|
|
451
|
-
|
|
452
|
-
**Emits**: <code>MQClient#workflow.event:completed - Workflow completion event</code>
|
|
106
|
+
### OrchestratorConnector
|
|
453
107
|
|
|
454
|
-
|
|
455
|
-
| --- | --- | --- |
|
|
456
|
-
| message | <code>WorkflowMessage</code> | Workflow message |
|
|
457
|
-
| finalResult | <code>\*</code> | Final workflow result |
|
|
108
|
+
Main orchestrator class for workflow execution.
|
|
458
109
|
|
|
459
|
-
|
|
460
|
-
```js
|
|
461
|
-
await orchestrator.completeWorkflow(message, {
|
|
462
|
-
status: 'success',
|
|
463
|
-
invoice_id: 'inv-789',
|
|
464
|
-
total: 1500
|
|
465
|
-
});
|
|
466
|
-
```
|
|
467
|
-
<a name="module_@onlineapps/conn-orch-orchestrator..handleWorkflowFailure"></a>
|
|
110
|
+
#### Methods
|
|
468
111
|
|
|
469
|
-
|
|
470
|
-
|
|
112
|
+
- `processWorkflowMessage(message)` - Process a workflow message
|
|
113
|
+
- `processStep(message)` - Process a single workflow step
|
|
114
|
+
- `handleControlFlow(step, message)` - Handle control flow steps
|
|
115
|
+
- `routeToNextService(message, nextService, result, nextIndex)` - Route to next service
|
|
116
|
+
- `completeWorkflow(message, result)` - Complete workflow execution
|
|
117
|
+
- `handleWorkflowFailure(message, error)` - Handle workflow failures
|
|
118
|
+
- `getStats()` - Get execution statistics
|
|
119
|
+
- `resetStats()` - Reset statistics
|
|
471
120
|
|
|
472
|
-
|
|
473
|
-
**Emits**: <code>MQClient#workflow.event:dlq - Sends to dead letter queue</code>
|
|
121
|
+
## Testing
|
|
474
122
|
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
| error | <code>Error</code> | Failure error |
|
|
123
|
+
```bash
|
|
124
|
+
# Run all tests
|
|
125
|
+
npm test
|
|
479
126
|
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
await orchestrator.handleWorkflowFailure(message,
|
|
483
|
-
new Error('Service unavailable')
|
|
484
|
-
);
|
|
485
|
-
```
|
|
486
|
-
<a name="module_@onlineapps/conn-orch-orchestrator..getStats"></a>
|
|
127
|
+
# Run unit tests
|
|
128
|
+
npm run test:unit
|
|
487
129
|
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
**Kind**: inner method of [<code>@onlineapps/conn-orch-orchestrator</code>](#module_@onlineapps/conn-orch-orchestrator)
|
|
492
|
-
**Returns**: <code>OrchestratorStats</code> - Current statistics<code>number</code> - stats.started - Workflows started<code>number</code> - stats.completed - Workflows completed<code>number</code> - stats.failed - Workflows failed<code>number</code> - stats.steps - Total steps processed<code>number</code> - stats.avgDuration - Average duration in ms<code>number</code> - stats.activeWorkflows - Currently active workflows
|
|
493
|
-
**Example**
|
|
494
|
-
```js
|
|
495
|
-
const stats = orchestrator.getStats();
|
|
496
|
-
console.log(`Success rate: ${stats.completed / stats.started * 100}%`);
|
|
497
|
-
console.log(`Average duration: ${stats.avgDuration}ms`);
|
|
130
|
+
# Run integration tests
|
|
131
|
+
npm run test:integration
|
|
498
132
|
```
|
|
499
|
-
<a name="module_@onlineapps/conn-orch-orchestrator..resetStats"></a>
|
|
500
|
-
|
|
501
|
-
### @onlineapps/conn-orch-orchestrator~resetStats() ⇒ <code>void</code>
|
|
502
|
-
Reset statistics
|
|
503
|
-
|
|
504
|
-
**Kind**: inner method of [<code>@onlineapps/conn-orch-orchestrator</code>](#module_@onlineapps/conn-orch-orchestrator)
|
|
505
|
-
**Example**
|
|
506
|
-
```js
|
|
507
|
-
orchestrator.resetStats();
|
|
508
|
-
// All counters reset to 0
|
|
509
|
-
```
|
|
510
|
-
<a name="module_@onlineapps/conn-orch-orchestrator..create"></a>
|
|
511
|
-
|
|
512
|
-
### @onlineapps/conn-orch-orchestrator~create(config) ⇒ <code>OrchestratorConnector</code>
|
|
513
|
-
Factory function to create orchestrator instance
|
|
514
|
-
|
|
515
|
-
**Kind**: inner method of [<code>@onlineapps/conn-orch-orchestrator</code>](#module_@onlineapps/conn-orch-orchestrator)
|
|
516
|
-
**Returns**: <code>OrchestratorConnector</code> - New orchestrator instance
|
|
517
|
-
|
|
518
|
-
| Param | Type | Description |
|
|
519
|
-
| --- | --- | --- |
|
|
520
|
-
| config | <code>Object</code> | Configuration object |
|
|
521
|
-
|
|
522
|
-
**Example**
|
|
523
|
-
```js
|
|
524
|
-
const orchestrator = OrchestratorConnector.create({
|
|
525
|
-
mqClient: mqConnector,
|
|
526
|
-
cookbook: cookbookConnector,
|
|
527
|
-
serviceName: 'invoice-service'
|
|
528
|
-
});
|
|
529
|
-
```
|
|
530
|
-
<a name="module_@onlineapps/conn-orch-orchestrator..WorkflowMessage"></a>
|
|
531
|
-
|
|
532
|
-
### @onlineapps/conn-orch-orchestrator~WorkflowMessage : <code>Object</code>
|
|
533
|
-
**Kind**: inner typedef of [<code>@onlineapps/conn-orch-orchestrator</code>](#module_@onlineapps/conn-orch-orchestrator)
|
|
534
|
-
**Properties**
|
|
535
|
-
|
|
536
|
-
| Name | Type | Default | Description |
|
|
537
|
-
| --- | --- | --- | --- |
|
|
538
|
-
| [workflow_id] | <code>string</code> | | Unique workflow identifier |
|
|
539
|
-
| cookbook | <code>Object</code> | | Cookbook definition |
|
|
540
|
-
| [current_step] | <code>number</code> | <code>0</code> | Current step index |
|
|
541
|
-
| [context] | <code>Object</code> | <code>{}</code> | Workflow context data |
|
|
542
|
-
| [trace] | <code>Array</code> | <code>[]</code> | Execution trace |
|
|
543
|
-
| [correlation_id] | <code>string</code> | | Correlation ID for tracing |
|
|
544
|
-
|
|
545
|
-
<a name="module_@onlineapps/conn-orch-orchestrator..WorkflowResult"></a>
|
|
546
|
-
|
|
547
|
-
### @onlineapps/conn-orch-orchestrator~WorkflowResult : <code>Object</code>
|
|
548
|
-
**Kind**: inner typedef of [<code>@onlineapps/conn-orch-orchestrator</code>](#module_@onlineapps/conn-orch-orchestrator)
|
|
549
|
-
**Properties**
|
|
550
|
-
|
|
551
|
-
| Name | Type | Description |
|
|
552
|
-
| --- | --- | --- |
|
|
553
|
-
| success | <code>boolean</code> | Whether workflow succeeded |
|
|
554
|
-
| workflowId | <code>string</code> | Workflow identifier |
|
|
555
|
-
| duration | <code>number</code> | Processing duration in ms |
|
|
556
|
-
|
|
557
|
-
<a name="module_@onlineapps/conn-orch-orchestrator..ControlFlowStep"></a>
|
|
558
|
-
|
|
559
|
-
### @onlineapps/conn-orch-orchestrator~ControlFlowStep : <code>Object</code>
|
|
560
|
-
**Kind**: inner typedef of [<code>@onlineapps/conn-orch-orchestrator</code>](#module_@onlineapps/conn-orch-orchestrator)
|
|
561
|
-
**Properties**
|
|
562
|
-
|
|
563
|
-
| Name | Type | Description |
|
|
564
|
-
| --- | --- | --- |
|
|
565
|
-
| type | <code>string</code> | Control flow type: 'if', 'foreach', 'fork_join', 'switch' |
|
|
566
|
-
| [condition] | <code>\*</code> | Condition for if steps |
|
|
567
|
-
| [items] | <code>\*</code> | Items for foreach steps |
|
|
568
|
-
| [branches] | <code>Array</code> | Branches for fork_join |
|
|
569
|
-
| [value] | <code>string</code> | Value for switch steps |
|
|
570
|
-
|
|
571
|
-
<a name="module_@onlineapps/conn-orch-orchestrator..OrchestratorStats"></a>
|
|
572
|
-
|
|
573
|
-
### @onlineapps/conn-orch-orchestrator~OrchestratorStats : <code>Object</code>
|
|
574
|
-
**Kind**: inner typedef of [<code>@onlineapps/conn-orch-orchestrator</code>](#module_@onlineapps/conn-orch-orchestrator)
|
|
575
|
-
**Properties**
|
|
576
133
|
|
|
577
|
-
|
|
578
|
-
| --- | --- | --- |
|
|
579
|
-
| started | <code>number</code> | Workflows started |
|
|
580
|
-
| completed | <code>number</code> | Workflows completed |
|
|
581
|
-
| failed | <code>number</code> | Workflows failed |
|
|
582
|
-
| steps | <code>number</code> | Total steps processed |
|
|
583
|
-
| avgDuration | <code>number</code> | Average duration in ms |
|
|
584
|
-
| activeWorkflows | <code>number</code> | Currently active workflows |
|
|
134
|
+
## 📚 Documentation
|
|
585
135
|
|
|
136
|
+
- [Complete Connectors Documentation](../../../docs/modules/connector.md)
|
|
137
|
+
- [Workflow Architecture](../../../docs/modules/workflow.md)
|
|
138
|
+
- [Testing Standards](../../../docs/modules/connector.md#testing-standards)
|
package/jest.config.js
CHANGED
|
@@ -6,9 +6,9 @@ module.exports = {
|
|
|
6
6
|
'!src/**/*.test.js'
|
|
7
7
|
],
|
|
8
8
|
testMatch: [
|
|
9
|
-
'**/
|
|
10
|
-
'**/
|
|
11
|
-
'**/
|
|
9
|
+
'**/tests/unit/**/*.test.js',
|
|
10
|
+
'**/tests/component/**/*.test.js',
|
|
11
|
+
'**/tests/integration/**/*.test.js'
|
|
12
12
|
],
|
|
13
13
|
testPathIgnorePatterns: [
|
|
14
14
|
'/node_modules/'
|
package/jest.setup.js
CHANGED
|
File without changes
|
|
Binary file
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@onlineapps/conn-orch-orchestrator",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.3",
|
|
4
4
|
"description": "Workflow orchestration connector for OA Drive - handles message routing and workflow execution",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
"author": "OA Drive Team",
|
|
21
21
|
"license": "MIT",
|
|
22
22
|
"dependencies": {
|
|
23
|
-
"@onlineapps/conn-base-
|
|
23
|
+
"@onlineapps/conn-base-monitoring": "^1.0.0",
|
|
24
24
|
"@onlineapps/conn-infra-mq": "^1.1.0",
|
|
25
25
|
"@onlineapps/conn-orch-registry": "^1.1.4",
|
|
26
26
|
"@onlineapps/conn-orch-cookbook": "^2.0.0",
|
|
@@ -38,4 +38,4 @@
|
|
|
38
38
|
"src/**/*.js"
|
|
39
39
|
]
|
|
40
40
|
}
|
|
41
|
-
}
|
|
41
|
+
}
|
|
@@ -70,6 +70,14 @@ class WorkflowOrchestrator {
|
|
|
70
70
|
// Validate cookbook structure
|
|
71
71
|
this.cookbook.validateCookbook(cookbookDef);
|
|
72
72
|
|
|
73
|
+
// Ensure delivery configuration is preserved in context (required by Delivery Dispatcher)
|
|
74
|
+
// Delivery comes from cookbook.delivery (set by Gateway) and must be passed through to workflow.completed
|
|
75
|
+
const enrichedContext = {
|
|
76
|
+
...context,
|
|
77
|
+
// Preserve delivery from cookbook if not already in context
|
|
78
|
+
delivery: context?.delivery || cookbookDef?.delivery || { handler: 'none' }
|
|
79
|
+
};
|
|
80
|
+
|
|
73
81
|
// Find current step
|
|
74
82
|
const step = cookbookDef.steps.find(s => s.id === current_step);
|
|
75
83
|
if (!step) {
|
|
@@ -83,29 +91,52 @@ class WorkflowOrchestrator {
|
|
|
83
91
|
return { skipped: true, reason: 'wrong_service' };
|
|
84
92
|
}
|
|
85
93
|
|
|
94
|
+
// Publish workflow.progress to monitoring.workflow using unified helper
|
|
95
|
+
const { publishToMonitoringWorkflow } = require('@onlineapps/mq-client-core').monitoring;
|
|
96
|
+
try {
|
|
97
|
+
const stepIndex = cookbookDef.steps.findIndex(s => s.id === current_step);
|
|
98
|
+
await publishToMonitoringWorkflow(this.mqClient, {
|
|
99
|
+
event_type: 'progress',
|
|
100
|
+
workflow_id: workflow_id,
|
|
101
|
+
service_name: serviceName,
|
|
102
|
+
step_index: stepIndex >= 0 ? stepIndex : 0,
|
|
103
|
+
step_id: current_step,
|
|
104
|
+
cookbook: cookbookDef,
|
|
105
|
+
context: enrichedContext,
|
|
106
|
+
status: 'in_progress',
|
|
107
|
+
timestamp: new Date().toISOString()
|
|
108
|
+
}, this.logger, { workflow_id, step_id: current_step });
|
|
109
|
+
} catch (monitoringError) {
|
|
110
|
+
// Don't fail workflow if monitoring publish fails (helper already logs)
|
|
111
|
+
this.logger.warn('Failed to publish workflow.progress to monitoring', {
|
|
112
|
+
workflow_id,
|
|
113
|
+
error: monitoringError.message
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
|
|
86
117
|
// Check cache if available
|
|
87
118
|
let result;
|
|
88
119
|
if (this.cache && step.type === 'task') {
|
|
89
|
-
const cacheKey = this._getCacheKey(step,
|
|
120
|
+
const cacheKey = this._getCacheKey(step, enrichedContext);
|
|
90
121
|
result = await this.cache.get(cacheKey);
|
|
91
122
|
|
|
92
123
|
if (result) {
|
|
93
124
|
this.logger.info('Cache hit', { step: step.id, cacheKey });
|
|
94
125
|
} else {
|
|
95
126
|
// Execute the step
|
|
96
|
-
result = await this._executeStep(step,
|
|
127
|
+
result = await this._executeStep(step, enrichedContext, cookbookDef);
|
|
97
128
|
await this.cache.set(cacheKey, result, { ttl: 300 });
|
|
98
129
|
}
|
|
99
130
|
} else {
|
|
100
131
|
// Execute without cache
|
|
101
|
-
result = await this._executeStep(step,
|
|
132
|
+
result = await this._executeStep(step, enrichedContext, cookbookDef);
|
|
102
133
|
}
|
|
103
134
|
|
|
104
|
-
// Update context with result
|
|
135
|
+
// Update context with result (preserve delivery from enrichedContext)
|
|
105
136
|
const updatedContext = {
|
|
106
|
-
...
|
|
137
|
+
...enrichedContext,
|
|
107
138
|
steps: {
|
|
108
|
-
...
|
|
139
|
+
...enrichedContext.steps,
|
|
109
140
|
[current_step]: result
|
|
110
141
|
}
|
|
111
142
|
};
|
|
@@ -130,11 +161,34 @@ class WorkflowOrchestrator {
|
|
|
130
161
|
};
|
|
131
162
|
|
|
132
163
|
} catch (error) {
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
error: error.
|
|
137
|
-
|
|
164
|
+
// Publish to workflow.failed queue
|
|
165
|
+
try {
|
|
166
|
+
console.log(`[WorkflowOrchestrator] [PUBLISH] Preparing to publish workflow.failed for ${workflow_id}`);
|
|
167
|
+
this.logger.error(`[WorkflowOrchestrator] [PUBLISH] Workflow processing failed: ${error.message}`, {
|
|
168
|
+
workflow_id,
|
|
169
|
+
current_step,
|
|
170
|
+
error: error.stack
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
await this.mqClient.publish('workflow.failed', {
|
|
174
|
+
workflow_id,
|
|
175
|
+
current_step,
|
|
176
|
+
error: error.message,
|
|
177
|
+
errorStack: error.stack,
|
|
178
|
+
failed_at: new Date().toISOString()
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
console.log(`[WorkflowOrchestrator] [PUBLISH] ✓ Successfully published workflow.failed for ${workflow_id}`);
|
|
182
|
+
this.logger.info(`[WorkflowOrchestrator] [PUBLISH] ✓ Published workflow.failed: ${workflow_id}`);
|
|
183
|
+
} catch (publishError) {
|
|
184
|
+
console.error(`[WorkflowOrchestrator] [PUBLISH] ✗ Failed to publish workflow.failed for ${workflow_id}:`, publishError.message);
|
|
185
|
+
this.logger.error(`[WorkflowOrchestrator] [PUBLISH] ✗ Failed to publish workflow.failed`, {
|
|
186
|
+
workflow_id,
|
|
187
|
+
originalError: error.message,
|
|
188
|
+
publishError: publishError.message
|
|
189
|
+
});
|
|
190
|
+
// Don't throw - original error is more important
|
|
191
|
+
}
|
|
138
192
|
|
|
139
193
|
// Handle error
|
|
140
194
|
if (this.errorHandler) {
|
|
@@ -273,13 +327,41 @@ class WorkflowOrchestrator {
|
|
|
273
327
|
* @param {Object} finalContext - Final workflow context
|
|
274
328
|
*/
|
|
275
329
|
async _completeWorkflow(workflow_id, finalContext) {
|
|
276
|
-
|
|
277
|
-
workflow_id
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
330
|
+
try {
|
|
331
|
+
console.log(`[WorkflowOrchestrator] [PUBLISH] Preparing to publish workflow.completed for ${workflow_id}`);
|
|
332
|
+
this.logger.info(`[WorkflowOrchestrator] [PUBLISH] Preparing to publish workflow.completed`, {
|
|
333
|
+
workflow_id,
|
|
334
|
+
hasMqClient: !!this.mqClient,
|
|
335
|
+
mqClientConnected: this.mqClient?._connected
|
|
336
|
+
});
|
|
337
|
+
|
|
338
|
+
// Extract delivery configuration from context (passed from Gateway)
|
|
339
|
+
// Delivery Dispatcher requires: workflow_id, status, delivery (must be object, not null)
|
|
340
|
+
const delivery = finalContext?.delivery || { handler: 'none' }; // Default to 'none' handler if not provided
|
|
341
|
+
|
|
342
|
+
// Build message in format expected by Delivery Dispatcher
|
|
343
|
+
const workflowCompletedMessage = {
|
|
344
|
+
workflow_id,
|
|
345
|
+
status: 'completed',
|
|
346
|
+
delivery: delivery, // Delivery configuration from Gateway context (must be object)
|
|
347
|
+
context: finalContext, // Full context for output resolution
|
|
348
|
+
steps: finalContext?.steps || {}, // Steps results for output resolution
|
|
349
|
+
completed_at: new Date().toISOString()
|
|
350
|
+
};
|
|
351
|
+
|
|
352
|
+
await this.mqClient.publish('workflow.completed', workflowCompletedMessage);
|
|
281
353
|
|
|
282
|
-
|
|
354
|
+
console.log(`[WorkflowOrchestrator] [PUBLISH] ✓ Successfully published workflow.completed for ${workflow_id}`);
|
|
355
|
+
this.logger.info(`[WorkflowOrchestrator] [PUBLISH] ✓ Workflow completed: ${workflow_id}`);
|
|
356
|
+
} catch (error) {
|
|
357
|
+
console.error(`[WorkflowOrchestrator] [PUBLISH] ✗ Failed to publish workflow.completed for ${workflow_id}:`, error.message);
|
|
358
|
+
this.logger.error(`[WorkflowOrchestrator] [PUBLISH] ✗ Failed to publish workflow.completed`, {
|
|
359
|
+
workflow_id,
|
|
360
|
+
error: error.message,
|
|
361
|
+
errorStack: error.stack
|
|
362
|
+
});
|
|
363
|
+
throw error; // Re-throw to allow ServiceWrapper to handle
|
|
364
|
+
}
|
|
283
365
|
}
|
|
284
366
|
|
|
285
367
|
/**
|
package/src/index.js
CHANGED
|
File without changes
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
|
|
8
8
|
const WorkflowOrchestrator = require('../../src/WorkflowOrchestrator');
|
|
9
9
|
|
|
10
|
-
describe('Orchestrator - Component Tests', () => {
|
|
10
|
+
describe('Orchestrator - Component Tests @component', () => {
|
|
11
11
|
let orchestrator;
|
|
12
12
|
let mqClientStub;
|
|
13
13
|
let registryClientStub;
|
|
@@ -13,10 +13,11 @@ const CookbookConnector = require('@onlineapps/conn-orch-cookbook');
|
|
|
13
13
|
|
|
14
14
|
// Skip integration tests if external services are not available
|
|
15
15
|
const SKIP_INTEGRATION = process.env.SKIP_INTEGRATION === 'true';
|
|
16
|
-
const
|
|
17
|
-
const
|
|
16
|
+
const { requireEnv } = require('../../../../../tests/_helpers/test-config');
|
|
17
|
+
const RABBITMQ_URL = requireEnv('RABBITMQ_URL', 'RabbitMQ connection URL');
|
|
18
|
+
const REGISTRY_URL = requireEnv('REGISTRY_URL', 'Registry service URL');
|
|
18
19
|
|
|
19
|
-
describe('Orchestrator - Integration Tests', () => {
|
|
20
|
+
describe('Orchestrator - Integration Tests @integration', () => {
|
|
20
21
|
if (SKIP_INTEGRATION) {
|
|
21
22
|
it.skip('Skipping integration tests (SKIP_INTEGRATION=true)', () => {});
|
|
22
23
|
return;
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
|
|
8
8
|
const WorkflowOrchestrator = require('../../src/WorkflowOrchestrator');
|
|
9
9
|
|
|
10
|
-
describe('WorkflowOrchestrator - Unit Tests', () => {
|
|
10
|
+
describe('WorkflowOrchestrator - Unit Tests @unit', () => {
|
|
11
11
|
let orchestrator;
|
|
12
12
|
let mockMqClient;
|
|
13
13
|
let mockRegistryClient;
|