Notes on improving the Tuscany async invocation infrastructure. See https://issues.apache.org/jira/browse/TUSCANY-3783.
Separating Infrastructure from Java specifics
Here's a quick diagram on my understanding of the current code in trunk.
The bold green lines look at the kind of separation I think we should head for. The motivation for this is that we'll need to support this mode of operation from implementation types other than Java such as implementation.bpel.
I've copied samples\extending-tuscany\implementation-sample to unreleased\samples\implementation-sample-async as a new and neutral implementation type where we can look at what this separation means.
Non-Native Asynchronous Reference Bindings
Here's how I think the separation pans out on the reference side
There is a new operation on the EndPointReference that allows the implementation provides to make a async invocation. It's described in a new InvokerAsync interface:
Code Block |
---|
public interface InvokerAsync { /** * Process an asynchronous wire * * @param msg The request Message for the wire * */ void invokeAsync(Message msg) throws Throwable; } |
There's a new async implementation provider interface that allows the infrastructure to retrieve and invoker that knows how to deal with the async response:
Code Block |
---|
public interface ImplementationAsyncProvider extends ImplementationProvider { /** * Create an invoker for the asynchronous responses in the invocation * chain. The invoker will be responsible for processing the async * response including correlating it with the forward call using * the MESAGE_ID that appears in the message header. * * @param service The component service * @param operation The operation that the interceptor will handle * @return An AsyncResponseHandler<T> instance */ Invoker createAsyncResponseInvoker(RuntimeComponentService service, Operation operation); } |
Non-Native Asynchronous Service Bindings
Here's how I think the separation pans out on the service side
Doing this has made me ask a rather fundamental question though. We don't take account of the fact that some bindings are naturally asynchronous, I.e. there is no service exposed with a response interface to which asynchronous response are sent.
Native Asynchronous Reference Bindings
I've drawn a picture of what this might look like.
Note that I imagine that it's the reference's responsibilty to look after processing the asynchronous response. There are some important implications her. Namely:
1 - The EndpointReference will need another new method, something like invokeAsyncResponse(Message), that will be called by the native async bindings async response listener.
2 - The EndpointReference will need to be able to invoke just the response side of its forward chain. This means extending the invoker interface
3 - The EndpointRefereence will need to pass the response into the implementation provider. The async response invoker already described can be used here.
Of these perhaps 2 is the most controversial. To make it work I think we need to change the new InvokerAsync interface to be something like.
Code Block |
---|
public interface InvokerAsync { Message invokeRequest(Message msg) throws Throwable; Message invokeRequest(Message msg) throws Throwable; } |
And then implement this with any inteceptors we expect to use on async wires (eventually all interceptors). In this way the separate sides of the chain can be invoked independently. We may also need to give the chain the ability to read the chain backwards for when we want to process the async response.
Native Asynchronous Service Bindings
And here's the same thing but on the service side.