I'm using http-client 4.3.x in my project. In order to close "idled" connections, I started a thread to monitor the connection pool and try to close connections which have been idled for 30s every one second.
The connectionManager:
PoolingHttpClientConnectionManager connectionManager =
new PoolingHttpClientConnectionManager(registry);
The thread to monitor it and close idled connections:
class ClosingIdleConnectionThread extends Thread {
private final PoolingHttpClientConnectionManager connectionManager;
private final int timeout;
public ClosingIdleConnectionThread(PoolingHttpClientConnectionManager connectionManager, int timeout) {
this.connectionManager = connectionManager;
this.timeout = timeout;
}
#Override
public void run() {
while (!Thread.currentThread().isInterrupted()) {
connectionManager.closeIdleConnections(timeout, TimeUnit.MILLISECONDS);
connectionManager.closeExpiredConnections();
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
return;
}
}
}
}
But now I have two problems:
Actually, I'm not sure what does "idled" connection means
I have to write some tests to make sure my code is working, but I don't know how to test it
Thanks for your help ~
(1) A persistent connection is considered idle if it has not been leased from the pool. Idle for 5 seconds = has not been leased for 5 seconds.
(2) This is a tough one. I see two options here
Use PowerMock, instrument SocketImpl abstract class and 'spy' on its #close method. Disclaimer: I have not tried it. It's just an idea and it may not work.
Use Mockito or similar toolkit and spy on PlainConnectionSocketFactory instance instead. Register Mockito enhanced implementation with the connection pool manager. Count how many times #connectSocket method has been called. If the method has been invoked upon new connection lease after a long period of inactivity, that basically means one of two things: the pool was either empty or idle connections were not in a re-usable state. It is not a perfect test, but it could be easier to implement given it does not require classloader magic of PowerMock.
Related
Is there a way to close java.net.http.HttpClient to instantly release resources held by it?
Internally it holds a selector, a connection pool and an Executor (when default one is used). However it does not implement Closeable/AutoCloseable.
I had similar problem when I was redeploying a war file into Tomcat. War application had an HttpClient, that was running scheduled jobs issuing http requests and processing results.
I was seeing warnings from Tomcat when redeploying war file quite often on dev enrionment about hanging threads that may cause memory leaks. The stack trace was pointing to HttpClient threads. After several attempts I solved this problem in this way:
HttpClient is created only when necessary to execute the job. It is not created as a field of a class or serivec, only as a local variable inside the scheduled method.
HttpClient is created using builder and populated with a ThreadPool Executor, thus I keep the link to Executor and have control on it.
ExecutorService executor = Executors.newSingleThreadExecutor();
HttpClient client = HttpClient.newBuilder().followRedirects(Redirect.ALWAYS).connectTimeout(Duration.ofSeconds(5)).executor(executor).build();
When job is done in try-catch block, finally section has these two lines that: close the thread pool explicitly and set null to the httpClient local variable:
executor.shutdownNow();
client = null;
System.gc();
Notes, have short connection timeout to limit the time of execution. keep number of threads small. I use threadPool of 1 thread.
After all these changes warnings about memory leaks disappeared from Tomcat logs.
As you've noticed, java.net.http.HttpClient does not implement Closeable or AutoCloseable. So I can think of only 2 options, but neither of them are really bulletproof or even good:
You could eliminate every strong reference to the HttpClient that your program is holding and request a garbage collection. However there's a real risk that something beyond your direct control is holding onto it or one of its components. Any remaining strong references would prevent the referenced object, and any objects it holds a strong reference to, from being garbage collected. Nevertheless, this is arguably the more idiomatic option than the alternative.
I also found another option.
final class HttpClientImpl extends HttpClient implements Trackable {
...
// Called from the SelectorManager thread, just before exiting.
// Clears the HTTP/1.1 and HTTP/2 cache, ensuring that the connections
// that may be still lingering there are properly closed (and their
// possibly still opened SocketChannel released).
private void stop() {
// Clears HTTP/1.1 cache and close its connections
connections.stop();
// Clears HTTP/2 cache and close its connections.
client2.stop();
}
...
}
I wouldn't feel comfortable using this unless I had no other choice. Your reference is probably of type HttpClient, so you'd need to cast it to HttpClientImpl. It's bad to rely on the concrete implementation, which could change in future releases, rather than the HttpClient interface. The method is also private. There are ways around this but it's messy.
In Java 11, each HttpClient spawn a daemon thread called selmgr which supposed to take care of in fly requests. This thread will be closed when there is no reference to the HttpClient in the code. However, in my experience, it is not reliable. Especially, when you use asynchronous methods with future timeouts.
Here is a piece of code I wrote using reflection to reliably close the HttpClient
static void shutDownHttpClient(HttpClient httpClient)
{
ThreadPoolExecutor threadPoolExecutor = (ThreadPoolExecutor) httpClient.executor().get();
threadPoolExecutor.shutdown();
try {
Field implField = httpClient.getClass().getDeclaredField("impl");
implField.setAccessible(true);
Object implObj = implField.get(httpClient);
Field selmgrField = implObj.getClass().getDeclaredField("selmgr");
selmgrField.setAccessible(true);
Object selmgrObj = selmgrField.get(implObj);
Method shutDownMethod = selmgrObj.getClass().getDeclaredMethod("shutdown");
shutDownMethod.setAccessible(true);
shutDownMethod.invoke(selmgrObj);
}
catch (Exception e) {
System.out.println("exception " + e.getMessage());
e.printStackTrace();
}
}
As you can see, this is implementation-dependent and may not works with future Java versions. It is tested with Java 11 and Java 12.
Also, you need to add --add-opens java.net.http/jdk.internal.net.http=ALL-UNNAMED to your java command.
Obviously HttpClient is designed to be self managed. So it responsible to maintain connection pool, cache ttl by itself.
In HttpClientCode We could find the following code:
if (!owner.isReferenced()) {
Log.logTrace("{0}: {1}",
getName(),
"HttpClient no longer referenced. Exiting...");
return;
}
this is a graceful way to exit from SelectorManager loop and clean all resources.
#Override
public void run() {
...
try {
while (!Thread.currentThread().isInterrupted()) {
...
if (!owner.isReferenced()) {
Log.logTrace("{0}: {1}",
getName(),
"HttpClient no longer referenced. Exiting...");
return;
}
...
}
} catch (Throwable e) {
...
} finally {
...
shutdown();
}
}
final boolean isReferenced() {
HttpClient facade = facade();
return facade != null || referenceCount() > 0;
}
So when your HttpClient object will not be referenced, then it will clean all resources.
UPD: also you should tune your requests by passing timeouts
If it is just to gracefully close HttpClient at the end of the application lifecycle, System.exit(0) shall just work.
public static void main(String[] args) {
...
System.exit(0);
}
I think it sends a interrupt signal to all threads in the JVM and HttpClient selmgr daemon does pick this up and shutdown itself.
final class HttpClientImpl extends HttpClient implements Trackable {
...
// Main loop for this client's selector
private final static class SelectorManager extends Thread {
...
#Override
public void run() {
...
try {
...
while (!Thread.currentThread().isInterrupted()) {...}
} catch (Throwable e) {...}
finally {
...
shutdown();
}
This is a bit late, but I just want to highlight that the comment from Jacob G. (Dec 25, 2018) contained a solution that worked for me:
Creating the httpClient:
myExecutorService = Executors.newCachedThreadPool();
HttpClient myHttpClient = HttpClient.newBuilder()
.executor(executor)
....
.build();
Shutting down:
myExecutorService.shutDown();
Instead of having to wait for 90 seconds for the client to drop its connection, it happened "instantly".
I have a Java ThreadPool that is initialized as follows:
ThreadFactory tFactory = new DatabaseWorkerThreadFactory();
final ExecutorService dbService = new ThreadPoolExecutor(1, 5, 10L, TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(10), tFactory);
Then execute Runnable Task on that threadpool like this
executorService.execute(new RunnableDbInsertTask(netData));
to get those inserts to be async from the rest of my code.
As i'm using ActiveJDBC as an ActiveRecord implementation, I need each worker to have an active Connection, which I do having this code at the start of the RunnableDbInsertTask's run() method:
if(!Base.hasConnection())
Base.open(params);
So when the ThreadPoolExecutor is used, each new spawned Thread that gets tasks, will have a unique connection, and will reuse it for every connection.
Now I want the thread amount to fallback to the minimum (1), as specified in the ThreadPoolExecutor's constructor, when there are no jobs to be done.
For this to happen correctly, I need that when a Thread is automatically finished by the ThreadPoolExecutor because of inactivity, it auto-finishes it's connection calling ActiveJDBC's Base.close() method
As a solution I tried overriding DatabaseWorker.interrupt() method, but that didn't worked.
Any help appreciated. Thanks!
I think you should not rely on the executor to open and close your connections. Instead of opening direct connections to the DB, you need to use a pool of connections and open a connection from the pool. Also, at the end of your run() method, you must close the connection. Since these are polled connections, a real JDBC connection will simply go back to the pool instead of closing. Here is the preudo-code:
public void run() {
try {
Base.open("myConnectionJNDIName");
//do some real work here
} finally {
Base.close();//always close connection
}
}
This way you have more control over thread count vs connection count.
I have a main thread that runs periodically. It opens a connection, with setAutoCommit(false), and is passed as reference to few child threads to do various database read/write operations. A reasonably good number of operations are performed in the child threads. After all the child threads had completed their db operations, the main thread commits the transaction with the opened connection. Kindly note that I run the threads inside the ExecutorService. My question, is it advisable to share a connection across threads? If "yes" see if the below code is rightly implementing it. If "no", what are other way to perform a transaction in multi-threaded scenario? comments/advise/a-new-idea are welcome. pseudo code...
Connection con = getPrimaryDatabaseConnection();
// let me decide whether to commit or rollback
con.setAutoCommit(false);
ExecutorService executorService = getExecutor();
// connection is sent as param to the class constructor/set-method
// the jobs uses the provided connection to do the db operation
Callable jobs[] = getJobs(con);
List futures = new ArrayList();
// note: generics are not mentioned just to keep this simple
for(Callable job:jobs) {
futures.add(executorService.submit(job));
}
executorService.shutdown();
// wait till the jobs complete
while (!executorService.isTerminated()) {
;
}
List result = ...;
for (Future future : futures) {
try {
results.add(future.get());
} catch (InterruptedException e) {
try {
// a jobs has failed, we will rollback the transaction and throw exception
connection.rollback();
result = null;
throw SomeException();
} catch(Exception e) {
// exception
} finally {
try {
connection.close();
} catch(Exception e) {//nothing to do}
}
}
}
// all the jobs completed successfully!
try {
// some other checks
connection.commit();
return results;
} finally {
try {
connection.close();
} catch(Exception e){//nothing to do}
}
I wouldn't recommend you to share connection between threads, as operations with connection is quite slow and overall performance of you application may harm.
I would rather suggest you to use Apache Connections Pool and provide separate connection to each thread.
You could create a proxy class that holds the JDBC connection and gives synchronized access
to it. The threads should never directly access the connection.
Depending on the use and the operations you provide you could use synchronized methods, or lock on objects if the proxy needs to be locked till he leaves a certain state.
For those not familiar with the proxy design pattern. Here the wiki article. The basic idea is that the proxy instance hides another object, but offers the same functionality.
In this case, consider creating a separate connection for each worker. If any one worker fails, roll back all the connections. If all pass, commit all connections.
If you're going to have hundreds of workers, then you'll need to provide synchronized access to the Connection objects, or use a connection pool as #mike and #NKukhar suggested.
This question has no doubt been asked in various forms in the past, but not so much for a specific scenario.
What is the most correct way to stop a Thread that is blocking while waiting to receive a network message over UDP.
For example, say I have the following Thread:
public class ClientDiscoveryEngine extends Thread {
private final int PORT;
public ClientDiscoveryEngine(final int portNumber) {
PORT = portNumber;
}
#Override
public void run() {
try {
socket = new DatagramSocket(RECEIVE_PORT);
while (true) {
final byte[] data = new byte[256];
final DatagramPacket packet = new DatagramPacket(data, data.length);
socket.receive(packet);
}
} catch (SocketException e) {
// do stuff 1
} catch (IOException e) {
// do stuff 2
}
}
}
Now, would the more correct way be using the interrupt() method? For example adding the following method:
#Override
public void interrupt() {
super.interrupt();
// flip some state?
}
My only concern is, is socket.receive() not a non-interruptable blocking method? The one way that I have thought of would be to implement the interrupt method as above, in that method call socket.close() and then cater for it in the run method in the catch for the SocketException. Or maybe instead of while(true) use some state that gets flipped in the interrupt method. Is this the best way? Or is there a more elegant way?
Thanks
The receive method doesn't seem to be interruptible. You could close the socket: the javadoc says:
Any thread currently blocked in receive(java.net.DatagramPacket) upon
this socket will throw a SocketException
You could also use setSoTimeout to make the receive method block only for a small amount of time. After the method has returned, your thread can check if it has been interrupted, and retry to receive again for this small amount of time.
Read this answer Interrupting a thread that waits on a blocking action?
To stop a thread, you should not user neither interrupt nor stop in java. The best way, as you suggested by the end of your question, is to have the loop inside the main method controlled by a flag that you can rise as needed.
Here is an old link about this :
http://download.oracle.com/javase/1.4.2/docs/guide/misc/threadPrimitiveDeprecation.html
Other ways of stopping a thread are deprecated and don't provide as much control as this one. Also, this may have changed a bit with executor services, I didn't have time to learn much about it yet.
Also, if you want to avoid your thread to be blocked in some IO state, waiting for a socket, you should give your socket a connection and reading time out (method setSoTimeout).
Regards,
Stéphane
This is one of the easier ones. If it's blocked on a UDP socket, send the socket a UDP message that instructs the receiving thread to 'stop'.
Rgds,
Martin
I'm running into an issue when i try to use the HttpClient connecting
to a url. The http connection is taking a longer time to timeout, even after i set
a connection timeoout.
int timeoutConnection = 5000;
HttpConnectionParams.setConnectionTimeout(httpParameters, timeoutConnection);
int timeoutSocket = 5000;
HttpConnectionParams.setSoTimeout(httpParameters, timeoutSocket);
It works perfect most of the time. However, every once in while, the http connection runs for ever and ignore the setconnectiontimeout, especailly when the phone is connected to wifi, and the phone was idling.
So after the phone is idling, the first time i try to connect, the http connection ignores the setconnectiontimeout and runs forever, after i cancel it and try again, it works like charm everytime. But that one time that doesn't work it creates a threadtimeout error, i tried using a different thread, it works, but i know that the thread is running for long time.
I understand that the wifi goes to sleep on idle, but i dont understand why its ignoring the setconnectiontimeout.
Anyone can help, id really appreciated.
Not sure if this helps you, however I think it's worth sharing here. While playing with the timeout stuff I found there is a third timeout type you can assign:
// the timeout until a connection is established
private static final int CONNECTION_TIMEOUT = 5000; /* 5 seconds */
// the timeout for waiting for data
private static final int SOCKET_TIMEOUT = 5000; /* 5 seconds */
// ----------- this is the one I am talking about:
// the timeout until a ManagedClientConnection is got
// from ClientConnectionRequest
private static final long MCC_TIMEOUT = 5000; /* 5 seconds */
...
HttpGet httpGet = new HttpGet(url);
setTimeouts(httpGet.getParams());
...
private static void setTimeouts(HttpParams params) {
params.setIntParameter(CoreConnectionPNames.CONNECTION_TIMEOUT,
CONNECTION_TIMEOUT);
params.setIntParameter(CoreConnectionPNames.SO_TIMEOUT, SOCKET_TIMEOUT);
params.setLongParameter(ConnManagerPNames.TIMEOUT, MCC_TIMEOUT);
}
I've met the same problem, I guess maybe the Android doesn't support this parameter.
In my case i tested all three parameters for the ThreadSafeClientConnManager
params.setParameter( ConnManagerPNames.MAX_CONNECTIONS_PER_ROUTE, new ConnPerRouteBean(20) );
params.setIntParameter( ConnManagerPNames.MAX_TOTAL_CONNECTIONS, 200 );
params.setLongParameter( ConnManagerPNames.TIMEOUT, 10 );
ThreadSafeClientConnManager connmgr = new ThreadSafeClientConnManager( params );
The first and second worked fine, but the third didn't work as documented. No exception was thrown and the executing thread was blocked indefinitely when the DefaultHttpClient#execute() was executing.
see http://hc.apache.org/httpcomponents-client-ga/tutorial/html/connmgmt.html#d4e650
"...One can ensure the connection manager does not block indefinitely in the connection request operation by setting 'http.conn-manager.timeout' to a positive value. If the connection request cannot be serviced within the given time period ConnectionPoolTimeoutException will be thrown."
Thread t=new Thread()
{
public void run()
{
try
{
Thread.sleep(absolutetimeout);
httpclient.getConnectionManager().closeExpiredConnections();
httpclient.getConnectionManager().closeIdleConnections(absolutetimeout,TimeUnit.MILLISECONDS);
httpclient.getConnectionManager().shutdown();
log.debug("We shutdown the connection manager!");
}
catch(InterruptedException e)
{}
}
};
t.start();
HttpResponse res= httpclient.execute(httpget);
t.interrupt();
Is that along the lines of what you all are suggesting?
I'm not exactly sure how to cancel the execute once it has started, but this seemed to work for me. I'm not sure which of the three lines in the thread did the magic, or if it was some combination of all of them.
You could manage the timeouts yourself, this way you can be confident that no matter what state the connection gets in, unless you receive an acceptable response, that your timeout will fire and the http request will be aborted.
I've had similar issues with timeouts on android. To resolve it what I did was used the commands to not let the phone idle while I was attempting to establish a connection and during any reads or writes to the connection. Its probably worth a shot in this case as well.
Although I haven't seen this on the Android platform, I've seen similar things on other platforms and the solution in these cases is to manage the timeout yourself. Kick off another thread (the timeout thread) when your make your request. The timeout thread counts down the requisite time. If the timeout expires before you receive any data, the timeout thread cancels the original request and you retry with a new request. Harder to code, but at least you know it will work.
From you snippet it's not ultimately clear if you set the timeouts before calling HttpClient.executeMethod(..). So this is my guess.
Well, if you idle/multitask to another application, then your thread that is running might be stopped and destroyed. Maybe you should put the connection code inside a Service instead?:
http://developer.android.com/reference/android/os/AsyncTask.html
http://developer.android.com/reference/android/app/IntentService.html
How are you making the HTTP Connection? This looks like a threading issue. If you are using a background thread, then the thread may be killed along with any timeout registered. The fact that it works the next time tells me that your code will work, if you make the call in a android component and manage the WAKE_LOCK on it yourself. Anyways please post more information about the calling mechanism?
The problem might be in the Apache HTTP Client. See HTTPCLIENT-1098.
Fixed in 4.1.2.
The timeout exception tries to reverse DNS the IP, for logging purposes. This takes an additional time until the exception is actually fired.