FastCGI

From DreamHost
(Redirected from Fastcgi)
Jump to: navigation, search

FastCGI is a way to have CGI scripts execute time-consuming code (like opening a database) only once, rather than every time the script is loaded. In technical terms, FastCGI is a language independent, scalable, open extension to CGI that provides high performance without the limitations of server specific APIs. fastcgi.com, fastcgi.com FAQ.

To use FastCGI you will need to:

  1. Enable it in the control panel under Domains -> Manage Domains -> Web Hosting -> Edit.
  2. Make some minor changes to your scripts (detailed below).
  3. Name your script with an .fcgi extension, or add the line "SetHandler fastcgi-script" to your .htaccess file. (One user says editing .htaccess this way might cause problems depending upon where you put your files.)

You should also understand that errors and troubleshooting are very different with FastCGI vs. regular CGI. If a FastCGI script has an error, a web page with a bad script will try to load for a few minutes rather than failing immediately, looking like a hung page. Also, if you fix the error, and try to reload the page, the server will still try to execute the old version of the script rather than the new one, so the page will continue to stall when loading. You solve this problem by killing the FastCGI process to force the server to load the newest version of the script. (More on that below.)


Language-specific code guides

If you want to get started quickly, these are the best place to start.

Configuration Details

This is the current FastCGI (mod_fastcgi) configuration at Dreamhost:

FastCgiConfig -autoUpdate -initial-env RAILS_ENV=production -idle-timeout 60 -startDelay 10 -maxClassProcesses 2 -killInterval 300

Those settings are almost exactly the default configuration for FastCGI. Details about this configuration line may be found in the mod_fastcgi documentation.

Note, the settings may change at any time without notice though Dreamhost says they have no plans to change it.


On DreamHost PS FastCGI is handled by mod_fcgid rather than mod_fastcgi. DreamHost has also started the process of migrating the shared hosting servers.

Changes to make to your scripts

Structure of a FastCGI script

FastCGI scripts have two sections:

  1. Code that runs just once (like opening a database).
  2. Code that runs every time.

Here's an example with Perl:

#!/usr/bin/perl

#-----------------------
#  CODE THAT RUNS ONCE
#-----------------------
     $counter=0;

#---------------------------------
#  CODE THAT RUNS EVERY TIME
#---------------------------------

use FCGI;
while ( FCGI::accept() >= 0 ) {
      $counter++;
      print "Content-type:text/html\n\n";
      print "I have run $counter times.";
}

While you might think that you have to print the header only once, in fact the header must be included in the "run every time" section.

No Exits

If your script terminates by some command (like exit; or last; in Perl), the script will start over from scratch the next time it's run, losing the benefits of running certain code only once. What's more, in my experience if a script is terminated this way it may not run again for several minutes. The symptom is that the browser tries to load the page for a couple of minutes, finally giving up with "an error occurred while processing this directive". The error is doubly frustrating because you (or your users) have to wait multiple minutes to get it.

The solution is to use whatever flow control is available in your programming language to have the script finish by itself. Here's a before and after example in Perl with some pseudocode.

Wrong way
#!/usr/bin/perl

#-----------------------
#  CODE THAT RUNS ONCE
#-----------------------
     (open a database)

#---------------------------------
#  CODE THAT RUNS EVERY TIME
#---------------------------------

use FCGI;
while ( FCGI::accept() >= 0 ) {
      print "Content-type:text/html\n\n";

      if (some test) { exit;}

      more code;
}
Right way
#!/usr/bin/perl

#-----------------------
#  CODE THAT RUNS ONCE
#-----------------------
     (open a database)

#---------------------------------
#  CODE THAT RUNS EVERY TIME
#---------------------------------

use FCGI;

while ( FCGI::accept() >= 0 ) {
      print "Content-type:text/html\n\n";

      if (some test) { goto(EXITLABEL) }

      more code;

      EXITLABEL: {}
}

Use $ENV{'QUERY_STRING'} instead of @ARGV

You cannot get the query string in FastCGI by using the @ARGV array. You must use $ENV{'QUERY_STRING'} instead.


Errors and Troubleshooting

Bad scripts won't return an error immediately; you have to wait a couple of minutes for the script to time out. If the script is on a web page, the page will appear to hang. And even when the script times out, the actual error message might not be logged, you might get only the 500 error. This means that testing under FastCGI is rather impractical. Development should be done with standard CGI, or on your local computer. FastCGI should be added after the script has already been debugged.

Also, while it's tempting to develop on a live server, it's dangerous and makes you a bad neighbor for shared hosting.

To see immediately if a script will fail (won't check all cases because %ENV will be different), test it from the command line.

 perl ~/mydomain.com/myscript.fcgi

or for deeper checking if you can use the debugger--

perl -d ~/mydomain.com/myscript.fcgi

If you've introduced an error into a script, fixing the error might not fix it immediately, because sometimes the server will still be running an old version of the script from memory for some reason. (The server is supposed to look at the modification date of the file so that it's always running the most recent version, but in my experience that's often not the case. When the server fails to to do this, "touch"ing the file doesn't help, either.) To get the server to run the current version of the script, find the old process and kill it:

killall -USR1 scriptname.fcgi     (replace scriptname.fcgi with the name of the process)

The above command may not always convince all the proccesses to stop. To force them to stop use:

killall -9 scriptname.fcgi   (replace scriptname.fcgi with the name of the process)

Occasionally you may have to use ruby1.8 as a task ID:

killall -9 ruby1.8

My FastCGI Isn't working

Make sure that the script you are trying to execute is set as executable:

chmod +x myscript.fcgi

Check the error log. If you are getting the error:

 [Fri Sep 05 11:55:03 2008] [error] [client 123.45.67.89] FastCGI: comm with (dynamic) server "/home/myaccount/mysite.com/myscript.fcgi" aborted: (first read) idle timeout (60 sec)

you need to check your file and directory permissions. The directory containing the fcgi, and the fcgi itself, need to be owned by your default unix group and be group-writable:

 chgrp -R `groups | awk '{print $1}'` ~/mysite.com/ 
 chmod -R g+w ~/mysite.com/

I'm able to run FastCGI without adding anything to my .htaccess file, but others suggest adding this:

AddHandler fastcgi-script .fcgi
Options +FollowSymLinks +ExecCGI

If you have edited your PHP.INI file, then you need to force a recache... load your terminal and type:

touch ~/php5/php5-wrapper.fcgi

Also, I found that I had the following directive:

RewriteRule ^(.*)$ scriptname.cgi [QSA,L]

That needed to be changed to:

RewriteRule ^(.*)$ scriptname.fcgi [QSA,L]


Delete the sessions in your /tmp folder

Possible future alternatives to using Fast CGI

http://www.vmunix.com/mark/blog/archives/2006/01/02/fastcgi-scgi-and-apache-background-and-future

Improving FastCGI on Dreamhost

There are now three suggestions up on the Suggestions sections of the panel:

These three would benefit deployment and use of certain application servers -- there's a problem w/ restarting processes correctly when deploying e.g. TurboGears using FastCGI, plus the memory consumption is 3x as large (with three forked processes as the current configuration on server glass).

Killed incorrectly, you'll have to wait for a couple of minutes (I *think* it's the Apache FastCGI timeout) before the application will start again. Also, the fact that you run N forked servers will force you to store all data in a database instead of keeping the state in the server, which is one of the main points of having an application server -- you have *state*.

Some other web hosts (linked from the TurboGears official site) assign port numbers to apps/websites to which the app is connected using an (optional) autostart CGI, bootstrapping the app server, through a reverse proxy using Apache/mod_proxy. Very easy and very clever. Would be nice to see something similar at DreamHost.


External Links