sca-j message
[Date Prev]
| [Thread Prev]
| [Thread Next]
| [Date Next]
--
[Date Index]
| [Thread Index]
| [List Home]
Subject: Re: [sca-j] Another early morning brainstorm - conversations revisited
- From: Simon Nash <NASH@uk.ibm.com>
- To: "OASIS Java" <sca-j@lists.oasis-open.org>
- Date: Fri, 8 Aug 2008 15:33:42 +0100
Mike,
Unfortunately it appears that the indentation
that Jim is using for his comments is getting stripped out when I send
my replies. I didn't realise that this was happening.
Simon
Simon C. Nash, IBM Distinguished Engineer
Member of the IBM Academy of Technology
Tel. +44-1962-815156 Fax +44-1962-818999
Mike Edwards/UK/IBM@IBMGB
08/08/2008 13:02
|
To
| "OASIS Java" <sca-j@lists.oasis-open.org>
|
cc
|
|
Subject
| Re: [sca-j] Another early morning brainstorm
- conversations revisited |
|
Folks,
Can I make a plea for better and clearer separation of the different parts
of the discussion.
It is gettting *extremely* hard to follow this debate with the complex
mixing of comments.
Yours, Mike.
Strategist - Emerging Technologies, SCA & SDO.
Co Chair OASIS SCA Assembly TC.
IBM Hursley Park, Mail Point 146, Winchester, SO21 2JN, Great Britain.
Phone & FAX: +44-1962-818014 Mobile: +44-7802-467431
Email: mike_edwards@uk.ibm.com
From:
| Simon Nash/UK/IBM@IBMGB
|
To:
| OASIS Java <sca-j@lists.oasis-open.org>
|
Date:
| 08/08/2008 11:24
|
Subject:
| Re: [sca-j] Another early morning brainstorm
- conversations revisited |
Jim,
This is a good discussion that is bringing out many important points. My
latest responses are in <scn4>....</scn4>.
Simon
Simon C. Nash, IBM Distinguished Engineer
Member of the IBM Academy of Technology
Tel. +44-1962-815156 Fax +44-1962-818999
Jim Marino <jim.marino@gmail.com>
07/08/2008 23:54
|
To
| OASIS Java <sca-j@lists.oasis-open.org>
|
cc
|
|
Subject
| Re: [sca-j] Another early morning brainstorm
- conversations revisited |
|
Simon,
I've commented inline and snipped some of the previous text to make it
easier to read...
<snip/>
I accept that my current proposal doesn't do this, but tries to provide
quite a lot of capability within the infrastructure. If the TC feels
this road is leading to a dead end then we could start a very different
discussion about what additional things could be delegated to business
code.
I don't think it is necessarily leading to a dead end but it would be beneficial
to step back and agree on the main use cases we are trying to achieve as
well as the extent of changes we are willing to make. If we agree
on the use cases, it will be easier to judge the merits of the various
proposals by looking at how application code would need to be written.
Use cases also have the nice effect of keeping scope limited.
<scn3>My main concern about moving the focus of the discussion to
use cases is that we already tried to do this, and the result was the union
of everyone's opinions on what the important use cases are (i.e., no possible
use cases were eliminated.)</scn3>
I still think this would be useful, even if it is a union, particularly
to contrast complexity introduced into application logic by the various
proposals.
<scn4>I think a side-by-side code comparison would be useful. I
believe I laid out the use cases in my earlier proposal
http://www.oasis-open.org/committees/download.php/27733/JAVA-25-Proposal-2.doc
Please take a look at the use cases there (not the specific proposal) to
see whether you agree they are the right ones to compare.</scn4>
<snip/>
What happens if I want to introduce asynchrony (non-blocking operations)
such as:
public interface OrderService {
@OneWay
void startNewOrder();
@OneWay
void orderApples(..);
@OneWay
void orderPlums(..);
}
Does the proposal require interfaces to have a synchronous operation to
start a conversation?
<scn2>Yes it does, and I believe this restriction is needed whether
or not we make API changes. The first operation of a conversation
will create an instance and initialize it for use by subsequent calls within
the same conversation. If the first operation is oneway, the client
can proceed immediately and it might make the second call before the first
call has completed (or even started) executing.</scn2>
I don't believe the current API requires this at all and that behavior
is the opposite of what I am proposing. The reference proxy can simply
make an out-of-band synchronous call to allocate a conversational id. This
may or may not involve out-of-process work. Either way, the proxy does
not return control to the client until an id is generated. The two key
things I am proposing are:
1. How the conversation id is generated does not bleed through to the programming
model
2. Id generation does not require an operation on the target service to
be invoked
Expanding on point 2, requiring a conversation to be initiated by a synchronous
operation *to the service* cannot work over JMS when the client is using
transacted messaging since messages are not sent until after the transaction
has committed This is a very common messaging scenario. Assuming the callback
is handled via a reply-to queue that the client listens on, the consumer
only receives enqueued messages when a transaction commits, thereby inhibiting
the client from receiving a response. If in the original above example
the client is participating in a global transaction and OrderService.startNewOrder()
returns a CallableReference or a proxy, the client will hang as the forward
message will not be received until the transaction commits (which won't
occur since the client would be listening on the reply-to queue).
To avoid this, I imagine most JMS binding implementations would use the
mechanisms as described by the JMS binding spec and pass a conversation
id in the message header.
Therefore, I believe your proposal won't work in these scenarios.
<scn3>I understand your point about JMS. However, you haven't
addressed my other point about the conversational provider instance needing
to be created and initialized before further invocations are made on it.
For transports that provide reliable queued in-order delivery of
messages (the JMS case) the transport can take care of this. For
other transports, the first invocation must execute and complete before
the second one can occur. This serialization needs to be handled
somehow, either by the application or by the infrastructure.</scn3>
Sorry, I didn't explain well. Let me try with an example. The current
programming model will work fine in the case you outline above, that is,
when an invocation arrives out of order as long as the creation of the
conversation id is a synchronous event from the perspective of the client
reference proxy. Let's start by taking a simplistic SCA implementation
and look at the sequence of events that would happen:
1. Application code invokes a reference proxy that represents a conversational
service by calling the orderApples operation
2. The reference proxy knows a conversation has not been started so acquires
a write lock for the conversation id and *synchronously* performs some
work to get a conversation id. Since this is a simplistic implementation,
it generates a UUID. and caches it, then releases the write lock. From
this point on, the conversation id is available to the reference proxy.
3. The reference proxy then invokes the orderApples operation over some
transport, flowing the id and invocation parameters
4. The reference proxy returns control to the application logic
5. At some later time, the orderApples invocation arrives in the runtime
hosting the target service
6. If the target instance is not created or initialized, the runtime does
so
7. The runtime dispatches the orderApples invocation to the target instance.
Now let's assume the client invokes both orderApples and orderPlums in
that order, which are non blocking. Let's also assume ordered messaging
is not used (e.g. the dispatch is in-VM using a thread pool) and for some
reason orderPlums is delivered to the target runtime before orderApples.
Steps 1-4 from above remain the same. Then:
5. The application logic invokes orderPlums.
6. The reference proxy acquires a read lock to read the conversation id
which it obtains immediately. It then releases the lock and flows the invocation
data and id over some transport.
7. The orderPlums request arrives, along with the conversation id created
in step 2 before the orderApples invocation.
8. The target instance does not exist, so the runtime instantiates and
initializes it
9. The orderApples invocation containing the operation parameters and same
conversation id arrives on the target runtime . At this point the target
instance is already created so the runtime dispatches to it.
Note that the read/write lock would not be necessary for clients that are
stateless components since they are thread-safe.
In the above cases, the creation of a conversation id is orthogonal to
the creation of a provider instance and the former always completes prior
to an instance being created. If we were to replace the conversation generation
algorithm (UUID) with something that was more complex (e.g. called out
to the service provider runtime) the same sequence would hold.
Also, the above sequence solves the problem of using conversational services
with transacted messaging that arises by forcing a request-reply pattern
to be part of the forward service contract.
<scn4>Now it's my turn to apologize for not explaining well enough.
The sequence above covers the case where either of the two forward
calls can validly execute first on the same conversational instance. The
case I am concerned about is where the first call must execute before the
second call because it does some necessary prerequisite initialization
of the conversational instance. For example, the first call is "create
order" and the subsequent calls add items (apples, plums) to the order
that was previously created. I believe this will be the common case,
and in this case it is necessary for the first call in the conversation
to be a two-way call.</scn4>
2. Clarification on service operation signatures
I'm unclear if by the following the proposal intends to require use of
CallableReference for conversational interactions:
A simple extension to the model already proposed can solve both these problems.
A conversation would be initiated by the service creating a CallableReference
and returning it to the client. This CallableReference contains an
identity for the conversation. This client then makes multiple calls
through this CallableReference instance. Because these calls all
carry the same identity, a conversation-scoped service will dispatch all
of them to the same instance.
I'm assuming this is just for illustrative purposes and it would be possible
for a conversation to be initiated in response to the following client
code, which does not use the CallableReference API:
public class OrderClient ... {
@Reference
protected OrderService service;
public void doIt() {
service.orderApples(...);
service.orderPlums(...); // routed to the same target instance
}
}
Is this correct?
<scn>In a word, No. All conversations would need to be initiated
by the proposed mechanism of having the server return a CallableReference
to the client. This allows the conversation identity to be generated
by the server, not the client. Several people (e.g., Anish and Mike)
have called this out as an issue with the current mechanism for conversations.</scn>
Sorry for being so thick, but I don't see why the above could not be supported
using "server" generation of conversation ids. We should be careful
here to specify what we mean by "server", and whether invocations
are flowing through a wire or a client external to the domain. I don't
think the term "server" should necessarily mean "the runtime
hosting the service provider." Sometimes this may be the (degenerate)
case, but not always.
For communications flowing through wires, the only thing we can likely
say is "conversation ids are generated by the domain". I
would imagine most domain implementations would chose an efficient id generation
scheme that can be done without context switching on every invocation (e.g.
UUID generation provided by the JDK). However, in cases where this efficient
identity generation is not possible, I believe SCA infrastructure can support
the above code. In this case, the reference proxies would be responsible
for making some type of out-of-band request to generate a conversation
id to some piece of domain "infrastructure".
<scn2>I'm very uncomfortable with placing this kind of runtime requirement
on the SCA domain, which IMO should not take on the responsibilities of
a persistence container. For efficient support of persistent conversational
instances with failover, load balancing and transactionality, the ID may
need to be generated by a persistence container. For example, it
could be a database key.</scn2>
I think this is less of a requirement than what you are proposing, which
also shifts the burden to application code (which should not have to deal
with these mundane infrastructure concerns).
The only requirement I am making is the "domain" provides the
key. My usage of the term "domain" is intentionally vague: it
could be a database, some service hosted in a cluster, or a snippet of
code embedded in a Java proxy. Generating the id can therefore be
done using a database key or, more simply, by having a reference proxy
use facilities already provided in the JDK 1.5 or greater, which would
require one line of code. My proposal would not restrict the SCA infrastructure
in how the id is generated, other than it is done synchronously and out-of-band.
<scn3>I'm concerned about putting too much mechanism into the SCA
domain. I think it needs to support SCA wiring, deployment and configuration.
I'd expect it other middleware that's not part of the SCA domain
to provide things like persistence, load balancing and failover.</scn3>
We may have a conceptual difference. I consider domain infrastructure to
include any middleware resources used by the SCA implementation. This may
include multiple runtimes, databases, messaging providers, JEE app servers
etc. An SCA implementation would not necessarily implement persistence,
ordered messaging, transaction recovery, etc. Rather, it could use other
software to provide those features. For example, an SCA implementation
that supports key generation using a database table may only contain a
DDL script and code that makes a JDBC call. Given that, I don't think I'm
putting anything into the domain.
<scn4>Yes, we seem to have a conceptual difference on what constitutes
the SCA domain. I see the system middleware as providing an SCA domain
as well as these other capabilities. IMO, SCA should not attempt
to provide a complete appserver infrastructure (become the new JEE). Over
time we may grow the SCA envelope as systems move towards a more service-oriented
internal sturucture, but I would like to take this step by step and not
attempt to take on too much in the first round of OASIS specs.</scn4>
The important thing is how conversation id generation happens does not
bleed into the programming model and is transparent to the application.
In other words, we not should require anything more complex than this when
the OrderClient is wired to an OrderService:
public class OrderClient ... {
@Reference
protected OrderService service;
public void doIt() {
service.orderApples(...);
service.orderPlums(...); // routed to the same target instance
}
}
<scn2>Another important thing is how much complexity is needed inside
the infrastructure to support the programming model. This cannot
always be hidden under the covers, especially when dealing with failure
cases and complex environments. The need for persistent transactional
storage of conversational instances is an example of where this complexity
arises.</scn2>
Here it would be useful to outline a specific use case for "persistent
transactional storage of conversational instances" as I'm not sure
what that entails. Does it mean the following
1. Invocations to orderApples() and orderPlums() are done with guaranteed
delivery
2. Changes to the *state* of a given OrderService instance are guaranteed
to be available in the case where the runtime hosting the instance fails
I suspect if it is the above, much of the complexity will be buried in
the messaging and failover infrastructure, not the SCA runtime.
<scn3>SCA would need to decide whether or not such guarantees are
part of the SCA conversational programming model. If they are, then
the SCA domain would have to step up to providing the mechanisms to implement
them. It's currently unclear from the SCA specs what assumptions,
if any, application code can make about these matters.</scn3>
I believe these should not be concerns of the programming model. They should
be expressed through policy. Also, the SCA implementation would be free
to delegate to some other middleware to provide these features.
<scn4>I'm not convinced that all of these aspects should be handled
through SCA policy or SCA mechanisms (see my previous comment).</scn4>
<snip/>
How about the current API:
public class OrderClient ... {
@Context
protected ComponentContext context;
public void doIt() {
service.orderApples(...);
CallableReference<OrderService>
reference = context.cast(service);
//...
}
}
Or, we could change "cast(..)" to
public interface ComponentContext {
<T> CallableReference<T> getCallableReference(T proxy);
}
I believe this to be similar in spirit to working with message-based correlation
ids (e.g. JMS) where the forward message id is not available until after
the message has been enqueued.
<scn2>This doesn't work because a callback can occur before control
is returned back to the invoking thread of execution. So the client's
conversation correlator must be known before invoking any call that may
trigger a callback, in case the callback business code needs to do anything
that needs to use the conversational state. There's a similar issue
with "callback ID" (if we retain this concept), as a forward
call can invoke a callback which may need to use a previously generated
callback ID to identify the context in which the callback business code
should execute.</scn2>
This assumes the conversation id is generated asynchronously from the client.
That is not what I am proposing. The first invocation on a proxy would
not return control to the client until after a conversation id was generated.
The difference with what I am saying and what you are proposing is that
the synchronous act of generating the id:
1. Is not exposed to application code and does not place requirements on
the service contract
2. Does not necessarily require any out-of-process work
<scn3>The problem with this is that as soon as the invocation is
made on the service, a callback could arrive, and this could happen before
the client code that calls the proxy has received control back from the
SCA runtime and been able to process the generated ID.</scn3>
In the sequence I defined above, a callback can never happen before the
conversation id is generated since the latter is a synchronous operation
that completes before a service provider instance is created.
<scn4>I haven't been able to explain my concern well enough. Let
me lay it out using sequences of steps. Sequence A is what the client
application expects will happen, Sequence B is what may actually
happen in some cases.
Sequence A:
1. The client business logic calls a proxy to start a conversation.
2. The proxy interacts with some system facility to obtain a conversation
ID.
3. The proxy invokes the service.
4. The proxy returns to the client.
5. The client business logic obtains the conversation ID from the proxy.
6. The client business logic creates a correlation entry keyed by the conversation
ID, for use by callbacks.
7. The service business logic executes and makes a callback to the client.
8. The client callback business logic uses the conversation ID passed by
the server to lookup the correct information in the correlation table.
Sequence B:
1. The client business logic calls a proxy to start a conversation.
2. The proxy interacts with some system facility to obtain a conversation
ID.
3. The proxy invokes the service.
7. The service business logic executes and makes a callback to the client.
8. The client callback business logic uses the conversation ID passed by
the server to lookup the correct information in the correlation table.
4. The proxy returns to the client.
5. The client business logic obtains the conversation ID from the proxy.
6. The client business logic creates a correlation entry keyed by the conversation
ID, for use by callbacks.
If steps 7 and 8 happen before steps 4, 5 and 6, the client logic is broken.
The only way to guard against this is to move steps 5 and 6 much
earlier, and change what step 2 does, as follows:
Sequence C:
5. The client business logic obtains a conversation ID from the system
infrastructure.
6. The client business logic creates a correlation entry keyed by the conversation
ID, for use by callbacks.
2. The client business logic associates this conversation ID with a proxy
for the service.
1. The client business logic calls a proxy to start a conversation.
3. The proxy invokes the service.
7. The service business logic executes and makes a callback to the client.
8. The client callback business logic uses the conversation ID passed by
the server to lookup the correct information in the correlation table.
4. The proxy returns to the client.
Steps 5 and 2 in sequence C require either new APIs or new semantics for
existing APIs. This negates the apparent simplicity advantage of
your proposed approach.</scn4>
<snip/>
Does this help at all? It eliminates the use of CallableReference
in business service APIs, though not in client business logic.</scn2>
It's a start but doesn't address my main concerns:
1. I don't think it will work for important messaging use cases
2. It places unnecessary restrictions on conversational service contracts,
namely a forward synchronous invocation
3. It will result in a lot of unnecessary application boilerplate code.
For example, all conversational calls will need to start with a synchronous
call to the provider, even if no application or business function is modeled.
4. Application logic is still unnecessarily tied to infrastructure
5. It's a lot more complex than the examples I gave or alternatives to
SCA
6. It's confusing, particularly this line:
OrderService myConversation = myService.startNewOrder(); // returns an
ID for the entire fruit order
For example, if I am an app developer, I will ask why do myService and
myConversation implement the same interface? What's the difference (I know
what it is but one can't tell by looking at the code)?
7. Requiring an extra invocation to start a conversation does not promote
coarse-granularity. It will result in an unnecessary and potentially costly
performance impact as an additional remote call is introduced.
<scn3>I'll observe that most or all of these focus around the proposed
additional forward synchronous call that returns a conversation ID. If
we could find a way to avoid the need for this, we might be close to agreement.</scn3>
Yes, that is mostly it although I also believe we do not need CallableReference
and we may have some differing opinions on the relationship between callbacks
and conversations. I believe Mike and my proposal solves the issues brought
forth as well as provides a way to avoid requiring a forward synchronous
call to return a conversation id to application logic. If you don't agree
that I have dealt with the issues raised previously, could you let me know
which specific cases. If I have, then would it be acceptable to move to
look at what you don't like about what Mike and I have proposed and perhaps
take that as a point for moving forward since the proposal only subtracts
from the current API and involves less change?
<scn4>I'd like to resolve the non-conversational callback case first,
as agreed by the TC at the F2F. (See the other note that I just sent
to the list with a proposal for this.) When we have resolved that,
I think the next step is to look at how the basic callbacks mechanisms
can be extended incrementally to handle conversations. For this second
stage we could look at multiple options, including some refinement of my
proposal and the proposal from you and Mike. There is another possible
option as well, which is to reconsider whether conversations in their current
form should be part of SCA. Before we open up all of that debate,
I think we need to have the basic callback approach in place</scn4>
Jim
Unless stated otherwise above:
IBM United Kingdom Limited - Registered in England and Wales with number
741598.
Registered office: PO Box 41, North Harbour, Portsmouth, Hampshire PO6
3AU
Unless stated otherwise above:
IBM United Kingdom Limited - Registered in England and Wales with number
741598.
Registered office: PO Box 41, North Harbour, Portsmouth, Hampshire PO6
3AU
Unless stated otherwise above:
IBM United Kingdom Limited - Registered in England and Wales with number
741598.
Registered office: PO Box 41, North Harbour, Portsmouth, Hampshire PO6
3AU
[Date Prev]
| [Thread Prev]
| [Thread Next]
| [Date Next]
--
[Date Index]
| [Thread Index]
| [List Home]