Jump to content

Problem With ISAPI


Kattes

Recommended Posts

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.

overview.jpg.257aac685146f5c347d1b3670cabd3cc.jpg

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!

Link to comment
Share on other sites

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.

Link to comment
Share on other sites

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.

Link to comment
Share on other sites

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?

Link to comment
Share on other sites

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.

  • Like 1
Link to comment
Share on other sites

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.

Link to comment
Share on other sites

@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.

Link to comment
Share on other sites

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?

Link to comment
Share on other sites

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

  • Like 2
Link to comment
Share on other sites

Please sign in to comment

You will be able to leave a comment after signing in



Sign In Now
×
×
  • Create New...