diff options
| author | bwarsaw | 2001-05-02 03:12:28 +0000 |
|---|---|---|
| committer | bwarsaw | 2001-05-02 03:12:28 +0000 |
| commit | a57f266f69c566112e50246ed5dfe973625b387c (patch) | |
| tree | 480fc332a8941e0d9878f5c367758323d484e93b /Mailman/Cgi/admin.py | |
| parent | c7a495d8944a555cfe88d4153c632c1f79e2ba3e (diff) | |
| download | mailman-a57f266f69c566112e50246ed5dfe973625b387c.tar.gz mailman-a57f266f69c566112e50246ed5dfe973625b387c.tar.zst mailman-a57f266f69c566112e50246ed5dfe973625b387c.zip | |
Fixes to handle User-Hits-Stop-Button problems, specifically,
main(): Set up a signal handler to catch SIGTERM, and unlock the
mailing list when this happens. This has the side effect of aborting
any changes to the MailList object that this web hit may have made.
This is necessary due to semantics of Apache's mod_cgi: when the
browser closes the socket, eventually Apache receives a SIGPIPE (on
output to the closed socket). This causes Apache to SIGTERM the cgi
process, wait three seconds, then SIGKILL it. We want to be able to
clean up the locks, so the best we can do is try to unlock the list on
the SIGTERM. Once we get SIGKILLed, there's nothing we can do.
This change also moves the Save() call into the try: block so that the
finally: block /only/ unlocks the list. Thus, the list gets unlocked
in most situations. There are still race conditions where 1) the
config.db file could be corrupted; 2) list locks could still be
unreleased. Given the semantics of signals in Python, the interaction
of Apache's mod_cgi, and other factors, this is the best we can do,
and it should be better than the old situation.
XXX What do other web servers or cgi execution environments do?
Diffstat (limited to 'Mailman/Cgi/admin.py')
| -rw-r--r-- | Mailman/Cgi/admin.py | 24 |
1 files changed, 22 insertions, 2 deletions
diff --git a/Mailman/Cgi/admin.py b/Mailman/Cgi/admin.py index 1e4b710b7..95d5558af 100644 --- a/Mailman/Cgi/admin.py +++ b/Mailman/Cgi/admin.py @@ -24,6 +24,7 @@ import cgi import types import sha import urllib +import signal from string import lowercase, digits from mimelib.address import unquote @@ -121,7 +122,7 @@ def main(): # The html page document doc = Document() doc.set_language(mlist.preferred_language) - # Now we're ready to do normal form processing. For this, though we must + # Now we're ready to do normal form processing. For this though, we must # lock the mailing list, and everything from here on out must be wrapped # in a try/except. # @@ -130,8 +131,23 @@ def main(): # or stale lock on the list. Maybe we should have a configurable timeout # setting after which we'll just inform the user that the operation # couldn't be performed? + # + # Set things up so that we can clean up the list lock even if the user + # hits the browser's stop button. Note that Apache under mod_cgi + # apparently can catch the SIGPIPE that results, and calls SIGTERM on the + # CGI process. Python doesn't install a signal handler for SIGTERM, so + # that would cause us to summarily exit, leaving list locks laying around + # (and this behavior has been confirmed). We can't just ignore SIGTERM + # because three seconds later Apache will SIGKILL us, giving us no chance + # to exit cleanly. By installing this signal handler, we can catch the + # SIGTERM and do the right thing. This may not work under other web + # servers, or even other Apache/cgi modules (mod_python, etc.). + def sigterm_handler(signum, frame, mlist=mlist): + mlist.Unlock() + mlist.Lock() try: + signal.signal(signal.SIGTERM, sigterm_handler) if cgidata.keys(): # There are options to change change_options(mlist, category, cgidata, doc) @@ -161,8 +177,12 @@ def main(): # Glom up the results page and print it out show_results(mlist, doc, category, category_suffix, cgidata) print doc.Format(bgcolor='#ffffff') - finally: mlist.Save() + finally: + # Now be sure to unlock the list. It's okay if we get a signal here + # because essentially, the signal handler will do the same thing. And + # unlocking is conditional, so it's not an error if we unlock while + # we're already unlocked. mlist.Unlock() |
