Friday, February 6, 2009

Working Step 2: Mod_Wsgi and Idle MySQL Connections

In my last post, I listed five broad steps to get from here (Raise the Hammer running creakily in Classic ASP on a slightly dodgy IIS server) to there (Raise the Hammer running smoothly in Python and hanging out with the cool kids on a Linux server).

Step 1 is self-explanatory, but Step 2 has definitely been a slow progression (and a humbling experience, if ever there was a danger of me becoming a cocky programmer).

The process of getting the basic environment up and running has been by turns frustrating and exhilirating, as I slowly grow more acquainted with SSH, MySQL command line, Apache, and so on.

Setting up Apache and Mod_Wsgi


The hosting provider automatically installs the Apache webserver and sets up mod_wsgi, but when I ran a very simple web.py application, it served the pages as text/plain rather than text/html.

This turned out to be an easy fix. I modified the httpd.conf file (the configuration file for Apache) to add the following line:

AddType text/html .py

My next problem was trying to configure the site so that it served pages from http://domain.com/ rather than the relatively ugly http://domain.com/index.py/ (note the trailing slash). Also, I'm told that it's bad form to expose the underlying server technology in the URL.

A few websites suggested adding an Alias to httpd.conf, but this threw an internal server error. Then I figured out that Apache needed to have the mod_alias module added:

LoadModule alias_module modules/mod_alias.so

Then I could add the following lines:

Alias /static/ /path/to/webapp/htdocs/static/
Alias / /path/to/webapp/htdocs/index.py/

and voila! the files inside the /static/ folder (images, CSS and javascript) were served as is, and everything else was passed into the web.py application for handling.

MySQL, Why Did You Go Away


Once I had a web.py application running, I noticed that SQLAlchemy would intermittently pass along a seemingly bizarre error: "the MySQL Server Has Gone Away". On refresh, the page would load fine. The error seemed to happen when no page had been viewed for several hours

I found a helpful suggestion on this blog. Apparently the problem is that MySQL closes idle database connections after eight hours. The solution, then, is to ensure that the connection doesn't spend eight hours idling. The author proposed doing this by instructing SQLAlchemy to recycle the connection pool every 7,200 seconds (two hours).

So I tried it out:

import sqlalchemy as s
import quandy_config as c

engine = s.create_engine(c.DB_CONNECTION,
pool_size = 100,
pool_recycle=7200,
)

metadata = s.MetaData(bind=engine)

# define tables here

metadata.create_all()
and it seems to be working fine. I left the app to idle for twelve hours, and when I loaded it in my browser it fired up with no complaints.

Coming Soon: Windows guy learns SSH, or I'm PuTTY in your hands.

2 comments:

  1. The AddType directive is the wrong way of going about setting content type for a response. This should be done by the WSGI application by setting 'Content-Type' response header supplied to start_response().

    You also should be preferably using WSGIScriptAlias for defining the mount point of the WSGI application and you should not be adding a trailing slash after the path to the WSGI script file, whether or not Alias or WSGIScriptAlias is used. A trailing slash would only be used for Alias directive when right hand side is a directory of static files as per your '/static/' mount point.

    You might like to review the configuration guidelines on the mod_wsgi web site.

    ReplyDelete
  2. Graham,

    Thanks for your helpful suggestions - very much appreciated since I'm still learning.

    I implemented the first one (setting content-type from the web.py application rather than httpd.conf) with no problems, but can't seem to get the second working.

    When I remove the trailing slash after the path to the WSGI script file, the server returns 'None' instead of the web page, and when I convert the Alias for the static page to WSGIScriptAlias, the static files are no longer accessible, returning an HTTP 500 error.

    I reviewed the configuration guidelines, and found them less than forthcoming beyond the very simple example they provided...

    ReplyDelete