Sunday, July 6, 2008

Powerful CGI applications

In the article Myths About CGI Scalability published some time ago by Lars from z505, one of the authors of Powerful Web Utilities, he exposes a problem every CGI programmer faces with database applications. As you can see in that document, every time a CGI is called by a web browser, the operating system execute it and wait until its end showing the results to the client's browser. This operation is cached by the operating system after the first execution of the CGI, resulting in a faster execution of following calls.

If a web application uses a database, it's very common to create a CGI that connects to the database, perform a query then format the results and return them to the client. Using this approach, every time a user try to execute the CGI program a new connection to the database is created, resulting in slow and inefficient response times.

To resolve this problem, I created a simple CGI that sends socket commands to a program (I'll call it AppServer) wich takes care of database connections and heavy processes and returns its results to the CGI to be shown in the client's browser, using only one database connection to handle every CGI request. If the CGI finds the AppServer isn't running, it starts an instance and send the commands.

One interesting part of this approach is it runs in cheap hosting accounts, using Apache, IIS or any CGI capable web server. Also it can be compiled using FreePascal or Delphi.

The example uses PWU and Synapse for the AppServer, but you can use WebBroker or any other CGI technology.

You can download the CGI client and server to give it a try.

The CGI side is this:
uses
classes,
PwuMain,
HttpSend,
Windows;

function GetHtml: Boolean;
var
lHttp: THTTPSend;
lHtml: TStringList;

begin
Result := False;
lHtml := TStringList.Create;
lHttp := THTTPSend.Create;

with lHttp do
begin
HTTPMethod('GET', 'localhost:85/');
lHtml.LoadFromStream(Document);
Result := lHtml.Text <> '';
out(lHtml.Text);
end;
lHttp.Free;
lHtml.Free;
end;

var
lHandle: longint;

begin
if not GetHtml then
begin
(* If not connected, start the process *)
{$IFDEF WIN32}
lHandle := ShellExecute(0 , 'open', '.\httpserver.exe',
nil, nil, SW_HIDE);
{$ELSE}
lHandle := Shell('./httpserver');
{$ENDIF}
while True do
begin
if GetHtml then
Break;
end;
end
end.

No comments: