I'm using Apache Axis to make a SOAP request to a service. I noticed that sometimes, it take a couple of seconds to get a response even though the service is a simple echo for now. So I'm wondering if establishing the connection is what takes the time, even though the server does HTTP/1.1 connection keep alive.
Should somehow reuse the client between requests or if it's ok to get a new one for every request?
This is my code. Should I keep locator and/or client around between requests or is it okay to forget it?
MyExampleServiceLocator locator = new MyExampleServiceLocator();
MyExampleServicePort client = locator.getMyExampleServicePort(url);
MyExampleRequest request = buildMyExampleRequest();
MyExampleResponse response = client.send(request); // This takes time sometimes
For complex services the cost of instantiating the locator may be high. Therefore you should always try to reuse it as much as possible. Locators are expected to be thread safe, so you can use them as singletons. Note however that in Axis 1.4 there is at least one thread safety issue regarding locators: AXIS-2498.
Creating a new stub (client) is less expensive, but reusing a stub is unproblematic. They are also expected to be thread safe (at least in Axis 1.4), except for scenarios that use the stub in a stateful way (e.g. HTTP sessions).
Axis' default HTTP transport only supports HTTP 1.0 and creates a new connection for every request.
Related
I have a few servers that I make REST requests to from my program. They will all have the same response to a particular request.
I accept one ip as argument and make my requests to that server. If I wish to now accept a List<ip>, how do I elegantly switch to the next server in the list when one fails? Looping through the list on every network call seems silly.
Unfortunately I cannot make a REST call with the catch-repeat_to_next_server extracted to one function that accepts an HttpClient with the rest of the request because I'm using a 3rd part SDK to talk to the servers and every request is a chain of method calls.
I can't do this (pseudo-code):
def doRequest(HttpClient client)
for ip in list_of_ips:
try:
client.host = ip
return client.execute()
catch exp:
// move failed ip to end of list or something
throw "None of them worked"
HttpClient c
c.method = "GET /api/employees"
doRequest(c)
c.method = "GET /api/department/:id"
doRequest(c)
Are there any standard ways to solve this in clean way?
I'm using Java and Spring so I am constrained by static typing but may have some sort of Spring annotation magic that I can use that I am not aware of.
How you are making the REST call is not important.
Your psuedo code should be correct even if you need to make a million method calls per REST call.
for ip in ip_list
do_stuff_to_make_the_rest_call
perhaps_note_the_ip_that_was_used
indicate_success
break_out_of_for_loop
catch some_exception
perhaps_note_the_ip_that_failed
end for
if !success
do all_ip_failed_stuff.
procedure do_stuff_to_make_the_rest_call
make a million method calls to get one REST call attempt.
I'm looking for the best solution to solve this problem :
I have a client and a server.
The client sending request to the server using the call.invoke method.
The call for now is synchronous and waiting for the answer.
The time is taking to receive the replay from the server under load is around 1 sec(this is a lot of time).
at the client side we are generating requests around 50-100 request per second , the queue is exploding.
For now i just created a thread pool that will work asynchronous and will send the requests to the server per thread , but the request it self will be synchronous.
The meaning of that is that the thread pool should maintain ~100 threads if we do want that it will work fine.
I'm not sure this is the best solution.
I also was thinking to create somehow 1 thread that will send the requests and 1 thread that will catch the replays, but then i'm afraid that i will pass on the load to the server side.
Few things that are importent:
We cannot effect the code on the server side and we cannot control the time it takes to receive a replay.
while receiving the replay we just use this data to create another data structure and pass it on - so the time stamp is not relay importent.
we are using axis api.
any idea of how is it the best way to solve it? the thread pool of the 100 thread seems fine ? or there some other ways?
Thanks!
You can call axis service using non-blocking client way by registering the callback instance.
Client class:
ServiceClient sc = new ServiceClient();
Options opt= new Options();
//set the target EP
opt.setTo(new EndpointReference("http://localhost:8080/axis2/services/CountryService"));
opt.setAction("urn:getCountryDetails");
sc.setOptions(opt);
sc.sendReceiveNonBlocking(payload, callBack);
// inner class with axisCallback , overide all its methods. onMessage get called once result receive from backend
AxisCallback callBack = new AxisCallback() {
#Override
public void onMessage(MessageContext msgContext) {
System.out.println(msgContext.getEnvelope().getBody().getFirstElement());
//this method get called when you received the results from the backend
}
...
}
Reference for writing axis service : http://jayalalk.blogspot.com/2014/01/writing-axis2-services-and-deploying-in.html
I have a Java web service client running on Linux (using Axis 1.4) that invokes a series of web services operations performed against a Windows server. There are times that some transactional operations fail with this Exception:
java.net.SocketTimeoutException: Read timed out
However, the operation on the server is completed (even having no useful response on the client). Is this a bug of either the web service server/client? Or is expected to happen on a TCP socket?
This is the expected behavior, rather than a bug. The operation behind the web service doesn't know anything about your read timing out so continues processing the operation.
You could increase the timeout of the connection - if you are manually manipulating the socket itself, the socket.connect() method can take a timeout (in milliseconds). A zero should avoid your side timing out - see the API docs.
If the operation is going to take a long time in each case, you may want to look at making this asynchronous - a first request submits the operations, then a second request to get back the results, possibly with some polling to see when the results are ready.
If you think the operation should be completing in this time, have you access to the server to see why it is taking so long?
I had similar issue. We have JAX-WS soap webservice running on Jboss EAP6 (or JBOSS 7). The default http socket timeout is set to 60 seconds unless otherwise overridden in server or by the client. To fix this issue I changed our java client to something like this. I had to use 3 different combinations of propeties here
This combination seems to work as standalone java client or webservice client running as part of other application on other web server.
//Set timeout on the client
String edxWsUrl ="http://www.example.com/service?wsdl";
URL WsURL = new URL(edxWsUrl);
EdxWebServiceImplService edxService = new EdxWebServiceImplService(WsURL);
EdxWebServiceImpl edxServicePort = edxService.getEdxWebServiceImplPort();
//Set timeout on the client
BindingProvider edxWebserviceBindingProvider = (BindingProvider)edxServicePort;
BindingProvider edxWebserviceBindingProvider = (BindingProvider)edxServicePort;
edxWebserviceBindingProvider.getRequestContext().put("com.sun.xml.internal.ws.request.timeout", connectionTimeoutInMilliSeconds);
edxWebserviceBindingProvider.getRequestContext().put("com.sun.xml.internal.ws.connect.timeout", connectionTimeoutInMilliSeconds);
edxWebserviceBindingProvider.getRequestContext().put("com.sun.xml.ws.request.timeout", connectionTimeoutInMilliSeconds);
edxWebserviceBindingProvider.getRequestContext().put("com.sun.xml.ws.connect.timeout", connectionTimeoutInMilliSeconds);
edxWebserviceBindingProvider.getRequestContext().put("javax.xml.ws.client.receiveTimeout", connectionTimeoutInMilliSeconds);
edxWebserviceBindingProvider.getRequestContext().put("javax.xml.ws.client.connectionTimeout", connectionTimeoutInMilliSeconds);
I'm having trouble establishing AsyncContexts for users and using them to push notifications to them. On page load I have some jQuery code to send the request:
$.post("TestServlet",{
action: "registerAsynchronousContext"
},function(data, textStatus, jqXHR){
alert("Server received async request"); //Placed here for debugging
}, "json");
And in "TestServlet" I have this code in the doPost method:
HttpSession userSession = request.getSession();
String userIDString = userSession.getAttribute("id").toString();
String paramAction = request.getParameter("action");
if(paramAction.equals("registerAsynchronousContext"))
{
AsyncContext userAsyncContext = request.startAsync();
HashMap<String, AsyncContext> userAsynchronousContextHashMap = (HashMap<String, AsyncContext>)getServletContext().getAttribute("userAsynchronousContextHashMap");
userAsynchronousContextHashMap.put(userIDString, userAsyncContext);
getServletContext().setAttribute("userAsynchronousContextHashMap", userAsynchronousContextHashMap);
System.out.println("Put asynchronous request in global map");
}
//userAsynchronousContextHashMap is created by a ContextListener on the start of the web-app
However, according to Opera Dragonfly (a debugging tool like Firebug), it appears that the server sends an HTTP 500 response about 30000ms after the request is sent.
Any responses created with userAsyncContext.getResponse().getWriter().print(SOME_JSON) and sent before the HTTP 500 response is not received by the browser, and I don't know why. Using the regular response object to send a response (response.print(SOME_JSON)) is received by the browser ONLY if all the code in the "if" statement dealing with AsyncContext is not present.
Can someone help me out? I have a feeling this is due to my misunderstanding of how the asynchronous API works. I thought that I would be able to store these AsyncContexts in a global map, then retrieve them and use their response objects to push things to the clients. However, it doesn't seem as if the AsyncContexts can write back to the clients.
Any help would be appreaciated.
I solved the issue. It seems as though there were several problems wrong with my approach:
In Glassfish, AsyncContext objects all have a default timeout period of 30,000 milliseconds (.5 minutes). Once this period expires, the entire response is committed back to the client, meaning you won't be able to use it again.
If you're implementing long-polling this might not be much of an issue (since you'll end up sending another request after the response anyway), but if you wish to implement streaming (sending data to back to the client without committing the response) you'll want to either increase the timeout, or get rid of it all together.
This can be accomplished with an AsyncContext's .setTimeout() method. Do note that while the spec states: "A timeout value of zero or less indicates no timeout.", Glassfish (at this time) seems to interpret 0 as being "immediate response required", and any negative number as "no timeout".
If you're implementing streaming , you must use the printwriter's .flush() method to push the data to the client after you're done using its .print() .println() or .write() methods to write the data.
On the client side, if you've streamed the data, it will trigger a readyState of 3 ("interactive", which means that the browser is in the process of receiving a response). If you are using jQuery, there is no easy way to handle readyStates of 3, so you're going to have to revert to regular Javascript in order to both send the request and handle the response if you're implementing streaming.
I have noticed that in Glassfish if you use AsyncContext and use .setTimeOut() to a negative number the connection is broken anyway, to fix this I had to go to my Glassfish admin web configurator : asadmin set
configs.config.server-config.network-config.protocols.protocol.http-listener-1.http. And set timeout to -1. All this to avoid glassfish finish the connections after 30 sec.
I am writing an application which uses web services to connect a remote server.I have written a method to ping function to determine if the server is online or not(i.e. its providing the web services which can be accessed using host:port).I am executing a simple web service with a 2 sec timeout(available as an option in stub class before I make the call).Ideally the call should return within 2 seconds allowing me to ascertain whether the server is up or down.However in certain cases it takes far longer than 2 seconds.
Can anyone help me figure out why this is happening?Is there a way to ensure that the timeout value is honored ?
Thanks,
Fell
In Axis client stubs, there is an option for you to set the timeout. You can also use it. Note that the time-out is measured in milliseconds. check here
And if it is Axis2, you can use like this:
Stub s = new Stub();
ServiceClient sc = s.getServiceClient();
Options o = sc.getOptions();
o.setTimeOutInMilliSeconds(2000); //2 seconds
sc.setOptions(o);
s.setServiceClient(sc);
You can make your calls after setting the above stuff.
Don't use the default http sender, switch to commons http client based sender. Details are here - http://wiki.apache.org/ws/FrontPage/Axis/AxisCommonsHTTP - Same page has details on how to set various kinds of timeouts as well.