@onlineapps/conn-orch-orchestrator 1.0.67 → 1.0.68
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/package.json
CHANGED
|
@@ -133,6 +133,11 @@ class WorkflowOrchestrator {
|
|
|
133
133
|
throw new Error(`Step not found: ${current_step}`);
|
|
134
134
|
}
|
|
135
135
|
|
|
136
|
+
// Fail-fast: task steps MUST have service
|
|
137
|
+
if (step.type === 'task' && !step.service) {
|
|
138
|
+
throw new Error(`[WorkflowOrchestrator] FAIL-FAST: Task step '${current_step}' missing required 'service'`);
|
|
139
|
+
}
|
|
140
|
+
|
|
136
141
|
// Check if this step is for this service
|
|
137
142
|
if (step.type === 'task' && step.service !== serviceName) {
|
|
138
143
|
this.logger.warn(`Step ${current_step} is for ${step.service}, not ${serviceName}`);
|
|
@@ -1028,6 +1033,9 @@ class WorkflowOrchestrator {
|
|
|
1028
1033
|
};
|
|
1029
1034
|
|
|
1030
1035
|
if (nextStep.type === 'task') {
|
|
1036
|
+
if (!nextStep.service) {
|
|
1037
|
+
throw new Error(`[WorkflowOrchestrator] FAIL-FAST: Task step '${nextStepId}' missing required 'service'`);
|
|
1038
|
+
}
|
|
1031
1039
|
// Route to specific service
|
|
1032
1040
|
if (this.router?.routeToService) {
|
|
1033
1041
|
await this.router.routeToService(nextStep.service, message);
|
|
@@ -1035,7 +1043,7 @@ class WorkflowOrchestrator {
|
|
|
1035
1043
|
step: nextStepId
|
|
1036
1044
|
});
|
|
1037
1045
|
} else {
|
|
1038
|
-
//
|
|
1046
|
+
// Backward compatibility: publish to service's workflow queue directly if router is not available
|
|
1039
1047
|
const serviceQueue = `${nextStep.service}.workflow`;
|
|
1040
1048
|
await this.mqClient.publish(serviceQueue, message);
|
|
1041
1049
|
this.logger.info(`Published to queue: ${serviceQueue}`, {
|
|
@@ -1045,14 +1053,14 @@ class WorkflowOrchestrator {
|
|
|
1045
1053
|
} else {
|
|
1046
1054
|
// Control flow steps:
|
|
1047
1055
|
// - if pinned (step.service), route to that service queue
|
|
1048
|
-
// - otherwise
|
|
1056
|
+
// - otherwise route to workflow.control (any business service may execute)
|
|
1049
1057
|
if (nextStep.service) {
|
|
1050
1058
|
const serviceQueue = `${nextStep.service}.workflow`;
|
|
1051
1059
|
await this.mqClient.publish(serviceQueue, message);
|
|
1052
1060
|
this.logger.info(`Routed control flow to pinned service queue: ${serviceQueue}`, { step: nextStepId });
|
|
1053
1061
|
} else {
|
|
1054
|
-
await this.mqClient.publish('workflow.
|
|
1055
|
-
this.logger.info(`Routed control flow to workflow.
|
|
1062
|
+
await this.mqClient.publish('workflow.control', message);
|
|
1063
|
+
this.logger.info(`Routed control flow to workflow.control`, { step: nextStepId });
|
|
1056
1064
|
}
|
|
1057
1065
|
}
|
|
1058
1066
|
}
|
|
@@ -85,7 +85,7 @@ describe('WorkflowOrchestrator - Component Tests @component', () => {
|
|
|
85
85
|
);
|
|
86
86
|
});
|
|
87
87
|
|
|
88
|
-
it('routes next pinned control-flow step to pinned service queue (not workflow.init)', async () => {
|
|
88
|
+
it('routes next pinned control-flow step to pinned service queue (not workflow.init/workflow.control)', async () => {
|
|
89
89
|
const cookbook = {
|
|
90
90
|
version: '2.1.0',
|
|
91
91
|
api_input: { items: ['a'] },
|
|
@@ -115,6 +115,36 @@ describe('WorkflowOrchestrator - Component Tests @component', () => {
|
|
|
115
115
|
})
|
|
116
116
|
);
|
|
117
117
|
});
|
|
118
|
+
|
|
119
|
+
it('routes next unpinned control-flow step to workflow.control', async () => {
|
|
120
|
+
const cookbook = {
|
|
121
|
+
version: '2.1.0',
|
|
122
|
+
api_input: { items: ['a'] },
|
|
123
|
+
steps: [
|
|
124
|
+
{ step_id: 's1', type: 'task', service: 'svc-a', operation: 'op1', input: { x: 1 } },
|
|
125
|
+
{
|
|
126
|
+
step_id: 'loop',
|
|
127
|
+
type: 'foreach',
|
|
128
|
+
iterator: '{{api_input.items}}',
|
|
129
|
+
body: [
|
|
130
|
+
{ step_id: 'inner', type: 'task', service: 'hello-service', operation: 'good-day', input: { name: '{{current}}' } }
|
|
131
|
+
]
|
|
132
|
+
}
|
|
133
|
+
],
|
|
134
|
+
delivery: { handler: 'none' }
|
|
135
|
+
};
|
|
136
|
+
|
|
137
|
+
const msg = { workflow_id: 'wf-3', cookbook, current_step: 's1' };
|
|
138
|
+
await orchestrator.processWorkflowMessage(msg, 'svc-a');
|
|
139
|
+
|
|
140
|
+
expect(mqClientStub.publish).toHaveBeenCalledWith(
|
|
141
|
+
'workflow.control',
|
|
142
|
+
expect.objectContaining({
|
|
143
|
+
workflow_id: 'wf-3',
|
|
144
|
+
current_step: 'loop'
|
|
145
|
+
})
|
|
146
|
+
);
|
|
147
|
+
});
|
|
118
148
|
});
|
|
119
149
|
|
|
120
150
|
|