diff options
Diffstat (limited to 'src/mailman/archiving/prototype.py')
| -rw-r--r-- | src/mailman/archiving/prototype.py | 59 |
1 files changed, 57 insertions, 2 deletions
diff --git a/src/mailman/archiving/prototype.py b/src/mailman/archiving/prototype.py index 55d78074e..453c6c770 100644 --- a/src/mailman/archiving/prototype.py +++ b/src/mailman/archiving/prototype.py @@ -25,11 +25,22 @@ __all__ = [ ] +import os +import errno +import logging + +from datetime import timedelta +from mailbox import Maildir from urlparse import urljoin + +from flufl.lock import Lock, TimeOutError from zope.interface import implements +from mailman.config import config from mailman.interfaces.archiver import IArchiver +log = logging.getLogger('mailman.error') + class Prototype: @@ -61,5 +72,49 @@ class Prototype: @staticmethod def archive_message(mlist, message): - """See `IArchiver`.""" - raise NotImplementedError + """See `IArchiver`. + + This archiver saves messages into a maildir. + """ + archive_dir = os.path.join(config.ARCHIVE_DIR, 'prototype') + try: + os.makedirs(archive_dir, 0775) + except OSError as error: + # If this already exists, then we're fine + if error.errno != errno.EEXIST: + raise + + # Maildir will throw an error if the directories are partially created + # (for instance the toplevel exists but cur, new, or tmp do not) + # therefore we don't create the toplevel as we did above. + list_dir = os.path.join(archive_dir, mlist.fqdn_listname) + mailbox = Maildir(list_dir, create=True, factory=None) + lock_file = os.path.join( + config.LOCK_DIR, '{0}-maildir.lock'.format(mlist.fqdn_listname)) + + # Lock the maildir as Maildir.add() is not threadsafe. Don't use the + # context manager because it's not an error if we can't acquire the + # archiver lock. We'll just log the problem and continue. + # + # XXX 2012-03-14 BAW: When we extend the chain/pipeline architecture + # to other runners, e.g. the archive runner, it would be better to let + # any TimeOutError propagate up. That would cause the message to be + # re-queued and tried again later, rather than being discarded as + # happens now below. + lock = Lock(lock_file) + try: + lock.lock(timeout=timedelta(seconds=1)) + # Add the message to the maildir. The return value could be used + # to construct the file path if necessary. E.g. + # + # os.path.join(archive_dir, mlist.fqdn_listname, 'new', + # message_key) + mailbox.add(message) + except TimeOutError: + # Log the error and go on. + log.error('Unable to acquire prototype archiver lock for {0}, ' + 'discarding: {1}'.format( + mlist.fqdn_listname, + message.get('message-id', 'n/a'))) + finally: + lock.unlock(unconditionally=True) |
