[Checkins] SVN: zope.sendmail/branches/3.5/ Backported c103980 - fixing LP 413335

Hanno Schlichting hannosch at hannosch.eu
Tue Apr 5 07:29:43 EDT 2011


Log message for revision 121280:
  Backported c103980 - fixing LP 413335
  

Changed:
  U   zope.sendmail/branches/3.5/CHANGES.txt
  U   zope.sendmail/branches/3.5/src/zope/sendmail/delivery.py

-=-
Modified: zope.sendmail/branches/3.5/CHANGES.txt
===================================================================
--- zope.sendmail/branches/3.5/CHANGES.txt	2011-04-05 08:40:00 UTC (rev 121279)
+++ zope.sendmail/branches/3.5/CHANGES.txt	2011-04-05 11:29:42 UTC (rev 121280)
@@ -4,6 +4,8 @@
 3.5.3 (unreleased)
 ------------------
 
+- Work around problem when used with Python >=2.5.1.  See
+  https://bugs.edge.launchpad.net/zope.sendmail/+bug/413335.
 
 3.5.2 (2010-10-01)
 ------------------

Modified: zope.sendmail/branches/3.5/src/zope/sendmail/delivery.py
===================================================================
--- zope.sendmail/branches/3.5/src/zope/sendmail/delivery.py	2011-04-05 08:40:00 UTC (rev 121279)
+++ zope.sendmail/branches/3.5/src/zope/sendmail/delivery.py	2011-04-05 11:29:42 UTC (rev 121280)
@@ -212,12 +212,14 @@
     """
 
     log = logging.getLogger("QueueProcessorThread")
-    __stopped = False
+    _stopped = False
     interval = 3.0   # process queue every X second
 
     def __init__(self, interval=3.0):
         threading.Thread.__init__(self)
         self.interval = interval
+        self._lock = threading.Lock()
+        self.setDaemon(True)
 
     def setMaildir(self, maildir):
         """Set the maildir.
@@ -260,10 +262,10 @@
 
     def run(self, forever=True):
         atexit.register(self.stop)
-        while not self.__stopped:
+        while not self._stopped:
             for filename in self.maildir:
                 # if we are asked to stop while sending messages, do so
-                if self.__stopped:
+                if self._stopped:
                     break
 
                 fromaddr = ''
@@ -349,32 +351,48 @@
                     message = file.read()
                     file.close()
                     fromaddr, toaddrs, message = self._parseMessage(message)
+                    # The next block is the only one that is sensitive to
+                    # interruptions.  Everywhere else, if this daemon thread
+                    # stops, we should be able to correctly handle a restart.
+                    # In this block, if we send the message, but we are
+                    # stopped before we unlink the file, we will resend the
+                    # message when we are restarted.  We limit the likelihood
+                    # of this somewhat by using a lock to link the two
+                    # operations.  When the process gets an interrupt, it
+                    # will call the atexit that we registered (``stop``
+                    # below).  This will try to get the same lock before it
+                    # lets go.  Because this can cause the daemon thread to
+                    # continue (that is, to not act like a daemon thread), we
+                    # still use the _stopped flag to communicate.
+                    self._lock.acquire()
                     try:
-                        self.mailer.send(fromaddr, toaddrs, message)
-                    except smtplib.SMTPResponseException, e:
-                        if 500 <= e.smtp_code <= 599:
-                            # permanent error, ditch the message
-                            self.log.error(
-                                "Discarding email from %s to %s due to"
-                                " a permanent error: %s",
-                                fromaddr, ", ".join(toaddrs), str(e))
-                            #os.link(filename, rejected_filename)
-                            _os_link(filename, rejected_filename)
-                        else:
-                            # Log an error and retry later
-                            raise
+                        try:
+                            self.mailer.send(fromaddr, toaddrs, message)
+                        except smtplib.SMTPResponseException, e:
+                            if 500 <= e.smtp_code <= 599:
+                                # permanent error, ditch the message
+                                self.log.error(
+                                    "Discarding email from %s to %s due to"
+                                    " a permanent error: %s",
+                                    fromaddr, ", ".join(toaddrs), str(e))
+                                #os.link(filename, rejected_filename)
+                                _os_link(filename, rejected_filename)
+                            else:
+                                # Log an error and retry later
+                                raise
 
+                        try:
+                            os.unlink(filename)
+                        except OSError, e:
+                            if e.errno == 2: # file does not exist
+                                # someone else unlinked the file; oh well
+                                pass
+                            else:
+                                # something bad happend, log it
+                                raise
+                    finally:
+                        self._lock.release()
                     try:
-                        os.unlink(filename)
-                    except OSError, e:
-                        if e.errno == 2: # file does not exist
-                            # someone else unlinked the file; oh well
-                            pass
-                        else:
-                            # something bad happend, log it
-                            raise
-
-                    try:
                         os.unlink(tmp_filename)
                     except OSError, e:
                         if e.errno == 2: # file does not exist
@@ -407,4 +425,6 @@
                 break
 
     def stop(self):
-        self.__stopped = True
+        self._stopped = True
+        self._lock.acquire()
+        self._lock.release()



More information about the checkins mailing list