[Zope] oddity in MailHost queue processor thread

Maric Michaud maric at aristote.info
Fri Apr 30 07:44:19 EDT 2010


Hi all,

I was surprised by the behavior of asynchronous mailing in zope 2.11.3 
MailHost product. It creates a thread by instance of MailHost by the 
mean of using self.absolute_url(1) as key for the queue_threads dictionnary.

It seems obviously wrong, IMO, if several instances share the same queue 
  directory, mesages actually get sent more than once.

Following is the monkey patch which works fine for me, but the idea is 
straightforward, it's to use the realpath of the smtp_queue_directory as 
the identifier of the thread, ensuring that MailHosts that share the 
same queue directory will also share the same thread for processing mails.

regards,


# un monkey patch du mailhost de zope2.11, ce dernier utilise une thread
# par instance de mailhost pour la getsion de la queue de messages, ce n'est
# pas correct, il faut qu'il garantisse qu'il n'y a qu'une thread par
# répertoire réel de queue.
from Products.MailHost import MailHost as mh
if not hasattr(mh.MailBase, '_cfenet_patched_queueThreadAlive'):
     mh.MailBase._cfenet_patched_queueThreadAlive = 
mh.MailBase.queueThreadAlive
     def queueThreadAlive(self):
         """return True/False is queue thread is working"""
         from Products.MailHost import MailHost as mh
         from os.path import realpath
         # Il est important d'avoir un mailer unique par répertoire
         th = mh.queue_threads.get(realpath(self.smtp_queue_directory))
         return th and th.isAlive()
     mh.MailBase.queueThreadAlive = queueThreadAlive

if not hasattr(mh.MailBase, '_cfenet_patched__stopQueueProcessorThread'):
     mh.MailBase._cfenet_patched__stopQueueProcessorThread = \
 
mh.MailBase._stopQueueProcessorThread
     @mh.synchronized(mh.MailBase.lock)
     def _stopQueueProcessorThread(self):
         """ Stop thread for processing the mail queue """
         from Products.MailHost import MailHost as mh
         from os.path import realpath
         path = realpath(self.smtp_queue_directory)
         if mh.queue_threads.has_key(path):
             th = mh.queue_threads[path]
             th.stop()
             while th.isAlive():
                 # wait until thread is really dead
                 mh.time.sleep(0.3)
             del mh.queue_threads[path]
             mh.LOG.info('Thread for %s stopped' % path)
     mh.MailBase._stopQueueProcessorThread = _stopQueueProcessorThread

if not hasattr(mh.MailBase, '_cfenet_patched__startQueueProcessorThread'):
     mh.MailBase._cfenet_patched__startQueueProcessorThread = \
 
mh.MailBase._startQueueProcessorThread
     @mh.synchronized(mh.MailBase.lock)
     def _startQueueProcessorThread(self):
         """ Start thread for processing the mail queue """
         from Products.MailHost import MailHost as mh
         from os.path import realpath
         path = realpath(self.smtp_queue_directory)
         if not mh.queue_threads.has_key(path):
             th = mh.QueueProcessorThread()
             th.setMailer(self._makeMailer())
             th.setQueuePath(self.smtp_queue_directory)
             th.start()
             mh.queue_threads[path] = th
             mh.LOG.info('Thread for %s started' % path)
     mh.MailBase._startQueueProcessorThread = _startQueueProcessorThread


-- 
_____________

Maric Michaud




More information about the Zope mailing list