Jersey Client, memory leak, static and concurrency - java

I am using Jersey Client (v2.17) to make external calls from my app.
I found out this memory leak bug (the CPU consumption was very high) which made me re-write my code to make the client static like this:
public class GeneralUtil {
private static final Client client = ClientBuilder.newClient()
public static String makeCall(String url) throws NotFoundException {
return client.target(url).request().get(String.class);
}
}
However, now I have concurrency problems - I am using this class to be called from multiple threads. I keep on getting:
org.apache.http.impl.execchain.RequestAbortedException: Request aborted
Any suggestion - how can I still prevent the memory leak, and still use the client?

If you don't want to create an arbitrary number of Client objects, you can use ThreadLocal and have one object per thread.
You can override ThreadLocal.initialValue to return ClientBuilder.newClient() to automate creation of Client objects for new threads.
Or you could make the methods synchronized, but that means that you will only be able to do one request at a time.
Here's some example code:
class GeneralUtil {
ThreadLocal<Client> client = new ThreadLocal<Client>() {
#Override
public Client initialValue() {
return ClientBuilder.newClient();
}
};
public static String makeCall(String url) throws NotFoundException {
return client.get().target(url).request().get(String.class);
}
...
}

As initially stated by Dejel, this is a known issue.
The "workarounds" work... but I believe this issue is critical and should be fixed by the Jersey team.
Let the Jersey team know that this affects YOU by logging in to JIRA and voting it up. It currently only has 3 votes :
https://java.net/jira/browse/JERSEY-2830

Related

Synchronizing rest service using JAVA Spring

I have a POST request that I would like to synchronize based on the incoming request body POJO. The request body has a variable by which I can identify if the incoming request is a duplicate or not.
My problem is that each incoming request body has a different reference.
I am generating some sort of confirmation number with the sample request body. I am getting multiple confirmation numbers for the same identifier(property inside SampleRequestBody class) which I don't want.
#PostMapping(value = "testingSync", headers = {"Content-type=application/json"})
public void testingSync(#RequestBody SampleRequestBody sampleRequestBody) {
synchronized(sampleRequestBody) {
//Do some process with the sample request body
}
}
The sample request body looks something like this
public class SampleRequestBody {
private String identifier;
public String getIdentifier(){
return this.identifier;
}
public void setIdentifier(String identifier){
this.identifier = identifier;
}
}
The synchronized block synchronizes calls that are using the same instance. As each call to your service will create a new instance of SampleRequestBody there is practically no synchronization.
You could synchronize on the identifier property of you request object by storing the strings in some kind of local cache in order to get the same string instance for the same identifier again:
// you should not actually use String.intern() here but some local cache
synchronized(sampleRequestBody.getIdentifier().intern()) {
//Do some process with the sample request body
}
The above example uses String.intern() just for the sake of simplicity. In a real live application using String.intern() should be avoided as it will create objects in memory that are not covered by the Java GC. That is: use a local cache instead.
You should additionally keep in mind that this synchronization will only work on a per JVM basis. That is, if you got two servers in a load balanced setup, this will not work as desired.
And one last thought: You should really rethink the need of synchronization here. Use it only if there is no other possibility to solve your requirements.
If you need a tool to synchronization by the value of the object which you can use in Spring Framework then I can suggest you XSync library.
All that you need is to add the XSync bean in your configuration:
#Configuration
public class Config{
#Bean
public XSync<String> xSync(){
return new XSync<>();
}
}
and now you can use it in your controller:
#Autowired
private XSync<String> xSync;
#PostMapping(value = "testingSync", headers = {"Content-type=application/json"})
public void testingSync(#RequestBody SampleRequestBody sampleRequestBody) {
xSync.execute(sampleRequestBody.getIdentifier(), () -> {
//Do some process with the sample request
});
}
Implementation of this library based on the WeakReference instead of String.intern.
Using String.intern here is a bad idea, you can get a deadlock and memory leaks.

How will multi-threading affect the Easy Rules engine?

I am looking for a rule engine for my web application and I found Easy Rules. However, in the FAQ section, it states that the limitation on thread safety.
Is a Web Container considered as a multi-threaded environment? For HTTP request is probably processed by a worker thread created by the application server.
How does thread safety comes into place?
How to deal with thread safety?
If you run Easy Rules in a multi-threaded environment, you should take into account the following considerations:
Easy Rules engine holds a set of rules, it is not thread safe.
By design, rules in Easy Rules encapsulate the business object model they operate on, so they are not thread safe neither.
Do not try to make everything synchronized or locked down!
Easy Rules engine is a very lightweight object and you can create an instance per thread, this is by far the easiest way to avoid thread safety problems
http://www.easyrules.org/get-involved/faq.html
http://www.easyrules.org/tutorials/shop-tutorial.html
Based on this example, how will multi-threading affects the rule engine?
public class AgeRule extends BasicRule {
private static final int ADULT_AGE = 18;
private Person person;
public AgeRule(Person person) {
super("AgeRule",
"Check if person's age is > 18 and
marks the person as adult", 1);
this.person = person;
}
#Override
public boolean evaluate() {
return person.getAge() > ADULT_AGE;
}
#Override
public void execute() {
person.setAdult(true);
System.out.printf("Person %s has been marked as adult",
person.getName());
}
}
public class AlcoholRule extends BasicRule {
private Person person;
public AlcoholRule(Person person) {
super("AlcoholRule",
"Children are not allowed to buy alcohol",
2);
this.person = person;
}
#Condition
public boolean evaluate() {
return !person.isAdult();
}
#Action
public void execute(){
System.out.printf("Shop: Sorry %s,
you are not allowed to buy alcohol",
person.getName());
}
}
public class Launcher {
public void someMethod() {
//create a person instance
Person tom = new Person("Tom", 14);
System.out.println("Tom:
Hi! can I have some Vodka please?");
//create a rules engine
RulesEngine rulesEngine = aNewRulesEngine()
.named("shop rules engine")
.build();
//register rules
rulesEngine.registerRule(new AgeRule(tom));
rulesEngine.registerRule(new AlcoholRule(tom));
//fire rules
rulesEngine.fireRules();
}
}
Yes, a web application is multithreaded. As you expect, there is a pool of threads maintained by the server. When the serversocket gets an incoming request on the port it's listening to, it delegates the request to a thread from the pool.Typically the request is executed on that thread until the response is completed.
If you try to create a single rules engine and let multiple threads access it, then either
the rules engine data is corrupted as a result of being manipulated by multiple threads (because data structures not meant to be threadsafe can perform operations in multiple steps that can be interfered with by other threads as they're accessing and changing the same data), or
you use locking to make sure only one thread at a time can use the rules engine, avoiding having your shared object get corrupted, but in the process creating a bottleneck. All of your requests will need to wait for the rules engine to be available and only one thread at a time can make progress.
It's much better to give each request its own copy of the rules engine, so it doesn't get corrupted and there is no need for locking. The ideal situation for threads is for each to be able to execute independently without needing to contend for shared resources.

Reusing JAX RS Client in multi-threaded environment (with resteasy)

According to the documentation,
"Clients are heavy-weight objects that manage the client-side
communication infrastructure. Initialization as well as disposal of a
Client instance may be a rather expensive operation. It is therefore
advised to construct only a small number of Client instances in the
application. "
Ok, I'm trying to cache Client itself and WebTarget instances in a static variable, the someMethod() is invoked in multi-threaded environment:
private static Client client = ClientBuilder.newClient();
private static WebTarget webTarget = client.target("someBaseUrl");
...
public static String someMethod(String arg1, String arg2)
{
WebTarget target = entrTarget.queryParam("arg1", arg1).queryParam("arg2", arg2);
Response response = target.request().get();
final String result = response.readEntity(String.class);
response.close();
return result;
}
But sometimes (not always) I'm get an exception:
Invalid use of BasicClientConnManager: connection still allocated.
Make sure to release the connection before allocating another one.
How can Client/WebTarget be reused/cached correctly? Is it possible with JAX RS Client API? Or I have to use some framework-specific features (resteasy/jersey) Could you provide some example or documentation?
Your implementation is not thread-safe. When two threads access someMethod at the same time they are sharing the same Client and one will try to make a second request while the first one is not finished.
You have two choices:
Synchronize the access to the Client and WebTarget manually.
Let the container manage concurrency by annotating the enclosing type with #javax.ejb.Singleton which guarantees thread safety. (see chapter 4.8.5 of the EJB specification)
If someMethod in a container managed environment I would use the second approach.
Since this issue is still open at the time of writing (version 3.0.X) RESTEASY: deprecated Apache classes cleanup
You can go deeper to use the newer, non-deprecated classes instead to create you resteasy client. You will also have more control over how you want the pool to be etc.
Here is what I did:
// This will create a threadsafe JAX-RS client using pooled connections.
// Per default this implementation will create no more than than 2
// concurrent connections per given route and no more 20 connections in
// total. (see javadoc of PoolingHttpClientConnectionManager)
PoolingHttpClientConnectionManager cm =
new PoolingHttpClientConnectionManager();
CloseableHttpClient closeableHttpClient =
HttpClientBuilder.create().setConnectionManager(cm).build();
ApacheHttpClient4Engine engine =
new ApacheHttpClient4Engine(closeableHttpClient);
return new ResteasyClientBuilder().httpEngine(engine).build();
Also make sure you release the connection after making a call. Calling response.close() will do that for you so probably put that in a finally block.
First, do not reuse WebTarget. For simplicity, you can always create new WebTarget.
Second, if you're using Resteasy, you can add provided dependency for Resteasy client to your project. Example in Gradle:
provided 'org.jboss.resteasy:resteasy-client:3.0.14.Final'
Then, you can create your connection like this:
ResteasyClientBuilder builder = new ResteasyClientBuilder();
builder.connectionPoolSize(200);
There is no need to set maxPooledPerRoute, this is set automatically by RestEasy (can be found in RestEasyClientBuilder class source code).
When you set connectionPoolSize, you will no longer get error when Client is reused and you can happily re-use them all across the application. I've tried this solution on many projects and it actually works well. But when you deploy your application to a non-resteasy container (like Glassfish), your code won't work and you will have to use ClientBuilder class again.
The documentation is unfortunately not very clear about what can and can't be reused safely. When in doubt reuse nothing. However, if you're determined to minimize overhead you can safely reuse most objects depending on the methods called.
Starting with your code, here's some comments about what's happening:
// (1) Store an instance of Client with its own configuration
private static Client client = ClientBuilder.newClient();
// (2) Store an instance of WebTarget with its own configuration (inherited from client)
private static WebTarget webTarget = client.target("someBaseUrl");
...
public static String someMethod(String arg1, String arg2)
{
// (3) New instance of WebTarget (copy entrTarget config) with "arg1" param
// (4) New instance of WebTarget (copy anonymous config) with "arg2" param
WebTarget target = entrTarget.queryParam("arg1", arg1).queryParam("arg2", arg2);
// (5) New instance of Invocation.Builder (copy target config)
// (6) Invoke GET request with stored configuration
Response response = target.request().get();
final String result = response.readEntity(String.class);
response.close();
return result;
}
I commented on the code as-is but I'm guessing (3) should've referenced the static webTarget field.
A lot of objects are getting created here. Every time an object is created there's a new instance with its own copy of the configuration (so it won't affect its predecessors). In this particular case there should be no race conditions, but there are definitely ways in which this could go wrong.
If on or before (3) you had done something like this (assuming these are legitimate properties):
WebTarget target = webTarget.property("foo", fooProperty).queryParam("arg1", arg1);
Then you would be altering the configuration of the static webTarget field and that could cause a race condition. There are many ways to alter the configuration from the static fields so you either need to guard them carefully or just not have them at all.
Also, be aware that pretty much every object that spawns from the original client will have a reference to it for the purpose of determining if the httpEngine has been closed. So unless you're trying to gracefully shutdown your application it's likely never a good idea to close the client.
And I found out all of this by digging through the source code because there's really no good reference.

Do I need to do anything special to re-init org.apache.http.client.HttpClient

I have some code:
public class Foo {
private HttpClient httpClient;
public Foo() {
httpClient = new DefaultHttpClient();
}
}
While chatting with a co-worker (one with a higher level of experience than myself), it came up as a concern that if I create multiple foo()s, that their httpClients might all be impacted by one httpClient's actions. Our concern specifically is Cookies.
If I have code like:
public class Bar {
public static void main(String[] args) {
Foo a = new Foo();
Foo b = new Foo();
a.executeHttpStuff();
}
}
...and executeHttpStuff() utilizes the httpClient, and cookies are added to it, will those cookies be present in any calls made on b?
My hunch is 'no'.
My co-worker's hunch is 'possibly'.
The JavaDoc is not terribly telling.
Do any of you guys know?
HttpClient doesn't shares cookies between instances (via static).
So your hunch is right.
You can try it yourself, sniffing traffic from two different instances of client to the same server (via tcpmon e.g.).
Per the following documentation page:
http://hc.apache.org/httpclient-3.x/performance.html
"HttpClient is fully thread-safe when used with a thread-safe connection manager such as MultiThreadedHttpConnectionManager"
The javadoc being at:
http://hc.apache.org/httpclient-3.x/apidocs/org/apache/commons/httpclient/MultiThreadedHttpConnectionManager.html
The answer is no. Except you take care and have a CookieStore.
See: https://hc.apache.org/httpcomponents-client-ga/tutorial/html/statemgmt.html
Have fun.

Does GWT RequestFactory support implementation of optimistic concurrency control?

In a GWT app I present items that can be edited by users. Loading and saving the items is perfomed by using the GWT request factory. What I now want to achive is if two users concurrently edit an item that the user that saves first wins in the fashion of optimistic concurrency control. Meaning that when the second user saves his changes the request factory backend recognizes that the version or presence of the item stored in the backend has changed since it has been transfered to the client and the request factory/backend then somehow prevents the items from being updated/saved.
I tried to implement this in the service method that is used to save the items but this will not work because request factory hands in the items just retrieved from the backend with applied user's changes meaning the versions of these items are the current versions from the backend and a comparison pointless.
Are there any hooks in the request factory processing I coud leverage to achieve the requested behaviour? Any other ideas? Or do I have to use GWT-RPC instead...
No: http://code.google.com/p/google-web-toolkit/issues/detail?id=6046
Until the proposed API is implemented (EntityLocator, in comment #1, but it's not clear to me how the version info could be reconstructed from its serialized form), you'll have to somehow send the version back to the server.
As I said in the issue, this cannot be done by simply making the version property available in the proxy and setting it; but you could add another property: getting it would always return null (or similar nonexistent value), so that setting it on the client-side to the value of the "true" version property would always produce a change, which guaranties the value will be sent to the server as part of the "property diff"; and on the server-side, you could handle things either in the setter (when RequestFactory applies the "property diff" and calls the setter, if the value is different from the "true" version, then throw an exception) or in the service methods (compare the version sent from the client –which you'd get from a different getter than the one mapped on the client, as that one must always return null– to the "true" version of the object, and raise an error if they don't match).
Something like:
#ProxyFor(MyEntity.class)
interface MyEntityProxy extends EntityProxy {
String getServerVersion();
String getClientVersion();
void setClientVersion(String clientVersion);
…
}
#Entity
class MyEntity {
private String clientVersion;
#Version private String serverVersion;
public String getServerVersion() { return serverVersion; }
public String getClientVersion() { return null; }
public void setClientVersion(String clientVersion) {
this.clientVersion = clientVersion;
}
public void checkVersion() {
if (Objects.equal(serverVersion, clientVersion)) {
throw new OptimisticConcurrencyException();
}
}
}
Note that I haven't tested this, this is pure theory.
We came up with another workaround for optimistic locking in our app. Since the version can't be passed with the proxy itself (as Thomas explained) we are passing it via HTTP GET parameter to the request factory.
On the client:
MyRequestFactory factory = GWT.create( MyRequestFactory.class );
RequestTransport transport = new DefaultRequestTransport() {
#Override
public String getRequestUrl() {
return super.getRequestUrl() + "?version=" + getMyVersion();
}
};
factory.initialize(new SimpleEventBus(), transport);
On the server we create a ServiceLayerDecorator and read version from the RequestFactoryServlet.getThreadLocalRequest():
public static class MyServiceLayerDecorator extends ServiceLayerDecorator {
#Override
public final <T> T loadDomainObject(final Class<T> clazz, final Object domainId) {
HttpServletRequest threadLocalRequest = RequestFactoryServlet.getThreadLocalRequest();
String clientVersion = threadLocalRequest.getParameter("version") );
T domainObject = super.loadDomainObject(clazz, domainId);
String serverVersion = ((HasVersion)domainObject).getVersion();
if ( versionMismatch(serverVersion, clientVersion) )
report("Version error!");
return domainObject;
}
}
The advantage is that loadDomainObject() is called before any changes are applied to the domain object by RF.
In our case we're just tracking one entity so we're using one version but approach can be extended to multiple entities.

Categories