diff options
Diffstat (limited to 'Mailman/Queue')
-rw-r--r-- | Mailman/Queue/Runner.py | 40 | ||||
-rw-r--r-- | Mailman/Queue/Switchboard.py | 23 |
2 files changed, 46 insertions, 17 deletions
diff --git a/Mailman/Queue/Runner.py b/Mailman/Queue/Runner.py index e229043e..1724f043 100644 --- a/Mailman/Queue/Runner.py +++ b/Mailman/Queue/Runner.py @@ -1,4 +1,4 @@ -# Copyright (C) 1998-2006 by the Free Software Foundation, Inc. +# Copyright (C) 1998-2007 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 @@ -98,16 +98,17 @@ class Runner: # Ask the switchboard for the message and metadata objects # associated with this filebase. msg, msgdata = self._switchboard.dequeue(filebase) - except email.Errors.MessageParseError, e: - # It's possible to get here if the message was stored in the - # pickle in plain text, and the metadata had a _parsemsg key - # that was true, /and/ if the message had some bogosity in - # it. It's almost always going to be spam or bounced spam. - # There's not much we can do (and we didn't even get the - # metadata, so just log the exception and continue. + except Exception, e: + # This used to just catch email.Errors.MessageParseError, + # but other problems can occur in message parsing, e.g. + # ValueError, and exceptions can occur in unpickling too. + # We don't want the runner to die, so we just log and skip + # this entry, but preserve it for analysis. self._log(e) - syslog('error', 'Ignoring unparseable message: %s', filebase) - self._switchboard.finish(filebase) + syslog('error', + 'Skipping and preserving unparseable message: %s', + filebase) + self._switchboard.finish(filebase, preserve=True) continue try: self._onefile(msg, msgdata) @@ -122,9 +123,22 @@ class Runner: self._log(e) # Put a marker in the metadata for unshunting msgdata['whichq'] = self._switchboard.whichq() - new_filebase = self._shunt.enqueue(msg, msgdata) - syslog('error', 'SHUNTING: %s', new_filebase) - self._switchboard.finish(filebase) + # It is possible that shunting can throw an exception, e.g. a + # permissions problem or a MemoryError due to a really large + # message. Try to be graceful. + try: + new_filebase = self._shunt.enqueue(msg, msgdata) + syslog('error', 'SHUNTING: %s', new_filebase) + self._switchboard.finish(filebase) + except Exception, e: + # The message wasn't successfully shunted. Log the + # exception and try to preserve the original queue entry + # for possible analysis. + self._log(e) + syslog('error', + 'SHUNTING FAILED, preserving original entry: %s', + filebase) + self._switchboard.finish(filebase, preserve=True) # Other work we want to do each time through the loop Utils.reap(self._kids, once=True) self._doperiodic() diff --git a/Mailman/Queue/Switchboard.py b/Mailman/Queue/Switchboard.py index 9a45280d..84e8a5e3 100644 --- a/Mailman/Queue/Switchboard.py +++ b/Mailman/Queue/Switchboard.py @@ -1,4 +1,4 @@ -# Copyright (C) 2001-2006 by the Free Software Foundation, Inc. +# Copyright (C) 2001-2007 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 @@ -164,12 +164,27 @@ class Switchboard: msg = email.message_from_string(msg, Message.Message) return msg, data - def finish(self, filebase): + def finish(self, filebase, preserve=False): bakfile = os.path.join(self.__whichq, filebase + '.bak') try: - os.unlink(bakfile) + if preserve: + psvfile = os.path.join(mm_cfg.SHUNTQUEUE_DIR, filebase + '.psv') + # Create the directory if it doesn't yet exist. + # Copied from __init__. + omask = os.umask(0) # rwxrws--- + try: + try: + os.mkdir(mm_cfg.SHUNTQUEUE_DIR, 0770) + except OSError, e: + if e.errno <> errno.EEXIST: raise + finally: + os.umask(omask) + os.rename(bakfile, psvfile) + else: + os.unlink(bakfile) except EnvironmentError, e: - syslog('error', 'Failed to unlink backup file: %s', bakfile) + syslog('error', 'Failed to unlink/preserve backup file: %s', + bakfile) def files(self, extension='.pck'): times = {} |