If we take the
approach used for the bundle element then I believe the termination of
running activities should be covered by the completeCondition (or
completionCondition) element. (This would not work for Axel's proposal
based on links and joinCondition.)
Alex, in your
proposal you did not address the following issue: A flow activity with the
completion condition may complete even if some of the enclosed activities experienced
problems and did not complete. The way to identify that an enclosed
activity did not complete is to propagate faults. We may distinguish between
severe faults and those that can be ignored. Severe faults cause the enclosing
flow activity (or more precisely, enclosing scope) to terminate the flow
activity, including all active concurrent activities, and corresponding fault
handler may be initiated. Other faults may be ignored - the flow activity is
"informed" that a concurrent activity did not complete but still allows other
active concurrent activities to continue with execution. Your
thoughts?
Regards,
Ivana
Hi, Axel,
Thanks for liking parts of my
proposal so far. Actually, the idea of my proposal is borrowed from a part
of presentation from Ivana and Dieter Roller in March F2F. I just generalize
it to apply to <flow> also.
About using links or not:
I don't have a huge opposition to Axel's proposal which enriches the
semantics of joinCondition evaluation. However, it is not that difficult for
people to make mistakes in joinCondition. Look at the 2-out-of-3 example. The
join condition already gets so complicated. If people make a mistake in their
joinCondition, the whole flow can get struck for no good reasons. (The
completeCondition approach will less likely to have the whole flow struck.
Because, it does not introduce a new parallel activity in the flow). But, if
this is what Petri-net-oriented and control-link-oriented audience really
want, I can accept it in a sense, as long as this is not the only way to
achieve similar business logic.
About static vs dynamic
parallelism: Static parallelism is basically <flow> construct in
BPEL. Dynamic parallelism is "parallel forEach" or "bundle". Issue 4 and 147
are related issues. http://www.choreology.com/external/WS_BPEL_issues_list.html#Issue4 http://www.choreology.com/external/WS_BPEL_issues_list.html#Issue147
About
"Terminating still running tasks versus proceeding in control flow while those
tasks are still running": I am not 100% that I understand your
question. Let me try to answer it anyway. The completeCondition is about
triggering termination of still-running tasks. The "proceeding in control
flow" (if I understand you correctly) will be handled by an outter flow. [I
guess it is related to (hotel and (train or plane)) flow??]
About
changes of "forcedTermination" fault handler: If you got a chance to
see some recent emails on Issue 135, Satish has recently suggested to remove
the notion "forcedTermination" fault and replace its fault handler with
cancelHandler. Frank, Yaron, Edwin and I all agree with this direction.
Because, overloading fault with the concept of "forcedTermination" is a "false
economy" and it creates quite a bit of unnecessary confusion.
I don't
think we should go back to this route or even further overload the
"forcedTermination" fault handler semantics. Because, fault handling is way
too generic and the changes you mentioned will create even more confusion.
(e.g. Will this change of marking as "completed" apply to all
"forcedTermination" fault handler / cancel handler of all scopes? )
I
guess most of us agree that we should have a new mechanism to kill / do an
early completion of a flow in a nice and clean way. However, overloading a
standard fault handler does not seem to be the best one. I would rather
introduce a construct which is very specific to <flow> or
parallel-forEach. For example, this <completeCondition> construct or
maybe a new activity called <completeFlow />. I will send out more
emails on joint thinking of both Issue 6 and Issue 135. Please stay
tuned.
Thanks!
Regards, Alex Yiu
Axel
Martens wrote:
Hi,
I like the simplicity of the syntax of Alex's
proposal. Although, for me it is
quite easy to model in terms of links and join conditions, and I want to keep my proposal alive
(because of the minimal changes to
BPEL's syntax and semantics), it looks like a nice macro to provide more convenience to the
customers.
Alex, could you
shortly explain to me, what do you mean by static and dynamic parallelism? How do you handle the two
different cases after evaluating the
completeCondition: Terminating still running tasks versus proceeding in control flow while those
tasks are still running (Sorry, I
missed your previous emails)?
I
agree to Alex's opinion, that we need a mechanism to kill parallel flow nice and clean. This could be done
either by a new mechanism which does
not throw a fault or by changing the way fault are handled. I have discussed already an example of the
second case with Ivana, and I like to tell
you, what I have in mind. Look at
the following example:
<scope
name="scopeFlow">
... <flow>
<link
name="linkA"/>
<link name="linkB"/>
<scope name="scopeA"> ... <invoke name="A"
...>
<source linkName="linkA" ...> </invoke> </scope>
<scope name="scopeB"> ... <invoke name="B"
...>
<source linkName="linkB" ...> </invoke> </scope>
<throw name="C"
faultName="bpws:forcedCompletion" joinCondition="linkA OR
linkB" joinEvaluation="immediate"> <target linkName="linkA"
...>
<target linkName="linkB" ...> </throw>
</flow> </scope>
First, I
explain the situation: In the example above, activity C will be executed if one of the two activities A and B
was successfully completed. Activity
C throws the fault "forcedCompletion". Like each other fault, this forces the
scope "scopeFlow" to terminate still
running activities. Assume, there was a fault handler defined in this scope which catches the
fault "forcedCompletion" (omitted in
here), the process continues after scope "scopeFlow". A problem arises, if scope "scopeFlow"
should be compensated. Because it
was exited from a fault handler, no compensation handler was installed.
Now, I explain my solution: In the example, I have
chosen a new "standard" fault name:
"forcedCompletion". The only necessary change is to allow a fault handler that catches this fault to
install a compensation handler for the same
scope, i.e. to mark the scope
"scopeFlow" as "completed" instead of "exited".
The standard compensation mechanism will only undo
those ("scoped") activities within
the scope, which actually have been successfully completed, i.e. scopeA or scopeB or may be both.
Axel. ---------------------------------------- Axel Martens
Post
Doc Researcher Component Systems Group IBM TJ Watson Research Center
Hawthorne, NY (USA) Phone: (914) 784-7480 E-mail: amarten@us.ibm.com
Hi,
Here are some examples how to use completeCondition
to express similar business logic in Axel's previous email:
(A)
"Select one out of three" example: <flow>
<completeCondition branch="1" />
<invoke name="CheckAirlineA" ... /> <invoke
name="CheckAirlineB" ... /> <invoke
name="CheckAirlineC" ... /> </flow>
(B) "Select two
out of three" example: <flow>
<completeCondition branch="2" />
<invoke name="AskRefereeA" ... /> <invoke
name="AskRefereeB" ... /> <invoke name="AskRefereeC"
... /> </flow>
As you guys can see, the completeCondition
declaration is very straight forward and simple. No complicated links and
joinCondition usage.
(C) "(Plane or Train) and Hotel" example: It
would become two flow constructed (nested).
<assign> ... <to
variable="planeResult"></assign> <!-- initialize
"planeResult" with NOT-OK value --> <assign> ... <to
variable="trainResult"></assign> <!-- initialize
"trainResult" with NOT-OK value --> <flow
name="checkIterinary"> <flow
name="PlaneOrPlane">
<completeCondition>
fn:planeOK(planeResult) or fn:trainOK(trainResult)
</completeCondition> <invoke
name="CheckPlane" outputVariable="planeResult" ... />
<invoke name="CheckTrain" outputVariable="trainResult" ... />
</flow> <invoke
name="checkHotel" /> </flow> <switch
name="bookingSwitch"> <case>
<condition>
(fn:planeOK(planeResult) or fn:trainOK(trainResult)) and
fn:hotelOK(hotelResult)
</condition> <invoke
name="invokeBooking" ... /> </case>
<otherwise> <invoke
name="writeInformation" ... /> </otherwise>
</switch>
Please note
that regardless whether we pick a link-oriented approach or
completeCondition approach:
- The initialization of result variables are needed because
of potential cancellation of one of the invoke between train and
plane
- The "fn:*()" represents the logic to determine whether a
traveling resource is available. They are used in either the
transitionCondition of links or the condition of switch/case.
As you guys see, we don't need declare to six
links. The completeCondition and case-condition are much simpler and easier
to understand.
I attach a diagram to illustrate the above
flows.
I guess we can still more time in terms of refiniment of
joinCondition evaluation. However, I don't think that should be the only
approach to achieve complete condition related
logic.
Thanks!!!
Regards, Alex
Yiu
Alex Yiu wrote:
Hi,
+1 to what Ivana said in general.
Few points to
add:
- Axel's proposed enhancement to control links evaluation
works to an extent for static parallelism (e.g. <flow>).
However, control links do not work well in dynamic parallelism (e.g.
"parallel forEach" or "bundle"). I think the notion of completeCondition
(borrowed from Ivana and DK) is general enough and it should be applied to
both static and dynamic parallelism. A general completeCondition mechanism
will be easier for BPEL users to learn.
- Even in a pure static parallelism case, completeCondition
has much better code clarity. It is more declarative and easier for BPEL
users to understand. It will eliminate significant amount of joinCondition
programming, which may be error prone. (I will send another email later to
show how completeCondition can be used to express the same semantics of
Axel's example).
- In one of my previous emails, I also tried to use a
"macro" way to illustrate how outstanding running flows can be cancelled
by throwing a fault within a scope. The illustration has the same
compensation handler installation problem that Ivana has pointed out. The
"illustraction macro" does NOT carry a desirable and intended semantics.
We need to create / describe a new mechanism to cancel parallel flow
without throwing a fault. (That was discussed briefly between Edwin and me
at Oracle).
Thanks!
Regards, Alex Yiu
Trickovic,
Ivana wrote: Axel,
I find the idea interesting. In fact, I was discussing the
completion condition issue with Dieter Koenig during the last f2f meeting
and his suggestion was also to try to resolve this issue using links. And we
identified that several changes need to be done, including removing
restriction for jonCondition, that "the join condition is evaluated as soon
as all incoming links of the activity are determined" - so definitely
"immediate" semantics needs to be introduced. I have the following comments on your proposal.
1. In your proposal you are using a
fault (bpws:forcedTermination) to terminate all active parallel branches.
But this changes the outcome of the flow activity. It will always end
abnormally and compensation handler (if it is defined) will never be
installed. Although completion condition has evaluated to true and needed
activities have completed the enclosing flow activity will end abnormally.
Is this really intended semantics? 2. Your proposal
does not address some pain points. For example, in case of "N out of M",
N<M there many possible "variations": (A) One enclosed activity may experience problems but the
<flow> activity may succeed (B) One of enclosed activities may experience a severe error, which
may have impact on the <flow> activity The question is what to do with running activities? In the
latter case, reasonable behavior would be: if one enclosed activity does not
succeed other running activities should be cancelled and the flow activity
should try to recover. In the former case, we should allow active parallel
activities to complete their work. This is not supported in your
proposal. Regards,
Ivana
[stuff deleted]
|