Kattes Posted April 15, 2020 Share Posted April 15, 2020 Hello, I am a bit clueless with a big problem I need to solve ASAP. The current situation is as followed. I am running on a Windows 2016 server two uniGui Applications. One works as a non visual DB server, which feeds an external PHP Shop Application with information like articles , prices, etc. The other one is a Backend Application, which handles all the articles from the shop. So this behaves more like the standard uniGui Application we all know, using all the nice uniGui visual components we all love. But my problem comes from the non visual application, which sometimes is not reachable, which means API calls from the PHP application do not get any response. Main part of this application is the Methode "UniGUIServerModuleHTTPCommand", which looks like this: procedure TUniServerModule.UniGUIServerModuleHTTPCommand(ARequestInfo: TIdHTTPRequestInfo; AResponseInfo: TIdHTTPResponseInfo; var Handled: Boolean); var sJSON, sParam, sRequest, s : string; i : integer; bValidRequest : boolean; begin // Examples of Supported APIs: // http://localhost:8077/v1/prom?ID=47 >> Get Details of selected event with the ID 47 // http://localhost:8077/v1/Prom/CheckAvail >> Check if server is online // http://localhost:8077/v1/Proms >> Get List of current events bValidRequest := false; if pos('/v1', ARequestInfo.URI) = 1 then // API Call found !! begin AResponseInfo.ResponseNo := 200; Handled := True; if ARequestInfo.AuthExists and (ARequestInfo.AuthPassword='wshgdaizuddsfrtG12') and (ARequestInfo.AuthUsername='XCloud') then begin sRequest := Uppercase(ARequestInfo.URI); if sRequest = Uppercase('/v1/Prom/CheckAvail') then // Checking the API accessibility during the purchase process begin bValidRequest := true; sJSON := '{"status": "online"}'; AResponseInfo.ContentText := sJSON; LogPayServer('HTTP Request "CheckAvail"', sJSON); end; if sRequest=Uppercase('/v1/Proms') then // Returns a list of all currently active proms in JSON format. begin bValidRequest := true; sJSON := GetEventsAsJSON; LogPayServer('HTTP Request "Proms"', sJSON); AResponseInfo.ContentText := sJSON; end; if sRequest=Uppercase('/v1/Prom/OrderConfirmed') then // Called after the sales process has been completed begin sJSON := ARequestInfo.RawHeaders.Values['OrderInfo']; // Process received order information LogPayServer('HTTP Request "OrderConfirmed"', sJSON); if AddJsonOrderInformationToDB2(sJSON) then begin LogPayServer('HTTP Request "OrderConfirmed"', 'bValidRequest=true'); bValidRequest := true; AResponseInfo.ContentText := '{"status": "processed"}'; // if everything is OK, than return follwing: end else LogPayServer('HTTP Request "OrderConfirmed"', 'bValidRequest=false'); end; if sRequest=Uppercase('/v1/Prom') then begin sParam := ARequestInfo.Params.Values['VoucherVal']; // Request to check the value of the given voucher if sParam <>'' then begin bValidRequest := true; // Get from DB the value of the given voucher and return it to JSON sJSON := '{"voucher value": '+GetVoucherValue(ZConnectionServerModule, sParam)+'}'; AResponseInfo.ContentText := sJSON; LogPayServer('HTTP Request "VoucherVal" ('+sParam+')', sJSON); end; sParam := ARequestInfo.Params.Values['Id']; // Returns information of the event, which was selected via its Id if sParam <>'' then begin bValidRequest := true; sJSON := GetEventDetailsJSON(sParam); AResponseInfo.ContentText := sJSON; LogPayServer('HTTP Request "Prom?Id=?"', sJSON); end; end; if not bValidRequest then begin AResponseInfo.ContentText := '<html>Not supported API-Call; Please check API documentation!</html>'; LogPayServer('HTTP Request "API ERROR"', ARequestInfo.URI); end; end else begin AResponseInfo.ContentText := '<html>Wrong or missing PW; Please use Basic Auth!</html>'; LogPayServer('HTTP Request "Invalid Caller"', 'PW / Auth wrong'); end; end; end; The Internalisation Methode is also simple and straightforward: procedure TUniServerModule.UniGUIServerModuleCreate(Sender: TObject); begin sHTML1 := tStringList.Create; sHTML2 := tStringList.Create; with ZConnectionServerModule do begin Connected := False; LibraryLocation := StartPath+'files\dll\libmysql.dll'; Protocol := 'mysql'; HostName := 'localhost'; Port := 3306; Database := 'xxxxx'; User := 'root'; Password := '-----'; Connected := true; end; LogPayServer('UniGUIServerModuleCreate','Server V'+FileVersionGet(StartPath+'AbiPaymentServer.dll')+' Created and running'); end; I am mentioning it here because as you can see it also uses a Log-Call, which writes information to a log table within my MySQL database and I can find randomly entries in the log, which show me that the application was restarted. At the moment the traffic handled by this Application is very low (less than 10 API calls per hour). Nevertheless I have the problem that the Application does not response and is not reachable sometimes. This is something I have not seen as long as I used it as standalone Application. Any comments or help are more than welcome! Quote Link to comment Share on other sites More sharing options...
Sherzod Posted April 15, 2020 Share Posted April 15, 2020 6 minutes ago, Kattes said: which means API calls from the PHP application do not get any response Hello, What is the response code gets a PHP app? Quote Link to comment Share on other sites More sharing options...
Kattes Posted April 15, 2020 Author Share Posted April 15, 2020 13 minutes ago, Sherzod said: Hello, What is the response code gets a PHP app? The PHP App is fed with JSON strings in a normal case, which were triggered by the API calls coming from the PHP app. But sometimes it happens that an API call does not get any response. This status of not getting any responses can stay for some minutes up to an hour. But then its starting to work again, which is very strange. Quote Link to comment Share on other sites More sharing options...
Sherzod Posted April 15, 2020 Share Posted April 15, 2020 31 minutes ago, Kattes said: This status of not getting any responses can stay for some minutes up to an hour. But then its starting to work again, which is very strange. Perhaps "third-party programs" interfere? Quote Link to comment Share on other sites More sharing options...
Jean-Marc Kiener Posted April 15, 2020 Share Posted April 15, 2020 I would assume that the problem is the MySQL connection. You connect once on the server module. I would recommend to create a new connection every time you send a sql statement to the db. Also some dB connection components needs a coinitialize construct every time a connection is created. Quote Link to comment Share on other sites More sharing options...
Kattes Posted April 15, 2020 Author Share Posted April 15, 2020 39 minutes ago, Jean-Marc Kiener said: I would assume that the problem is the MySQL connection. You connect once on the server module. I would recommend to create a new connection every time you send a sql statement to the db. Also some dB connection components needs a coinitialize construct every time a connection is created. Hi Jean-Marc, So you would suggest to keep the DB connection in the state "connected := false" as long as I do not enter UniGUIServerModuleHTTPCommand routine - so changing its state here on entry to true and before leaving to false again? Quote Link to comment Share on other sites More sharing options...
Jean-Marc Kiener Posted April 16, 2020 Share Posted April 16, 2020 i would suggest to create a new connection at the beginning of UniGUIServerModuleHTTPCommand, something like Con := TZconnection.create // Create the connection object Try // configure your connection here, // then open Con.open; // Do your stuff here Finally Con.free End; I assume that each HTTPCommand event runs in his own thread. Each thread needs his own db connection. I would try it this way. 1 Quote Link to comment Share on other sites More sharing options...
mierlp Posted April 16, 2020 Share Posted April 16, 2020 Hi Mysql depends on the wait_timeout parameter on the server-side .For example, I use myDac components to connect to MySQL. A common error is Lost Connection to MySQL during query. Not only with MyDac but also php or everything that connects to a MySQL server. This is caused by 2 parameters: 1. on the mysql server side, that is wait_timout parameter 2. on the software / component / connection side there is often a parameter regarding connection time-out These 2 values must be coordinated and the value on the software side must always be lower than the value of mysql server.In addition, a timer can be used to ping or re-connect to provide the time-out of the software side. Quote Link to comment Share on other sites More sharing options...
Kattes Posted April 16, 2020 Author Share Posted April 16, 2020 @Jean Marc, I followed your advice and changed the complete server code to make it even more thread-safe (although I thought ZEOS was already thread-safe). I also tested the other solution I mentioned before overnight, which already helped to make it more stable, but that ended up with another strange effect. Everything worked fine overnight, but the response times (time between API calls and JSON's response to the PHP server) became extremely high - about 10 seconds! So let's see what will be the outcome of changing the complete code and giving each API request its own DB connection. Whatever the outcome will be, I really appreciate your help JM. @mierlp, I also want to thank you for this additional inspiration. If my last changes do not solve my problem, I will investigate in the direction you suggest. Quote Link to comment Share on other sites More sharing options...
Kattes Posted April 16, 2020 Author Share Posted April 16, 2020 Okay, I just found another important piece of the puzzle. The problem only occurs if the visual application is also running and accessing the same database. In this case the access of the second application is extremely slowed down. We are not talking about a lot of traffic. This happens already when only one visual and one non-visual application connects to the same database at the same time, but I have no idea how to prevent this. Perhaps I will try to change to Firedac instead of using ZEOS - what do you think? Quote Link to comment Share on other sites More sharing options...
delagoutte Posted April 16, 2020 Share Posted April 16, 2020 5 hours ago, Kattes said: Perhaps I will try to change to Firedac instead of using ZEOS - what do you think? i think it is a very good idea 1 Quote Link to comment Share on other sites More sharing options...
Kattes Posted April 17, 2020 Author Share Posted April 17, 2020 Although it was a lot of work to change everything to FireDAC, it seems to have been worth the effort! All problems I described before are gone! So I would like to warn everyone to use ZEOS in their uniGui projects. Something seems to be incompatible and can cause problems that are extremely difficult to understand. Once again, a big thank you to all of you who joined me on the bug search. Kind regards, Carsten - aka Kattes 2 Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.