Reputation: 485
I need to create a 'do while' loop in Mule 4.0. I need a loop which will terminate on a given condition.
Unfortunately, I cannot seem how to do this in Mule 4.0.
Using recursive loops, although not ideal, used to work in Mule 3, but no longer in Mule 4.
I also used to use the until-successful scope to be able to loop until a particular condition is met, however there is no failure expression in Mule 4.0 so I'm not able to check the condition to terminate.
What is the way forward in Mule 4.0 to create a simple do-while loop.
TIA
Upvotes: 1
Views: 8083
Reputation: 4473
I hope there is a hope. I saw DO in some answers but I could not figure out how to add condition. At least it works and does not throw syntax error
%dw 2.0
output application/json
---
do {
{
n: 1
}
}
Mule does not have do-while concept. However it could be imitated with a little trick. The only one iterative (to emulate do) function is reduce but it has only one accumulator which is passed from itration to iteration. This only one variable should be used to accumulate results and to indicate end of iterations (to emulate while). Simplest way is to use value as accumulator and sign as indicator. While accumulating summary value negative result indicates end of cycles.
%dw 2.0
var x=[1,2,3,4,5]
output application/json
---
-(x reduce (item, acc=0) -> if (item <4 and acc >= 0) acc + item else if (acc>0) -acc else acc)
Some complex object could be used to collect results and also have indicator of the end of cycle as part of the object
%dw 2.0
var x=[1,2,3,4,5]
output application/json
---
(x reduce (item, acc={sum:0}) -> if (item < 4 and acc.end==null ) (acc - 'sum' ++ {sum: acc.sum+item}) else ( acc ++ {end:true} )).sum
https://simpleflatservice.com/mule4/DoWhileImitation.html
Upvotes: 0
Reputation: 1172
The following solution mimics "loop" in Mule loop using foreach component without delays or triggering error:
<set-variable value="#[1 to 100]" doc:name="loopArray" variableName="loopArray"/>
<foreach doc:name="For Each" collection="#[vars.loopArray]">
<choice doc:name="Choice" >
<when expression="#[vars.hasNextPage > 0]">
<flow-ref doc:name="getNextPage" name="getNextPage" />
</when>
<otherwise >
<logger level="DEBUG" doc:name="Logger" message="noop" />
</otherwise>
</choice>
</foreach>
Upvotes: -1
Reputation: 461
If you are waiting on a job running on a server to complete before continuing, you could achieve this sort of orchestration with queues - I've used this approach.
After triggering the task place the message on a VM queue. In another flow poll the VM queue with a sensible poll frequency depending on how long you expect the task to complete. Call the server to determine the task status and if not yet complete place the message back on the queue. If the task has completed, proceed with whatever else you need to do.
This approach prevents the stack overflow issue, but isn't viable if the entire process needs to be synchronous for some reason.
Upvotes: 0
Reputation: 11606
I think until-successful
is still the best solution as it gives you a way of breaking out of the loop after X attempts. Just, unfortunately, needs to be controlled with errors. You can use a simple choice
and raise-error
processor:
<until-successful maxRetries="5">
<http:request method="GET" url="http://something" doc:name="Request" />
<choice>
<when expression="#[payload.status !='OK']">
<raise-error type="APP:REQUEST_NOT_FINISHED"/>
</when>
</choice>
</until-successful>
Upvotes: 3
Reputation: 25872
Mule flows are not meant to work as a programming language. You have a foreach scope to iterate over things and DataWeave has a functional map() operation.
Calling recursively flows is considered a bad practice and should be avoided. It is possible but it is restricted in Mule 4 because it can easily led to stack overflow errors.
If you absolutely need to do that you should do it in Java or a scripting language.
Perhaps you could describe more in depth the use case you are trying to solve, in case there are other options better suited to the problem.
Upvotes: 1