I am using a restlet 2.1 client sever based architecture, my client times out within 1 minute after sending the request. and I get the following exception :
Internal Connector Error (1002) - The calling thread timed out while waiting for a response to unblock it.
at org.restlet.resource.ClientResource$1.invoke(ClientResource.java:1663)
at com.sun.proxy.$Proxy17.getTaskList(Unknown Source)....
My code is as below :
import org.restlet.resource.ClientResource;
ClientResource cr = new ClientResource(uri);
MyResource resource= cr.wrap(MyResource .class);
updateStatus = resource.updateData(Parameter);
i also tried this code :
Context context = new Context();
context.getParameters().add("socketTimeout", new String("180000"));
context.getParameters().add("socketConnectTimeoutMs", new String("180000"));
context.getParameters().add("idleTimeout", new String("180000"));
ClientResource cr = new ClientResource(context, url);
TasksResource resource = cr.wrap(TasksResource.class);
how should I configure my client resource to avoid timeout ?
The connection timeout for a Restlet client can be configured at the client connector level. If your call is within a component, you can get the client connector from it (class Client), otherwise you need to instantiate it. Configuring timeout can be done through its parameters (method getContext and then getParameters).
Parameters depend on the underlying connectors (HTTP client, ...).
The following links will help you to fix your issue:
Restlet HTTP Connection Pool
Restlet timeout
Hope it helps you,
Thierry
Related
I play the Jetty Websocket use example here :
https://github.com/jetty-project/embedded-jetty-websocket-examples (i use native-jetty-websocket-example)
I just move from websocketpp (C++) to Java Jetty Websocket and i just wonder is there any way for me to authen the connection before the connection move to the onWebSocketConnect event ?
Back in websocketpp i'll authenticate the connection via url (eg: ws://xxx/?key=123) when i will accept the connection or not. I can drop the connection before it "upgrade", and the client will result in connect failed
In Java i don't known how to do that, when the event come to onWebSocketConnect then the connection is etablished
You can set up Security Constraints for that path and configure the Jetty authentication mechanisms, see details of how to do that here https://www.eclipse.org/jetty/documentation/jetty-9/index.html#configuring-security.
You could also use the JettyWebSocketCreator to do some checks on the HTTP Request just before the connection upgrades to WebSocket. Instead of this line https://github.com/jetty-project/embedded-jetty-websocket-examples/blob/564c40b56413905cadeb500ade40d53e578ea990/native-jetty-websocket-example/src/main/java/org/eclipse/jetty/demo/EventServer.java#L55
You can do something like:
wsContainer.addMapping("/events/*", (req, resp) ->
{
if (!Objects.equals(req.getParameterMap().get("key"), "123"))
{
resp.sendError(...);
return null;
}
return new EventSocket();
});
We need to set Eureka server URL at client application from startup code, but it seems there is no way how to do it.
We have a mechanism how to discover Eureka server on network by UDP multicast broadcasting. Server sends response back to the client with information about IP address and port where Eureka server is running. But we don't know how to set this URL in Eureka client application from code. It seems the only way how to set Eureka server URL is the property eureka.client.serviceUrl.defaultZone in application.property file.
// Server - start a new thread with UDP packet detection and reply mechanism
LocationService.listenAndReplyToEurekaClients(thisServerPort);
// Server - application start
SpringApplication.run(EurekaServerApplication.class, args);
// Client - send UDP packet and receive reply with Eureka server IP and port
Response response = LocationService.findEurekaServerAddress(5, 3, TimeUnit.SECONDS);
var hostProtocol = "http";
var eurekaUrl = new URL(
hostProtocol,
response.getEurekaAddress(),
response.getEurekaPort(),"").toString();
We would like to set this eurekaURL to the client before it starts registering to Eureka server.
In this case, we can do following things-
Extend EurekaClientConfigBean and override getEurekaServerServiceUrls method. Method returns a List of String which is nothing but list of all the URLS, of eureka instances. You need to set the URL here from your response which has IP and port.
Later create the discovery client using- DiscoveryClient(ApplicationInfoManager applicationInfoManager, EurekaClientConfig config). (Its going to be a Bean for sure).
That should work.
You can create ApplicationInfoManager as-
ApplicationInfoManager applicationInfoManager =
initializeApplicationInfoManager(webAppInstanceConfig);
Where WebAppInstanceConfig is-
class WebAppInstanceConfig extends MyDataCenterInstanceConfig {// Override all the needed properties from MyDataCenterInstanceConfig}
My Java application which resides in AWS private subnet connects to an http server via AWS Nat gateway. I am calling a POST request via HttpClient to the HTTP server. That request will take more than 10 minutes to complete. I have configured a socket time out and connection timeout of 1 hour as this this a background task . But the intermediate AWS NAT gateway will send back a RST packet after 300 secs [5 mins] and cause the connection to get resetted , there is no way i can increase the NAT gateway timeout. So i need to handle the problem from my application side.
My strategy is to use a TCP keep alive time which will send a packet say every 240 secs to keep the connection active. I have configured this
as below
CloseableHttpClient httpClient = HttpClients.createDefault()
HttpParams params = httpClient.getParams();
HttpConnectionParams.setConnectionTimeout(params, 3600000); //connection Timeout
HttpConnectionParams.setSoTimeout(params, 3600000); // Socket Time out
HttpConnectionParams.setSoKeepalive(params, true); //Enable Socket level keep alive time
and then call the post request via execute method
HttpPost post = new HttpPost("http://url");
HttpResponse response = httpClient.execute(post);
Since I am using a Linux system I have configured the server with following sysctl values:
sysctl -w net.ipv4.tcp_keepalive_time=240
sysctl -w net.ipv4.tcp_keepalive_intvl=240
sysctl -w net.ipv4.tcp_keepalive_probes=10
But while executing the program the keep alive is not enabled and connection fails as previous.
I have checked this with netstat -o option and as shown below keep alive is off
tcp 0 0 192.168.1.141:43770 public_ip:80 ESTABLISHED 18134/java off (0.00/0/0)
Is there any way i can set TCP keep alive from java code using httpclient . Also I can see HttpConnectionParams are deprecated. But I couldn't find any new class which can set keep alive
I have found a solution to the problem . Curious case is there is no way i can use some builder class in httpclient to pass socket keep alive . One method as i specified in the question is using HttpConnectionParams as below but this is not working and this class is now deprecated.
HttpParams params = httpClient.getParams();
HttpConnectionParams.setSoKeepalive(params, true);
So while checking apache http docs I can see that now connection parameters are passed to httpclient via RequestConfig class . Builders of this class provide solution to set connection_time_out and socket_time_out. But checking the socurce code of this I couldnt see an option to enable SocketKeepAlive which is what we want. So the only solution is directly creating a Socket using SocketBuilder class and pass that to the HttpClientBuilder.
Following is the working code
SocketConfig socketConfig = SocketConfig.custom().setSoKeepAlive(true).setSoTimeout(3600000).build(); //We need to set socket keep alive
RequestConfig requestConfig = RequestConfig.custom().setConnectTimeout(3600000).build();
CloseableHttpClient httpClient = HttpClientBuilder.create().setDefaultRequestConfig(requestConfig).
setDefaultSocketConfig(socketConfig).build();
HttpPost post = new HttpPost(url.toString());
HttpResponse response = httpClient.execute(post);
While executing above i can see that keep alive is properly set in the socket based on the sysctl values i set in linux kernel
tcp 0 0 localip:48314 public_ip:443 ESTABLISHED 14863/java keepalive (234.11/0/0)
If some one has a better solution to enable Socket Keep alive from Requestconfig class or any other high level builder class i am open to suggestions.
Keeping an HTTP connection open but inactive for a long period is a bad design choice. HTTP is a request-response protocol, with the implication that requests and responses are quick.
Holding a connection open holds resources. From the perspective of the server (and network firewalls and routers) a client that opens a connection and begins a request (A POST in your case) but does not send any bytes for a long period is indistinguishable from a client that will never send any more data, because it is faulty or malicious (conducting a DOS attack). The server (and network hardware) is right to conclude that the right thing to do is to shutdown the connection and reclaim the resources used for it. You are trying to fight against correct behaviour that occurs for good reasons. Even if you manage to workaround the TCP shutdown you will find other problems, such as HTTP server timeouts and database timeouts.
You should instead be reconsidered the design of communication between the two components. That is, this looks like an XY Problem. You might consider
Having the client wait until it has a complete upload to perform before starting the POST.
Splitting the uploads into smaller, more frequent uploads.
Use a protocol other than HTTP.
The approach above with Socket worked beautifully with a reset of tcp_keepalive_intvl value below the AWS Network Load Balancer timeout. Using both, reset the NLB tcp idle timeout that allowed java hour+ connections.
Sometimes, if the configuration is overwritten, the configuration does not take effect.My initial modification of setDefaultSocketConfig in buildClient didn't take effect.Because it is overwritten by getConnectionManager()
public CloseableHttpClient buildClient() throws Exception {
HttpClientBuilder builder = HttpClientBuilder.create()
.setDefaultSocketConfig(SocketConfig.custom().setSoKeepAlive(true).build()) // did not work
.setConnectionManager(getConnectionManager())
.setRetryHandler(getRequestRetryHandler())
.setConnectionReuseStrategy(getConnectionReuseStrategy())
.setDefaultConnectionConfig(getConnectionConfig())
.setDefaultRequestConfig(getRequestConfig())
.setDefaultHeaders(getDefaultHeaders())
.setDefaultCredentialsProvider(getDefaultCredentialsProvider())
.disableContentCompression() // gzip is not needed. Use lz4 when compress=1
.setDefaultCookieStore(cookieStoreProvider.getCookieStore(properties))
.disableRedirectHandling();
String clientName = properties != null ? properties.getClientName() : null;
if (!Utils.isNullOrEmptyString(clientName)) {
builder.setUserAgent(clientName);
}
return builder.build();
And then I move the config to getConnectionManager(),and it work.
private PoolingHttpClientConnectionManager getConnectionManager()
throws CertificateException, NoSuchAlgorithmException, KeyStoreException, KeyManagementException, IOException {
RegistryBuilder<ConnectionSocketFactory> registry = RegistryBuilder.<ConnectionSocketFactory>create()
.register("http", PlainConnectionSocketFactory.getSocketFactory());
if (properties.getSsl()) {
HostnameVerifier verifier = "strict".equals(properties.getSslMode()) ? SSLConnectionSocketFactory.getDefaultHostnameVerifier() : NoopHostnameVerifier.INSTANCE;
registry.register("https", new SSLConnectionSocketFactory(getSSLContext(), verifier));
}
//noinspection resource
PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(
registry.build(),
null,
null,
new IpVersionPriorityResolver(),
properties.getTimeToLiveMillis(),
TimeUnit.MILLISECONDS
);
connectionManager.setDefaultMaxPerRoute(properties.getDefaultMaxPerRoute());
connectionManager.setMaxTotal(properties.getMaxTotal());
connectionManager.setDefaultConnectionConfig(getConnectionConfig());
connectionManager.setDefaultSocketConfig(SocketConfig.custom().setSoKeepAlive(true).build());
return connectionManager;
}
My main goal is for pooling a httpclient in silent or somehow, and i'd like to call a method to give me a httpclient...because i think its too resource usage for every rest call add a new httpclient instance and set the things and so on...is there best practice for it?
If you refer to Apache HTTP client then you may follow the steps below:
Initiate Apache HTTP client only once, since it is thread safe you can safely reuse it. If you use Spring then it should be safe to store it in the Spring Context as a Bean. See following link for the thread-safety.
Despite the fact that HTTP client instance itself is not pooled (since you gonna use single instance of it) what you can do to increase the performance is configuring pooled connection manager on the HTTP client. See following link for the details.
(search for the 'Pooling connection manager' on that page) . The actual code should be something similar to the snippet bellow :
PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager();
// Increase max total connection to 200
cm.setMaxTotal(200);
// Increase default max connection per route to 20
cm.setDefaultMaxPerRoute(20);
// Increase max connections for localhost:80 to 50
HttpHost localhost = new HttpHost("localhost", 80);
cm.setMaxPerRoute(new HttpRoute(localhost), 50);
CloseableHttpClient httpClient = HttpClients.custom()
.setConnectionManager(cm)
.build();
Hope this helps .
How does one change the timeout on a Restlet Client get()?
All I've have been able to find is the obsolete SetConnectTimeout(). I tried context.getParameters().add ( "socketTimeout", "1000" ); with no success.
Basically, this is done by configuring the client connector (class org.restlet.Client):
client.context.getParameters().add ( "parameter", "value" );
I see two distinct contexts and thus two ways to get the client connector.
You are running your client calls inside a org.restlet.Component container
In this case, configure the common client connector hosted by the component:
Component c = new Component();
Client client = c.getClients().add(Protocol.HTTP);
client.getContext().getParameters().add ( "parameter", "value" );
You are not running your client calls inside a org.restlet.Component container
In this case, instantiate manually the client connector and set it to the ClientResource
Client client = new Client(new Context(), Protocol.HTTP);
client.getContext().getParameters().add ( "parameter", "value" );
ClientResource cr = new ClientResource("http://example.com");
cr.setNext(client);
To conclude with, the list of available parameters to be set depends on the kind of client connector you are using (internal connector, based on httpclient, etc)
You can have a look at this page http://restlet.com/learn/guide/2.2/core/base/connectors/.