You are viewing a plain text version of this content. The canonical link for it is here.
Posted to users@cxf.apache.org by Paul Wilton <Pa...@bbc.com> on 2010/02/09 11:48:35 UTC

is webclient thread safe ?

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

 
 

Re: is webclient thread safe ?

Posted by Sergey Beryozkin <sb...@progress.com>.
Actually, forgot to mention one more (simpler) option to do with the timely cleanup of the thread-local storage :

try {
   webClient.path("bar")
   webClient.header("bar", baz);
   webClient.invoke(...);
} finally {
   // if proxy : WebClient.client(proxy).reset();
   webClient.reset();
}

> 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:sberyozk@progress.com]
>>> Sent: 09 February 2010 11:16
>>> To: users@cxf.apache.org
>>> 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
>>>
>>>
>>>
>>>
>>>
>>
>
> 


Re: is webclient thread safe ?

Posted by Sergey Beryozkin <sb...@progress.com>.
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:sberyozk@progress.com]
>> Sent: 09 February 2010 11:16
>> To: users@cxf.apache.org
>> 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
>>
>>
>>
>>
>>
> 


Re: is webclient thread safe ?

Posted by Sergey Beryozkin <sb...@progress.com>.
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:sberyozk@progress.com]
> Sent: 09 February 2010 11:16
> To: users@cxf.apache.org
> 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
>
>
>
>
> 


RE: is webclient thread safe ?

Posted by Paul Wilton <Pa...@bbc.com>.
Okay thanks Sergey, I may do that then. 
Although this will make testing quite painful (mocking out the webclient copy then not really possible)

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

Cheers
Paul

-----Original Message-----
From: Sergey Beryozkin [mailto:sberyozk@progress.com] 
Sent: 09 February 2010 11:16
To: users@cxf.apache.org
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





Re: is webclient thread safe ?

Posted by Sergey Beryozkin <sb...@progress.com>.
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