PDA

View Full Version : Improving throughput by creating Asynchronous Web Services ( a working approach )


javajunky
06-15-2007, 11:08 AM
I have a service in my Spring app that executes long running web-service calls (this is all it does, it is very lightweight, just acts as a proxy).
However the default behaviour of Asp.Net web services when exposed is to consume a worker thread from the pool, which after 25 or so requests (12 in my case due to an unrelated issue with maxconnections *sigh* ) locks the system so it can no longer receive requests.

Now, I've written around this by creating my own ASMX Handler factory, that constructs IHTTPAsyncHandler derived classes rather than IHTTPHandlers, each of which consumes the IHTTPHandler that the Spring.Web.WebServiceHandlerFactory would have provided when called for .asmx .

This works really well, and free's ASP.Net to handle parallel web requests whilst these long running requests work in the background. (Just ask if anyone wants some example code)

*However* whilst researching these issues I'm seeing ([1],[2]). I came across a neater approach which was rather than exposing

[WebMethod]
public string MyMethod()

if you expose

[WebMethod]
IAsyncResult BeginMyMethod(AsyncCallBack cb, object obj, ...parameters...)

[WebMethod]
string EndMyMethod(IAsyncResult result)


Then the wsdl would only expose a single 'MyMethod' method that returned a string, and when called the web-service would be handled seperately to the threads consumed by the requests.

For me this is very useful as it allows the system to continue handling and responding to requests even when it is 'busy' servicing many long-running requests. Which is very important so I can respond to requests with a 'too busy' response when I really am too busy, rather than just ending up in a big request queue.

Clearly this approach isn't suitable for every WebService method, but there are some cases where it would be very useful. e.g. When calling another remote web-service request, inline [my case].

I figure I can implement this by extending the existing WebServiceExporter, would this be a useful thing to work on, or should I stick with my (currently working) AsyncHandlerFactory approach ?

Many thanks,




-- Ciaran
[1] : http://blogs.msdn.com/tess/archive/2006/02/23/537681.aspx
[2] : http://msdn2.microsoft.com/en-us/library/ms998562.aspx#scalenetchapt10_topic9

edit: Hmm, as an added complexity, the BeginMyMethod call would need to grab + store the HttpContext.Current in order to set it back in the thread that handles the asynchronous work or WebApplicationContext.Current won't be at all happy.

Bruno Baia
06-26-2007, 08:53 PM
Hi,

Sorry for the delay.
This is interresting.. didn't know we can do that on the server side.

Tell me what you don't like in your first solution ?
The 'all or nothing' configuration : all methods will be asynchrone if you use the IHTTPAsyncHandler ?


The second implementation needs some changes in the WebServiceExporter but it should work, and we will be able to configure it via configuration :

<property name="AsyncMethods">
<list>
<value>MyMethodName1</value>
<value>MyMethodName3</value>
</list>
</property>



Bruno

javajunky
06-26-2007, 10:20 PM
Hi,

Sorry for the delay.
This is interresting.. didn't know we can do that on the server side.

Neither did I until I started running out of worker threads!! (this happens remarkably quickly if you have even a few long running web method connections!]


Tell me what you don't like in your first solution ?
The 'all or nothing' configuration : all methods will be asynchrone if you use the IHTTPAsyncHandler ?

The problem was I had to re-implement the Spring.Web.ServiceHandlerFactory, I couldn't neatly sub-class it in any way :( [Effectively I've cut'n'pasted the code from Spring.Web.ServiceHandlerFactory, into a new 'AsynchHandlerFactory'].
It just seems a little more logical to me to apply the 'this method is asychronous' type behaviour at the point which I expose the service, not at the handler-factory [I did toy with the idea of an Attribute on the class, but thiswould also have required a new handler factory]


The second implementation needs some changes in the WebServiceExporter but it should work, and we will be able to configure it via configuration :

<property name="AsyncMethods">
<list>
<value>MyMethodName1</value>
<value>MyMethodName3</value>
</list>
</property>

Bruno

I *think* this would be more useful, perhaps also a 'async service, or perhap reg-ex method-names so one could specify <value>.*</value>.

It is quite complex to do this properly I think [for me at leas], for example I have a dedicated thread-pool purely for servicing these async requests in the handler factory instance, allowing me to refuse web service connections if there is too much demand on the service (the pool of waiting items in the queue is too large). Also the generated proxy code needs to keep track of the HTTPContext.Current value at the time the IAsyncResult implementing object was created, so it is set-back-up again at the time the asynchronous thread *actually* begins working on the workitem. (I toyed with execution contexts, but they ddn't seem to do things quite right for me, although would probably be the best way of doing things to transport thread-security credentials about as well?)