I'm constructing an AsyncHttpClient
like this:
public AsyncHttpClient getAsyncHttpClient() {
AsyncHttpClientConfig config = new AsyncHttpClientConfig.Builder()
.setProxyServer(makeProxyServer())
.setRequestTimeoutInMs((int) Duration.create(ASYNC_HTTP_REQUEST_TIMEOUT_MIN, TimeUnit.MINUTES).toMillis())
.build();
return new AsyncHttpClient(new NettyAsyncHttpProvider(config), config);
}
This gets called once at startup, and then the return value is passed around and used in various places. makeProxyServer()
is my own function to take my proxy settings an return a ProxyServer
object. What I need to do is be able to change the proxy server settings and then recreate the AsyncHttpClient
object. But, I don't know how to shut it down cleanly. A bit of searching on leads me to believe that close()
isn't gracefull. I'm worried about spinning up a whole new executor and set of threads every time the proxy settings change. This won't be often, but my application is very long-running.
I know I can use RequestBuilder.setProxyServer()
for each request, but I'd like to have it set in one spot so that all callers of my asyncHttpClient
instance obey the system-wide proxy settings without each developer having to remember to do it.
What's the right way to re-configure or teardown and rebuild a Netty
-based AsyncHttpClient
?
The problem with using AsyncHttpClient.close()
is that it shuts down the thread pool executor used by the provider, then there is no way to re-use the client without re-building it, because as per documentation, the executor instance cannot be reused once ts is shutdown. So, there is no way but re-build the client if you go that way (unless you implement your own ExecutorService that would have another shutdown logic, but it is a long way to go, IMHO).
However, from looking into the implementation of NettyAsyncHttpProvider
, I can see that it stores the reference to the given AsyncHttpClientConfig
instance and calls its getProxyServerSelector()
to get the proxy settings for every new NettyAsyncHttpProvider.execute(Request...)
invocation (i.e. for every request executed by AsyncHttpClient
).
Then, if we could make the getProxyServerSelector()
return the configurable instance of ProxyServerSelector
, that would do the thing.
Unfortunately, AsyncHttpClientConfig
is designed to be a read-only container, instantiated by AsyncHttpClientConfig.Builder
.
To overcome this limitation, we would have to hack it, using, say, "wrap/delegate" approach:
Create a new class, derived from AsyncHttpClientConfig
. The class should wrap the given separate AsyncHttpClientConfig
instance and implement the delegation of the AsyncHttpClientConfig
getters to that instance.
To be able to return the proxy selector we want at any given point of time, we make this setting mutable in a this wrapper class and expose the setter for it.
Example:
public class MyAsyncHttpClientConfig extends AsyncHttpClientConfig
{
private final AsyncHttpClientConfig config;
private ProxyServerSelector proxyServerSelector;
public MyAsyncHttpClientConfig(AsyncHttpClientConfig config)
{
this.config = config;
}
@Override
public int getMaxTotalConnections() { return config.maxTotalConnections; }
@Override
public int getMaxConnectionPerHost() { return config.maxConnectionPerHost; }
// delegate the others but getProxyServerSelector()
...
@Override
public ProxyServerSelector getProxyServerSelector()
{
return proxyServerSelector == null
? config.getProxyServerSelector()
: proxyServerSelector;
}
public void setProxyServerSelector(ProxyServerSelector proxyServerSelector)
{
this.proxyServerSelector = proxyServerSelector;
}
}
AsyncHttpClient
config instance with our new wrapper and use it to configure the AsyncHttpClient
:Example:
MyAsyncHttpClientConfig myConfig = new MyAsyncHttpClientConfig(config);
return new AsyncHttpClient(new NettyAsyncHttpProvider(myConfig), myConfig);
myConfig.setProxyServerSelector(newSelector)
, the new request executed by NettyAsyncHttpProvider
instance in your client will use the new proxy server settings. A few hints/warnings:
This approach relies on the internal implementation of NettyAsyncHttpProvider
; therefore make your own judgement on maintainability, future Netty libraries versions upgrade strategy etc. You could always look at the Netty source code before upgrading to the new version. At the current point, I personally think it is unlikely to change too much to invalidate this implementation.
You could get ProxyServerSelector
for ProxyServer
by using com.ning.http.util.ProxyUtils.createProxyServerSelector(proxyServer)
- that's exactly what AsyncHttpClientConfig.Builder
does.
The given example has no synchronization logic for accessing proxyServerSelector
; you may want to add some as your application logic needs.
Maybe it is a good idea to submit a feature request for AsyncHttpClient
to be able to setup a "configuration factory" for the AsyncHttpProvider
so all these complications would vanish :-)
You should be holding a RequestHandle instance for all your unfinished requests. When you want to shut down, you can loop through and call isFinished() on all of them until they are all done. Then you know you can safely close it and no pending requests will be killed.
Once it's closed, just build a new one. Don't try to reuse the existing one. If you have references to it around, change those to reference a Factory that will return the current one.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With