Revision: 8121
http://svn.sourceforge.net/mailman/?rev=8121&view=rev
Author: bwarsaw
Date: 2006-12-28 20:34:52 -0800 (Thu, 28 Dec 2006)
Log Message:
-----------
Remove SIGTERM handling from all the CGI scripts. This messes with HTTPRunner
because when you issue "mailmanctl stop" after the signal handler has been
installed, the process will get a SIGTERM, the signal handler will run, and
the process will exit with a normal zero code. This will cause mailmanctl to
try to restart the HTTPRunner.
I don't think we need that stuff at all when running under wsgi with a
SQLAlchemy backend. If mailmanctl kills the HTTPRunner in the middle of the
process, I believe (but have not tested) that the transaction should get
properly rolled back at process exit. We need to make sure about this, and
also we need to test the signal handling functionality under traditional CGI
environment (if we even still want to support that).
Also, make sure that we don't try to initialize the loggers twice in qrunner.
This was the cause of all the double entries in logs/qrunner.
Fix a coding style nit in mailmanctl.py.
De-DOS-ify line endings in loginit.py.
Modified Paths:
--------------
branches/tmp-sqlalchemy-branch/Mailman/Cgi/admin.py
branches/tmp-sqlalchemy-branch/Mailman/Cgi/admindb.py
branches/tmp-sqlalchemy-branch/Mailman/Cgi/create.py
branches/tmp-sqlalchemy-branch/Mailman/Cgi/options.py
branches/tmp-sqlalchemy-branch/Mailman/Cgi/subscribe.py
branches/tmp-sqlalchemy-branch/Mailman/Queue/HTTPRunner.py
branches/tmp-sqlalchemy-branch/Mailman/bin/mailmanctl.py
branches/tmp-sqlalchemy-branch/Mailman/bin/qrunner.py
branches/tmp-sqlalchemy-branch/Mailman/loginit.py
branches/tmp-sqlalchemy-branch/scripts/driver
Modified: branches/tmp-sqlalchemy-branch/Mailman/Cgi/admin.py
===================================================================
--- branches/tmp-sqlalchemy-branch/Mailman/Cgi/admin.py 2006-12-28 00:17:26 UTC
(rev 8120)
+++ branches/tmp-sqlalchemy-branch/Mailman/Cgi/admin.py 2006-12-29 04:34:52 UTC
(rev 8121)
@@ -22,7 +22,6 @@
import cgi
import sha
import sys
-import signal
import urllib
import logging
@@ -127,40 +126,8 @@
# The html page document
doc = Document()
doc.set_language(mlist.preferred_language)
-
- # From this point on, the MailList object must be locked. However, we
- # must release the lock no matter how we exit. try/finally isn't enough,
- # because of this scenario: user hits the admin page which may take a long
- # time to render; user gets bored and hits the browser's STOP button;
- # browser shuts down socket; server tries to write to broken socket and
- # gets a SIGPIPE. Under Apache 1.3/mod_cgi, Apache catches this SIGPIPE
- # (I presume it is buffering output from the cgi script), then turns
- # around and SIGTERMs the cgi process. Apache waits three seconds and
- # then SIGKILLs the cgi process. We /must/ catch the SIGTERM and do the
- # most reasonable thing we can in as short a time period as possible. If
- # we get the SIGKILL we're screwed (because it's uncatchable and we'll
- # have no opportunity to clean up after ourselves).
- #
- # This signal handler catches the SIGTERM, unlocks the list, and then
- # exits the process. The effect of this is that the changes made to the
- # MailList object will be aborted, which seems like the only sensible
- # semantics.
- #
- # BAW: This may not be portable to other web servers or cgi execution
- # models.
- def sigterm_handler(signum, frame, mlist=mlist):
- # Make sure the list gets unlocked...
- mlist.Unlock()
- # ...and ensure we exit, otherwise race conditions could cause us to
- # enter MailList.Save() while we're in the unlocked state, and that
- # could be bad!
- sys.exit(0)
-
mlist.Lock()
try:
- # Install the emergency shutdown signal handler
- signal.signal(signal.SIGTERM, sigterm_handler)
-
if cgidata.keys():
# There are options to change
change_options(mlist, category, subcat, cgidata, doc)
@@ -190,10 +157,6 @@
print doc.Format()
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 unconditional, so it's not an error if we unlock while
- # we're already unlocked.
mlist.Unlock()
Modified: branches/tmp-sqlalchemy-branch/Mailman/Cgi/admindb.py
===================================================================
--- branches/tmp-sqlalchemy-branch/Mailman/Cgi/admindb.py 2006-12-28
00:17:26 UTC (rev 8120)
+++ branches/tmp-sqlalchemy-branch/Mailman/Cgi/admindb.py 2006-12-29
04:34:52 UTC (rev 8121)
@@ -23,7 +23,6 @@
import time
import email
import errno
-import signal
import logging
from urllib import quote_plus, unquote_plus
@@ -134,27 +133,8 @@
if qs and isinstance(qs, list):
details = qs[0]
- # We need a signal handler to catch the SIGTERM that can come from Apache
- # when the user hits the browser's STOP button. See the comment in
- # admin.py for details.
- #
- # BAW: Strictly speaking, the list should not need to be locked just to
- # read the request database. However the request database asserts that
- # the list is locked in order to load it and it's not worth complicating
- # that logic.
- def sigterm_handler(signum, frame, mlist=mlist):
- # Make sure the list gets unlocked...
- mlist.Unlock()
- # ...and ensure we exit, otherwise race conditions could cause us to
- # enter MailList.Save() while we're in the unlocked state, and that
- # could be bad!
- sys.exit(0)
-
mlist.Lock()
try:
- # Install the emergency shutdown signal handler
- signal.signal(signal.SIGTERM, sigterm_handler)
-
realname = mlist.real_name
if not cgidata.keys():
# If this is not a form submission (i.e. there are no keys in the
Modified: branches/tmp-sqlalchemy-branch/Mailman/Cgi/create.py
===================================================================
--- branches/tmp-sqlalchemy-branch/Mailman/Cgi/create.py 2006-12-28
00:17:26 UTC (rev 8120)
+++ branches/tmp-sqlalchemy-branch/Mailman/Cgi/create.py 2006-12-29
04:34:52 UTC (rev 8121)
@@ -21,7 +21,6 @@
import cgi
import sha
import sys
-import signal
import logging
from Mailman import Errors
@@ -161,18 +160,7 @@
fqdn_listname = '[EMAIL PROTECTED]' % (listname, email_host)
# We've got all the data we need, so go ahead and try to create the list
mlist = MailList.MailList()
- # See admin.py for why we need to set up the signal handler.
- def sigterm_handler(signum, frame):
- # Make sure the list gets unlocked...
- mlist.Unlock()
- # ...and ensure we exit, otherwise race conditions could cause us to
- # enter MailList.Save() while we're in the unlocked state, and that
- # could be bad!
- sys.exit(0)
try:
- # Install the emergency shutdown signal handler
- signal.signal(signal.SIGTERM, sigterm_handler)
-
pw = sha.new(password).hexdigest()
# Guarantee that all newly created files have the proper permission.
# proper group ownership should be assured by the autoconf script
@@ -205,10 +193,6 @@
mlist.default_member_moderation = moderate
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 unconditional, so it's not an error if we unlock while
- # we're already unlocked.
mlist.Unlock()
# Now do the MTA-specific list creation tasks
if config.MTA:
Modified: branches/tmp-sqlalchemy-branch/Mailman/Cgi/options.py
===================================================================
--- branches/tmp-sqlalchemy-branch/Mailman/Cgi/options.py 2006-12-28
00:17:26 UTC (rev 8120)
+++ branches/tmp-sqlalchemy-branch/Mailman/Cgi/options.py 2006-12-29
04:34:52 UTC (rev 8121)
@@ -20,7 +20,6 @@
import os
import cgi
import sys
-import signal
import urllib
import logging
@@ -369,13 +368,6 @@
_('Addresses may not be blank'))
print doc.Format()
return
-
- # Standard sigterm handler.
- def sigterm_handler(signum, frame, mlist=mlist):
- mlist.Unlock()
- sys.exit(0)
-
- signal.signal(signal.SIGTERM, sigterm_handler)
if set_address:
if cpuser is None:
cpuser = user
@@ -463,15 +455,6 @@
print doc.Format()
return
- # Standard signal handler
- def sigterm_handler(signum, frame, mlist=mlist):
- mlist.Unlock()
- sys.exit(0)
-
- # Okay, zap them. Leave them sitting at the list's listinfo page. We
- # must own the list lock, and we want to make sure the user (BAW: and
- # list admin?) is informed of the removal.
- signal.signal(signal.SIGTERM, sigterm_handler)
mlist.Lock()
needapproval = False
try:
@@ -582,7 +565,6 @@
# Now, lock the list and perform the changes
mlist.Lock()
try:
- signal.signal(signal.SIGTERM, sigterm_handler)
# `values' is a tuple of flags and the web values
for flag, newval in newvals:
# Handle language settings differently
@@ -926,23 +908,10 @@
def change_password(mlist, user, newpw, confirmpw):
- # This operation requires the list lock, so let's set up the signal
- # handling so the list lock will get released when the user hits the
- # browser stop button.
- def sigterm_handler(signum, frame, mlist=mlist):
- # Make sure the list gets unlocked...
- mlist.Unlock()
- # ...and ensure we exit, otherwise race conditions could cause us to
- # enter MailList.Save() while we're in the unlocked state, and that
- # could be bad!
- sys.exit(0)
-
# Must own the list lock!
mlist.Lock()
try:
- # Install the emergency shutdown signal handler
- signal.signal(signal.SIGTERM, sigterm_handler)
- # change the user's password. The password must already have been
+ # Change the user's password. The password must already have been
# compared to the confirmpw and otherwise been vetted for
# acceptability.
mlist.setMemberPassword(user, newpw)
@@ -973,9 +942,6 @@
# Must own the list lock!
mlist.Lock()
try:
- # Install the emergency shutdown signal handler
- signal.signal(signal.SIGTERM, sigterm_handler)
-
if globalopts.enable is not None:
mlist.setDeliveryStatus(user, globalopts.enable)
Modified: branches/tmp-sqlalchemy-branch/Mailman/Cgi/subscribe.py
===================================================================
--- branches/tmp-sqlalchemy-branch/Mailman/Cgi/subscribe.py 2006-12-28
00:17:26 UTC (rev 8120)
+++ branches/tmp-sqlalchemy-branch/Mailman/Cgi/subscribe.py 2006-12-29
04:34:52 UTC (rev 8121)
@@ -20,7 +20,6 @@
import os
import cgi
import sys
-import signal
import logging
from Mailman import Errors
@@ -76,27 +75,8 @@
i18n.set_language(language)
doc.set_language(language)
- # We need a signal handler to catch the SIGTERM that can come from Apache
- # when the user hits the browser's STOP button. See the comment in
- # admin.py for details.
- #
- # BAW: Strictly speaking, the list should not need to be locked just to
- # read the request database. However the request database asserts that
- # the list is locked in order to load it and it's not worth complicating
- # that logic.
- def sigterm_handler(signum, frame, mlist=mlist):
- # Make sure the list gets unlocked...
- mlist.Unlock()
- # ...and ensure we exit, otherwise race conditions could cause us to
- # enter MailList.Save() while we're in the unlocked state, and that
- # could be bad!
- sys.exit(0)
-
mlist.Lock()
try:
- # Install the emergency shutdown signal handler
- signal.signal(signal.SIGTERM, sigterm_handler)
-
process_form(mlist, doc, cgidata, language)
mlist.Save()
finally:
Modified: branches/tmp-sqlalchemy-branch/Mailman/Queue/HTTPRunner.py
===================================================================
--- branches/tmp-sqlalchemy-branch/Mailman/Queue/HTTPRunner.py 2006-12-28
00:17:26 UTC (rev 8120)
+++ branches/tmp-sqlalchemy-branch/Mailman/Queue/HTTPRunner.py 2006-12-29
04:34:52 UTC (rev 8121)
@@ -61,6 +61,8 @@
qlog.info('HTTPRunner qrunner started.')
-server.serve_forever()
-# We'll never get here, but just in case...
-qlog.info('HTTPRunner qrunner exiting.')
+try:
+ server.serve_forever()
+except:
+ qlog.exception('HTTPRunner qrunner exiting.')
+ raise
Modified: branches/tmp-sqlalchemy-branch/Mailman/bin/mailmanctl.py
===================================================================
--- branches/tmp-sqlalchemy-branch/Mailman/bin/mailmanctl.py 2006-12-28
00:17:26 UTC (rev 8120)
+++ branches/tmp-sqlalchemy-branch/Mailman/bin/mailmanctl.py 2006-12-29
04:34:52 UTC (rev 8121)
@@ -456,8 +456,8 @@
# error!)
restarting = ''
if opts.restart:
- if ((exitstatus == None and killsig <> signal.SIGTERM) or
- (killsig == None and exitstatus <> signal.SIGTERM)):
+ if ((exitstatus is None and killsig <> signal.SIGTERM) or
+ (killsig is None and exitstatus <> signal.SIGTERM)):
# Then
restarting = '[restarting]'
qrname, slice, count, restarts = kids[pid]
Modified: branches/tmp-sqlalchemy-branch/Mailman/bin/qrunner.py
===================================================================
--- branches/tmp-sqlalchemy-branch/Mailman/bin/qrunner.py 2006-12-28
00:17:26 UTC (rev 8120)
+++ branches/tmp-sqlalchemy-branch/Mailman/bin/qrunner.py 2006-12-29
04:34:52 UTC (rev 8121)
@@ -182,13 +182,11 @@
global log, opts
parser, opts, args = parseargs()
- initialize(opts.config)
-
# If we're not running as a subprocess of mailmanctl, then we'll log to
# stderr in addition to logging to the log files. We do this by passing a
# value of True to propagate, which allows the 'mailman' root logger to
# see the log messages.
- loginit.initialize(propagate=not opts.subproc)
+ initialize(opts.config, propagate_logs=not opts.subproc)
log = logging.getLogger('mailman.qrunner')
if opts.list:
Modified: branches/tmp-sqlalchemy-branch/Mailman/loginit.py
===================================================================
--- branches/tmp-sqlalchemy-branch/Mailman/loginit.py 2006-12-28 00:17:26 UTC
(rev 8120)
+++ branches/tmp-sqlalchemy-branch/Mailman/loginit.py 2006-12-29 04:34:52 UTC
(rev 8121)
@@ -1,132 +1,133 @@
-# Copyright (C) 2006 by the Free Software Foundation, Inc.
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
USA.
-
-"""Logging initialization, using Python's standard logging package.
-
-This module cannot be called 'logging' because that would interfere with the
-import below. Ah, for Python 2.5 and absolute imports.
-"""
-
-import os
-import codecs
-import logging
-
-from Mailman.configuration import config
-
-FMT = '%(asctime)s (%(process)d) %(message)s'
-DATEFMT = '%b %d %H:%M:%S %Y'
-LOGGERS = (
- 'bounce',
- 'config',
- 'debug',
- 'error',
- 'fromusenet',
- 'http',
- 'locks',
- 'mischief',
- 'post',
- 'qrunner',
- 'smtp',
- 'smtp-failure',
- 'subscribe',
- 'vette',
- )
-
-_handlers = []
-
-
-
-class ReopenableFileHandler(logging.Handler):
- def __init__(self, filename):
- self._filename = filename
- self._stream = self._open()
- logging.Handler.__init__(self)
-
- def _open(self):
- return codecs.open(self._filename, 'a', 'utf-8')
-
- def flush(self):
- self._stream.flush()
-
- def emit(self, record):
- try:
- msg = self.format(record)
- fs = '%s\n'
- try:
- self._stream.write(fs % msg)
- except UnicodeError:
- self._stream.write(fs % msg.encode('string-escape'))
- self.flush()
- except:
- self.handleError(record)
-
- def close(self):
- self.flush()
- self._stream.close()
- logging.Handler.close(self)
-
- def reopen(self):
- self._stream.close()
- self._stream = self._open()
-
-
-
-def initialize(propagate=False):
- # XXX Don't call logging.basicConfig() because in Python 2.3, it adds a
- # handler to the root logger that we don't want. When Python 2.4 is the
- # minimum requirement, we can use basicConfig() with keyword arguments.
- #
- # The current set of Mailman logs are:
- #
- # error - All exceptions go to this log
- # bounce - All bounce processing logs go here
- # mischief - Various types of hostile activity
- # post - Information about messages posted to mailing lists
- # vette - Information related to admindb activity
- # smtp - Successful SMTP activity
- # smtp-failure - Unsuccessful SMTP activity
- # subscribe - Information about leaves/joins
- # config - Configuration issues
- # locks - Lock steals
- # qrunner - qrunner start/stops
- # fromusenet - Information related to the Usenet to Mailman gateway
- #
- # There was also a 'debug' logger, but that was mostly unused, so instead
- # we'll use debug level on existing loggers.
- #
- # Start by creating a common formatter and the root logger.
- formatter = logging.Formatter(fmt=FMT, datefmt=DATEFMT)
- log = logging.getLogger('mailman')
- handler = logging.StreamHandler()
- handler.setFormatter(formatter)
- log.addHandler(handler)
- log.setLevel(logging.INFO)
- # Create the subloggers
- for logger in LOGGERS:
- log = logging.getLogger('mailman.' + logger)
- # Propagation to the root logger is how we handle logging to stderr
- # when the qrunners are not run as a subprocess of mailmanctl.
- log.propagate = propagate
- handler = ReopenableFileHandler(os.path.join(config.LOG_DIR, logger))
- _handlers.append(handler)
- handler.setFormatter(formatter)
- log.addHandler(handler)
-
-
-
-def reopen():
- for handler in _handlers:
- handler.reopen()
+# Copyright (C) 2006 by the Free Software Foundation, Inc.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+# USA.
+
+"""Logging initialization, using Python's standard logging package.
+
+This module cannot be called 'logging' because that would interfere with the
+import below. Ah, for Python 2.5 and absolute imports.
+"""
+
+import os
+import codecs
+import logging
+
+from Mailman.configuration import config
+
+FMT = '%(asctime)s (%(process)d) %(message)s'
+DATEFMT = '%b %d %H:%M:%S %Y'
+LOGGERS = (
+ 'bounce',
+ 'config',
+ 'debug',
+ 'error',
+ 'fromusenet',
+ 'http',
+ 'locks',
+ 'mischief',
+ 'post',
+ 'qrunner',
+ 'smtp',
+ 'smtp-failure',
+ 'subscribe',
+ 'vette',
+ )
+
+_handlers = []
+
+
+
+class ReopenableFileHandler(logging.Handler):
+ def __init__(self, filename):
+ self._filename = filename
+ self._stream = self._open()
+ logging.Handler.__init__(self)
+
+ def _open(self):
+ return codecs.open(self._filename, 'a', 'utf-8')
+
+ def flush(self):
+ self._stream.flush()
+
+ def emit(self, record):
+ try:
+ msg = self.format(record)
+ fs = '%s\n'
+ try:
+ self._stream.write(fs % msg)
+ except UnicodeError:
+ self._stream.write(fs % msg.encode('string-escape'))
+ self.flush()
+ except:
+ self.handleError(record)
+
+ def close(self):
+ self.flush()
+ self._stream.close()
+ logging.Handler.close(self)
+
+ def reopen(self):
+ self._stream.close()
+ self._stream = self._open()
+
+
+
+def initialize(propagate=False):
+ # XXX Don't call logging.basicConfig() because in Python 2.3, it adds a
+ # handler to the root logger that we don't want. When Python 2.4 is the
+ # minimum requirement, we can use basicConfig() with keyword arguments.
+ #
+ # The current set of Mailman logs are:
+ #
+ # error - All exceptions go to this log
+ # bounce - All bounce processing logs go here
+ # mischief - Various types of hostile activity
+ # post - Information about messages posted to mailing lists
+ # vette - Information related to admindb activity
+ # smtp - Successful SMTP activity
+ # smtp-failure - Unsuccessful SMTP activity
+ # subscribe - Information about leaves/joins
+ # config - Configuration issues
+ # locks - Lock steals
+ # qrunner - qrunner start/stops
+ # fromusenet - Information related to the Usenet to Mailman gateway
+ #
+ # There was also a 'debug' logger, but that was mostly unused, so instead
+ # we'll use debug level on existing loggers.
+ #
+ # Start by creating a common formatter and the root logger.
+ formatter = logging.Formatter(fmt=FMT, datefmt=DATEFMT)
+ log = logging.getLogger('mailman')
+ handler = logging.StreamHandler()
+ handler.setFormatter(formatter)
+ log.addHandler(handler)
+ log.setLevel(logging.INFO)
+ # Create the subloggers
+ for logger in LOGGERS:
+ log = logging.getLogger('mailman.' + logger)
+ # Propagation to the root logger is how we handle logging to stderr
+ # when the qrunners are not run as a subprocess of mailmanctl.
+ log.propagate = propagate
+ handler = ReopenableFileHandler(os.path.join(config.LOG_DIR, logger))
+ _handlers.append(handler)
+ handler.setFormatter(formatter)
+ log.addHandler(handler)
+
+
+
+def reopen():
+ for handler in _handlers:
+ handler.reopen()
Modified: branches/tmp-sqlalchemy-branch/scripts/driver
===================================================================
--- branches/tmp-sqlalchemy-branch/scripts/driver 2006-12-28 00:17:26 UTC
(rev 8120)
+++ branches/tmp-sqlalchemy-branch/scripts/driver 2006-12-29 04:34:52 UTC
(rev 8121)
@@ -98,6 +98,8 @@
pkg = __import__('Mailman.Cgi', globals(), locals(), [scriptname])
module = getattr(pkg, scriptname)
main = getattr(module, 'main')
+ import signal
+ signal.signal(signal.SIGTERM, sigterm_handler)
try:
try:
sys.stdout = tempstdout
@@ -197,6 +199,7 @@
print >> outfp, 'sys.exec_prefix =', sys.exec_prefix
print >> outfp, 'sys.path =', sys.exec_prefix
print >> outfp, 'sys.platform =', sys.platform
+ print >> outfp, 'args =', SPACE.join(sys.argv)
# Write the same information to the HTML sink.
if not STEALTH_MODE:
@@ -275,3 +278,37 @@
this site.
"""
print >> sys.__stderr__, '[Mailman: low level unrecoverable exception]'
+
+
+
+# Signal handler to guarantee that, when running under traditional CGI, a
+# locked mailing list will be unlocked when a fatal signal is received.
+#
+# try/finally isn't enough because of this scenario: user hits a CGI page
+# which may take a long time to render; user gets bored and hits the browser's
+# STOP button; browser shuts down socket; server tries to write to broken
+# socket and gets a SIGPIPE. Under Apache 1.3/mod_cgi, Apache catches this
+# SIGPIPE (I presume it is buffering output from the cgi script), then turns
+# around and SIGTERMs the cgi process. Apache waits three seconds and then
+# SIGKILLs the cgi process. We /must/ catch the SIGTERM and do the most
+# reasonable thing we can in as short a time period as possible. If we get
+# the SIGKILL we're screwed because it's uncatchable and we'll have no
+# opportunity to clean up after ourselves.
+#
+# This signal handler catches the SIGTERM, unlocks the list, and then
+# exits the process. The effect of this is that the changes made to the
+# MailList object will be aborted, which seems like the only sensible
+# semantics.
+#
+# Note that we must not install this signal handler when running under the
+# HTTPRunner wsgi server because the sys.exit(0) will cause the supervisor
+# mailmanctl process to restart the HTTPRunner. When running in that
+# environment, just let the normal signal handling do the right thing.
+def sigterm_handler(signum, frame, mlist=mlist):
+ # Make sure the list gets unlocked...
+ if mlist.Locked():
+ mlist.Unlock()
+ # ...and ensure we exit, otherwise race conditions could cause us to
+ # enter MailList.Save() while we're in the unlocked state, and that
+ # could be bad!
+ sys.exit(0)
This was sent by the SourceForge.net collaborative development platform, the
world's largest Open Source development site.
_______________________________________________
Mailman-checkins mailing list
[email protected]
Unsubscribe:
http://mail.python.org/mailman/options/mailman-checkins/archive%40jab.org