[FIX] mail.mail: avoid prefetching attachment data in memory while processing mail...
authorOlivier Dony <odo@openerp.com>
Fri, 2 May 2014 14:44:31 +0000 (16:44 +0200)
committerOlivier Dony <odo@openerp.com>
Fri, 2 May 2014 14:44:31 +0000 (16:44 +0200)
Specifically when there are many emails in the queue, prefetching
all their attachments at once when processing the first one
could fail, so not even one mail would be sent.

Added explicit logging when an email triggers a MemoryError,
as well as logging when each email is successfully sent.

bzr revid: odo@openerp.com-20140502144431-r3brgagl4gel4wmt

addons/mail/mail_mail.py

index f984f8f..0bd1537 100644 (file)
@@ -240,13 +240,17 @@ class mail_mail(osv.Model):
             :return: True
         """
         ir_mail_server = self.pool.get('ir.mail_server')
+        ir_attachment = self.pool['ir.attachment']
                 
         for mail in self.browse(cr, SUPERUSER_ID, ids, context=context):
             try:
-                # handle attachments
-                attachments = []
-                for attach in mail.attachment_ids:
-                    attachments.append((attach.datas_fname, base64.b64decode(attach.datas)))
+                # load attachment binary data with a separate read(), as prefetching all
+                # `datas` (binary field) could bloat the browse cache, triggerring
+                # soft/hard mem limits with temporary data.
+                attachment_ids = [a.id for a in mail.attachment_ids]
+                attachments = ((a['datas_fname'], base64.b64decode(a['datas']))
+                                 for a in ir_attachment.read(cr, uid, attachment_ids,
+                                                             ['datas_fname', 'datas']))
                 # specific behavior to customize the send email for notified partners
                 email_list = []
                 if mail.email_to:
@@ -295,10 +299,14 @@ class mail_mail(osv.Model):
                 # /!\ can't use mail.state here, as mail.refresh() will cause an error
                 # see revid:odo@openerp.com-20120622152536-42b2s28lvdv3odyr in 6.1
                 if mail_sent:
+                    _logger.info('Mail with ID %r and Message-Id %r successfully sent', mail.id, mail.message_id)
                     self._postprocess_sent_message(cr, uid, mail, context=context)
             except MemoryError:
                 # prevent catching transient MemoryErrors, bubble up to notify user or abort cron job
                 # instead of marking the mail as failed
+                _logger.exception('MemoryError while processing mail with ID %r and Msg-Id %r. '\
+                                      'Consider raising the --limit-memory-hard startup option',
+                                  mail.id, mail.message_id)
                 raise
             except Exception as e:
                 _logger.exception('failed sending mail.mail %s', mail.id)