My current project has had good success using a deepClone copy of the pipeline invoking 2 separate threads in parallel and as many as 16 separate threads in a couple of nested loops.
I understand that the deepClone approach uses more resources, but we have not seen any issue with it to date. Perhaps others can comment on their findings regarding cloneType.
One approach is to put some test values in the pipeline, invoke a thread, modify some additional values and invoke your second thread. Use the tracePipeline command (or debugLog statements) to view the contents of the pipeline in each invoked thread to confirm that the behavior is what you expect it to be.
One lesson we learned about invoking services on a separate thread is avoid allowing the invoked service (child thread) to throw exceptions. Instead use the pub.sync:notify command to return a code and error message to the calling service (parent thread).
If you throw an exception in a service invoked as a child thread the pub.sync:wait command will never receive any results and will hit the timeout limit that you specified.
While this will tell you that some error occurred in the child thread, it won’t identify the error and you will add the number of seconds you specify for the timeout limit to your overall response time.
To simply things, I created two Flow services (notifyOnSuccess and notifyOnFailure) to standardize the way a service invoked on a child thread returned results to its parent. I did something similar as common methods for java services that would be invoked as child threads. They both were simple wrappers around the pub.sync:notify service but helped enforce common handling of return codes and error messages and avoid the negative side affects mentioned above.
In short, our project has found that you can obtain significant performance improvements by identiying portions of your integration application that can be invoked in parallel. Invest the time to standardize approaches for invoking services on child threads in either separate steps or within a loop and for returning results to parent threads in both success and error conditions.