Python and FastCGI

S

Steffen Ebermann

Hi,

this might be a little off topic (could be any other language)
but I'm trying to set up Python to use FastCGI instead of plain CGI.

The basic setup is no problem but every tutorial (including Python's
'HOWTO Use Python in the web') ends with some basic dispatch file and
that's it. I guess I should know how to go about from there, but,
well I don't.

I guess I could put an execfile('index.py') into the dispatcher and
then rewrite my code for FastCGI (i.e. replace every print with
req.write() for jonpy), but that doesn't seem right to me.

Is there a better solution or do I misunderstand something entirely?
I would be glad if someone could point me in the right direction.

Thanks in advance.
 
J

John Nagle

Steffen said:
Hi,

this might be a little off topic (could be any other language)
but I'm trying to set up Python to use FastCGI instead of plain CGI.

The basic setup is no problem but every tutorial (including Python's
'HOWTO Use Python in the web') ends with some basic dispatch file and
that's it. I guess I should know how to go about from there, but,
well I don't.

I guess I could put an execfile('index.py') into the dispatcher and
then rewrite my code for FastCGI (i.e. replace every print with
req.write() for jonpy), but that doesn't seem right to me.

Is there a better solution or do I misunderstand something entirely?
I would be glad if someone could point me in the right direction.

Thanks in advance.

You don't print in an FCGI program. At the end of the function,
you return a reply string.

Here's the main program of a live FCGI application. This is
from something that answers XMLHttpRequest request, rather than
serving HTML pages. So it outputs XML.

Things to note:

1. FCGI programs can run for a long time, like days. So you
have to handle the possible loss of a database connection, as
is done here.

2. Catch and handle all exceptions. FCGI won't give you much
information in the error log.

3. You have to specify everything that goes in the HTTP headers
by calling start_response().

4. Notice the last line:
WSGIServer(QuickSitetruthQuery).run()

That's the call which tells WSGIServer what function to call
for each request.

5. If you put an FCGI file in a directory from which Apache
will run CGI files, your FCGI program will be run as a CGI
program. Everything will appear to work, because the FCGI
library understands this is a debug mode. But you're loading
the program on each use, so the overhead is huge, as with CGI.
CGI is built into Apache at too low a level, and it will run
something as CGI even when you've told it a directory is
supposed to be used for FCGI. So create an "fcgi" directory
someplace other than "cgi" and tell Apache to use that for
FCGI.

FCGI is a good system; it's just that the documentation isn't
very good. This code has been running a live
web site for two years now.


John Nagle

#!/usr/local/bin/python
### ... application-specific stuff deleted
from fcgi import WSGIServer
import MySQLdb
import cgi import urllib
import InfoDisplay import miscutils
db = None # database connection, held open for life of FCGI
#
# The application
#
def QuickSitetruthQuery(environ, start_response):
global db # static global - active database handle
try:
if db : # if previously attached
try :
db.ping() # test whether connection is still up
except MySQLdb.OperationalError, message: # loss of conn.
db = None # we lost database connection
if db is None : # if no valid database handle
db = miscutils.dbattach(kdbfile) # connect to database
status = '200 OK' # normal status
headers = [('Content-type','text/xml'), ('charset','utf-8')]
reqlist = cgi.parse_qsl(environ['QUERY_STRING']) # Parse params
priority = 1 # priority of request
sourceip = environ['REMOTE_ADDR'] # get IP address of client
urls = [] # list of URLs to check
for item in reqlist : # for all items
(key, value) = item # extract item
if key.lower() == 'url' : # want all "url" items,
urls.append(value)
elif key.lower() == 'priority' : # if priority
priority = int(value) # get priority value
# Make request; no waiting, no details
outstr = InfoDisplay.getratingXMLquick(db, kdbfile,
urls, priority, sourceip) # get the rating XML
needretry = outstr.find('status="202"') >= 0 # if retry soon
if needretry : # if the client will need to retry this request
headers.append(('Expires','-1')) # expire immediately
start_response(status, headers) # compose result
s = kprefixxml + outstr + ksuffixxml # construct output XML
return [s.encode('utf8')] # encode as UTF8
except Exception, message: # if trouble, report to user
# Error handling
status = "500 Internal Error on Server"
response_headers = [("Content-type","text/html")]
start_response(status, response_headers)
s = "<h1>Internal error - request not processed.</h1>\n\n" +
traceback.format_exc()
s = s.replace("\n","<br\>") # convert to HTML
return
#
# Main FCGI program
#
WSGIServer(QuickSitetruthQuery).run()
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,995
Messages
2,570,230
Members
46,819
Latest member
masterdaster

Latest Threads

Top