I have trouble with Delphi XE2 app. Sometimes WinInet call to ASMX service blocks and never returns - user must terminate process from task manager to close app.
To connect to ASMX service app uses service generated by WSDLImp tool.
During its work, app makes a lot of calls to web service (~1000-2000). And at some moment (last time it was 782 request item, first time it was near the end) app freezes. After some digging, logging I find out that app blocks on
WinInetResult := HttpSendRequest(Request, nil, 0, DatStr.Bytes, DatStr.Size);
In Soap.SOAPHTTPTrans unit
First guess was it is some server-side problem – server hangs on request processing. But on trials server was processing requests from other clients, while target one was blocked. And, when you use Fiddler to debug http traffic from app everything works as expected, no locks. Also, WinInet’s SendTimeout, ReceiveTimeout, ConnectTimeout has no effect – there are no timeout errors. One more point, app blocks not on specific method call, but on different ones.
After googling, I find out that HttpSendRequest can block on max parallel connections exceeded. But there are no parallel execution in app – each action is performed in main GUI thread.
My next try was to use Indy for HTTP communication instead of WinInet. And with Indy, app does its work as it should, no locks. But downside is performance degradation – app’s work takes two times longer with Indy.
This is not very good. So, I want to go back to WinInet. But for this I need to find reason of blocking. Does anybody know why HttpSendRequest can block?
P.S.
It is strange that with Indy we have such performance degradation. Maybe there are some properties, parameters to increase performance?
So, I have finally fixed this issue.
After all trials with no success, I've re-implemented SOAP calls using WinHTTP instead of WinInet.
With WinHTTP everything works normally.
Related
I use TIdHTTPServer in Delphi 11 to run a simple web server on a VPS.
It works great, except from time to time my app will start to use 100% of the CPU and keep this way forever, and I can't identify what is causing this.
When this happens, the server is still active and replying to requests, but very slowly. The only way to fix this is to force close the application and open it again.
I don't have any code to show, as my code is just generic responses using the OnCommandGet event of the TIdHTTPServer. This event will handle GET parameters on the URL and return something in the AResponseInfo.ContentText.
I know this is difficult, but any ideas about what I should hunt for to fix this?
We use TIdHttpServer quite a lot and have no problems with it. We use it in Delphi 10.3-10.4.2, but it’s not the reason for the problem. Programs work a few months without restarting.
From our experience we can say that problem of such unexpected behavior can be (in order of probability):
Code is not threadsafe. Event OnCommandGet run not in a main thread, so all access to global object/resources/etc must be done thru some kind of synchronization mechanism (locks, TEvent, synchronize, mutex, semaphore or other). If code does not use synchronization – it can broke logic, throw exceptions or do some other unexpected actions (like high CPU usage).
Connections count go over the limit. TIdHttpServer has properties like ListenQueue and MaxConnections. Can be that you make more requests that the server can handle. In this case your new requests wait until they can be handled by your code and it can make some additional CPU usage. To diagnose this – try to increment some internal variable at the start of your event and decrement it at the end. Make some service request to return this variable and you will know if all work correctly. Other similar situation – connection does not close after using the inside event and stay in memory, then you can go over limits too. Try to workaround properties TIdHttpServer.KeepAlive := false and TIdHttpServer.ReuseSocket := rsFalse.
Memory leaks. Try to set variable ReportMemoryLeaksOnShutdown := true and start the application, make a few requests and close it. If you’ll see a message with leaks – then you do something wrong, try to handle these objects in the right way. In production these small leaks can take a lot of RAM and Windows will dump part of memory into a swap-file, so your new requests will take more time to be processed.
Without an example, we can't say more.
This is an issue that's making me question my own sanity, but I'm posting the question in case it's something real rather than a problem of my own making.
I have an iOS app that is making use of the NSURLConnection class to send a request to a webserver. The object is instantiated and instructed to call back the delegate, which receives the corresponding notifications didReceiveResponse / didReceiveData / didFinishLoading / didFailWithError. Effectively the same code that is posted on Apple's dev page for using the class. The requests are all short POST transmissions with JSON data; the responses are also JSON-formatted, and come back from an Apache Tomcat Java Servlet.
For the most part it all works as advertised. The app sends a series of requests to the server in order to start a job and poll for partial results. Most of the exhanges are short, but sometimes the results can be up to about 100-200Kb maximum when there are partial results available.
The individual pieces of data get handed back by the operating system in chunks of about 10Kb each time, give or take. The transport is essentially instantaneous, as it is talking to a test server on the LAN.
However: after a few dozen polling operations, the rate of transport grinds to a near standstill. The sequence of response/data.../finished works normally: the webserver has delivered its payload, but the iOS app is receiving exactly 2896 bytes, with a periodicity of 20-30 seconds in between chunks. It is the correct data, and waiting about 5 minutes for 130Kb of data does confirm that it's operating correctly.
Nothing I do seems to conveniently work around it. I tried switching to the "async" invocation method with a response block; same result. Talking to a remote website rather than my LAN test deployment gets the same result. Running in simulator or iPhone gets the same result. The server returns content-length and doesn't try to do anything weird like keeping the connection alive.
Changing the frequency of the polling achieves little, unless I crank up the delay in between polling to 50 seconds, then everything works fine, presumably because it only ends up polling once or twice.
A hypothesis that fits this observation is that the NSURLConnection object hangs around long after it has been released, and chews up resources. Once a certain limit is hit, the progress rate grinds to a near halt. If the slowed down connection actually completes, subsequent connections work normally again, presumably because they've been cleaned up.
So does this sound familiar to anyone?
Does blackberry framework use connection reuse for http connection? I use connectionFactory.getConnection("api.abc.com") . I have noticed that the first call (simple rest call for ex, getting number of unread messages) from my app takes about 4 seconds but all the subsequent calls take less than a second to complete. I have noticed that the same call when made after another call takes less than a second, so I am thinking that blackberry uses http connection reuse. Does anyone have an explanation for this behaviour?
You can test this on the server, by looking at the network activity that actually makes it to the server. My own testing indicates BlackBerry devices do not re-use connections.
I want to download a file from internet and I imagine this should be a simple task. Trying several different approaches I have found that each one has its own drawback.
The main issues are:
Application freezes until it downloads the file
Application freezes forever if the Internet connection is lost/server does not respond.
(details:
How to retrieve a file from Internet via HTTP?
The connection does not timeout while downloading file from internet )
So, finally I used the suggestions I got from several people to use "pro" libraries such as Indy. However, Indy is not much better than the pieces of code I have tried (but it is way much larger and difficult to maintain). While using Indy the application does not freezes only for short periods so it is still (somehow) usable. However, the application cannot be shut down until the download finishes (never if the Internet connections gets broken).
Other people reported the same problem: http://borland.newsgroups.archived.at/public.delphi.internet.winsock/200609/0609079112.html
https://forums.embarcadero.com/thread.jspa?threadID=25199&tstart=90
So, there is some hacking I had to do to TIDAntiFreeze in order to make it work?
Also, the ConnectTimeout property is not recognized.
fIDHTTP := TIDHTTP.Create(NIL);
fIDHTTP.ConnectTimeout:=5000;
Should I drop Indy and return to original idea of downloading the file in a separate thread and end the thread when it does not respond (at least this way I get rid of 3rd party libraries)? There will be unforeseen side effects if I do this?
Using: Delphi 7, Indy 10.1.5 10.5 (probably).
Thanks
You probably need to use Indy the Indy way: using threads. Indy was specifically designed to work in blocking mode, because that's how most internet protocols work (example: with HTTP, at protocol level, you send a request, then you read the response. You don't send and receive at the same time). TIdAntiFreeze is supposed to help you use some Indy functionality without dealing with threads; I never used that because, at least conceptually, it's an ugly hack.
If you don't want to deal with threads then you should take a look at ICS - it was designed to be used in async mode, without threading. It doesn't need the equivalent of TIdAntiFreeze because it's not blocking. You start a download and you handle some events to get progress and completion notifications. ICS is just as well-known, professional and wildly used as Indy.
It's not too difficult to solve these sorts of problems. The first thing you have to do is make sure that you have properly handled error handling. If something fails then make sure everything cleans up properly. Beyond that make sure the downloading code is part of a separate thread. If there is any problem you can always terminate the thread from your main program. Here's the code (for downloading only, not the threading) which is working fine for me.
with TDownloadURL.Create(nil) do
try
URL := 'myurltodownload.com';
filename := 'locationtosaveto';
try
ExecuteTarget(nil);
except
result := false;
end;
if not FileExists(filename) then
result := false;
finally
clear;
free;
end;
we are developing a SOAP webservice (Apache/PHP). All run well for small size calls, but with a 1Mb soap call (the HTTPS call size is 1MB) our Delphi Soap client stop with a timeout on all PC but one, and our PHP clients run well with a default_socket_timeout=300, but stop with a "Error Fetching http headers" with default_socket_timeout=60.
How can we change the timeout for Delphi? In fact this timeout seem to be in a Windows XP network library (wininet.dll called by soaphttptrans.pas)
Thanks
Cédric
In fact it was a problem with IE7 installation : it change all the network timeout.
PC with IE6 have a 3600 secondes timeout, IE7 change it to 30 secondes.
Use of InternetQueryOption() show this, and InternetSetOption help to change this.
Big thanks to my work mate wich hunt the bug for hours.
There's a MaxSinglePostSize in SOAPHttpTrans. I seem to recall having issues with that. This isn't a limit, but it behaves differently (breaks up into chunks for sending) if you're over, or under that limit. (basically 32768 by default). I expect you'll hit that size sooner if you're on D2009/D2010 due to widestrings. It would be interesting to see if you run into trouble around that size. You can use Fiddler to capture some output (or hook into the OnBeforePost event and dump the serialized XML to a file yourself) and see if that's where you run into trouble, instead of the previously observed 1MB.
But anyway, the THTTPReqResp class has options for SendTimeout and ReceiveTimeout. Try adjusting those.
Also... if you are using Delphi prior to Delphi2007, you should update your soap libraries. There's a download somewhere... many bug fixes, including a nasty memory issue that will cause your app to be halted by DEP.