<div class="h5">Hi Ciprian,<br><br><br>
</div><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"> I've also pondered about the same topic a while ago... (Though I<br>
haven't tried it in practice.) As such my options were the following:<br>
<br>
a) (the easiest one) Go with the choreography approach, but<br>
instead of naming the queue of the next service (and send to a direct<br>
exchange), just send it to an exchange named by the next step's<br>
purpose (like "enrich", "validate", etc.). Maybe make this a topic<br>
exchange and put enough information in the routing key to allow<br>
"debugging" by being able to register another queue and "capture" the<br>
traffic.<br>
<br></blockquote><div><br>Yes, I agree with you, send to a exchange is more apropriate<br> </div><blockquote class="gmail_quote" style="margin:0pt 0pt 0pt 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
b) (the "declarative" approach) Why not have the orchestration<br>
approach (in a declarative flavor) combined with choreography:<br>
* let's assume that you have a task which goes through a set of<br>
processes (transformations or just validations, etc.) which can be<br>
described as decision tree (a binary tree of actions, where each node<br>
is a process and the two children (one for success and one for<br>
failure) are the next process to be executed);<br>
* now you just put this decision tree inside the "envelope" of<br>
each message, send it to the root process;<br>
* this process executes its logic and based on the outcome<br>
(success or failure), extracts one of it's subtrees, puts that in the<br>
new envelope and together with the new message sends it to the root of<br>
the new tree; (evidently at some point the new tree would be empty,<br>
which means it should stop sending it further;)<br>
* (you could again use "purpose" names for exchanges instead of<br>
direct queues;)<br>
* you could extend this to a graph (maybe containing cycles, thus<br>
obtaining loops), by saying that each node has two links to other<br>
nodes;<br>
* of course yet another extension would be to allow "labeled" node<br>
links, i.e. each process outputs two things: a next-step string label,<br>
and the new message, and now you select from the labeled links the one<br>
matching the label; (maybe have something as a default link);<br>
<br>
Thus with option b) you obtain both the advantages of choreography<br>
(i.e. no middle man to become a single point of failure or<br>
bottleneck), but also the advantages of orchestration (i.e. each<br>
message having it's own "route" through the processes). At the same<br>
time you keep the processors "dumb", none knowing of another.<br></blockquote><div><br>Very interesting this approach, and better the possibility to eliminate a possible SPOF.<br><br> <br></div><blockquote class="gmail_quote" style="margin:0pt 0pt 0pt 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
<br>
Hope this helps.<br>
Ciprian.<br>
<br>
P.S.: If you like this approach (b), you could go even further and<br>
instead of using a static decision tree (or graph) you could<br>
substitute that with an embedded language or machine which allows<br>
generic operations on both the old and new message to decide the next<br>
actions. (I could expand on this if someone is interested.)<br>
<br></blockquote><div>I think that (b) approach can be more flexible for large and complex process and it sounds good.<br><br>Maybe this topic can generate good discussions and patterns for complex process management.<br>
<br>Best regards<br><br><br> <br></div><blockquote class="gmail_quote" style="margin:0pt 0pt 0pt 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
A practical (not very elegant) Java approach:<br>
* define a Java interface with a method like `public AmqpTarget<br>
decide (MyMessage old, MyMessage new)` (or something similar), where<br>
`AmqpTarget` has two fields for exchange and routing key;<br>
a) if all the processes share the same code and are upgraded at<br>
the same time, just instantiate a serializable object implementing<br>
that interface and put that in the envelope instead of the decision<br>
tree;<br>
b) if you don't have shared code or you want to keep your options opened:<br>
* for each different "workflow" define a new public "top" class<br>
(i.e. not nested or anonymous) implementing that interface with as few<br>
dependencies as possible;<br>
* in the envelope instead of the decision tree put the byte-code<br>
of this class (you can use the<br>
`MyWorkflowClass.class.getResourceStream(MyWorkflowClass.class.getCanonicalName())`<br>
and the canonical name; (be careful to use caching or you'll get<br>
`PermGenError` or similar;)<br>
* to instantiate the class on the receiver just create a custom<br>
classloader which when asked for the bytecode of that known class just<br>
returns the bytes previously stored;<br>
</blockquote></div><br><br clear="all"><br>-- <br>Isaías Barroso<br><br>