Hi

I've done some work and now there're few more options to do with making webcliens and proxies thread-safe. I'll chat about proxies a bit too (it's offtopic for this thread but I'll just try to put all the info in one email, sorry about it)

WebClient.fromClient() will work in all the cases for both proxies and web clients, as well as JAXRSClientFactory.toClient() but it may not be quite ideal from the testing point of view and it is not quite cool that an injected webClient/proxy is acts purely as a source for the copy construction.

If a webClient or proxy does a one way request without changing the current uri during subsequent invocations (ex, webClient.path("{bar}", 1).post(...), webClient.back(), webClient.path("{bar}", 2).post(...), webClient.back()) then there's no need to synchronize or worry about the internal thread safety.

Both approaches will work fine on the trunk right now. The explicit synchronization followed by webClient.reset() should work ok for oneways.

Now, with the fixes being committed, it is possible :

1. To reuse a plain webclient/proxy instance accross multiple threads if it is the same URI and headers (configured at the injection time) which are being reused across multiple requests. The only limitation here is that a proxy can not get the 'safe' Response (without synchronizing) :

Book book  = bookStoreProxy.getBook();
// get some response headers passed to us 'outofband', which is unreliable for 
a plain proxy :
Response response = 
WebClient.toClient(bookStoreProxy).getHeaders().getFirst("BookHeader");

2. The complexity may come when say a given webClient is reused accross mutiple requests and this client does add new headers or manipulates the path somehow, etc, accross every new request :

public class BridgeResource {
public void doIt(String path, String header) {
// WebClient.toClient(webCleint)
webClient.header("bar", header);
for (int i = 0; i < 5; i++) {

     webClient.path(path);
     webClient.post(...);
     webClient.back(false);
}
}
}

etc...Likewise, I'm quite keen on letting the proxies check the Responses as shwon abaobe even if they're not coded to have Responses explicitly returned.

For the above to work well WebClient.toClient() can be used, but another option now is to just pass a threadSafe boolean value to either WebClient.create() or JAXRSClientFactory.create() or JAXRSClientFactoryBean (from Spring or programmatically). The above will work just fine, see [1].

Now, if thread-safe webclients/proxies are used then there're few options available to do with the timely cleanup of the thread-local storage [2]. Perhaps the simplest option is do nothing if we have a bound/limited number of threads coming in over the time, with the worker threads even being recycled. If we have a case where it is possible that the original thread which left the state will not come back but will stay alive forever serving something else and we have thousands of such threads then it may be worth configuring a ThreadLocalClientState to remove the stale state, by setting a secondsToKeepState property. In this latter case WebClients/proxies will have to be created using JAXRSClientFactoryBean (it has createWebClient() method) and can have the address/providers/etc sert on it...

If you need some more info or have some suggestions then please let me know

thanks, Sergey


[1] http://svn.apache.org/repos/asf/cxf/trunk/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/JAXRSMultithreadedClientTest.java [2] http://svn.apache.org/repos/asf/cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/client/ThreadLocalClientState.java





Hi

Okay thanks Sergey, I may do that then.
Although this will make testing quite painful (mocking out the webclient copy 
then not really possible)

I see...


Commons HttpClient 3.x has a nice way of injecting a MultithreadedHttpConnectionManager into the client to make it threadsafe, and allowing easy testing too


To some extent, the CXF ConduitInitiator (used internally) will act as a connection manager...What is really thread-unsafe at the moment is that a WebClient persists the latest response details and the currentURI until the next invocation so the problems may arise in deserializing the per request specific response input streams. I'll be looking into this issue later on...

cheers, Sergey

Cheers
Paul

-----Original Message-----
From: Sergey Beryozkin [mailto:[email protected]]
Sent: 09 February 2010 11:16
To: [email protected]
Subject: Re: is webclient thread safe ?

Hi

Unfortuntately not, not yet.
However, you can do the following on every request, after it has been injected :

public class SomeService {
private WebClient injectedWc = ...

@POST
public void doIt() {

   // copy-constructor-like creation
   WebClient currentWc = WebClient.fromClient(injectedWc, true);
   // or just WebClient.fromClient(injectedWc);

   currentWc.post(...)
}

}


The currentWc will get all the configuration the injectWc has, including the headers which might've been set on it on the init time
(the 2nd 'true' parameter). WebClient.fromClient() can be used to 'convert' 
proxies into WebClients too. I've been thinking about
the tread-safety of a single client earlier on and at a time I chose to have 
methods like WebClient.getResponse() or
WebClient.back() working well. I reckon WebClient.fromClient() can be quite a cheap alternative (albeit with some extra effort from a user) to making sure a proxy/client is thread-safe internally, however, I'll be looking into this issue with more attention once I
get into working on enhancing the client api (on the map)...

Hope it helps, Sergey

Hi

How thread safe is WebClient.  Can it be injected (spring wired) into a
bean, and reused on a per request basis to call a downstream web service
?



Thanks for any guidance

Paul


This e-mail (and any attachments) is confidential and may contain personal 
views which are not the views of the BBC unless
specifically stated. If you have received it in error, please delete it from 
your system. Do not use, copy or disclose the
information in any way nor act in reliance on it and notify the sender 
immediately.

Please note that the BBC monitors e-mails sent or received. Further 
communication will signify your consent to this

This e-mail has been sent by one of the following wholly-owned subsidiaries of 
the BBC:

BBC Worldwide Limited, Registration Number: 1420028 England, Registered 
Address: BBC Media Centre, 201 Wood Lane, London, W12 7TQ
BBC World News Limited, Registration Number: 04514407 England, Registered Address: BBC Media Centre, 201 Wood Lane, London, W12 7TQ BBC World Distribution Limited, Registration Number: 04514408, Registered Address: BBC Media Centre, 201 Wood Lane, London, W12 7TQ







Reply via email to