← Back to team overview

credativ team mailing list archive

[Branch ~credativ/openobject-addons/6.1] Rev 7079: [FIX] Lock obtained on mail_message before sending e-mail

 

------------------------------------------------------------
revno: 7079
committer: Tom Pickering <tom.pickering@xxxxxxxxxxxxxx>
branch nick: 6.1
timestamp: Wed 2016-09-07 10:13:19 +0100
message:
  [FIX] Lock obtained on mail_message before sending e-mail
modified:
  mail/mail_message.py


--
lp:~credativ/openobject-addons/6.1
https://code.launchpad.net/~credativ/openobject-addons/6.1

Your team credativ is subscribed to branch lp:~credativ/openobject-addons/6.1.
To unsubscribe from this branch go to https://code.launchpad.net/~credativ/openobject-addons/6.1/+edit-subscription
=== modified file 'mail/mail_message.py'
--- mail/mail_message.py	2015-02-03 13:54:34 +0000
+++ mail/mail_message.py	2016-09-07 09:13:19 +0000
@@ -24,18 +24,23 @@
 import datetime
 import dateutil.parser
 import email
+import pooler
 import logging
 import pytz
 import re
 import time
 from email.header import decode_header
 from email.message import Message
+from contextlib import closing
 
 import tools
 from osv import osv
 from osv import fields
 from tools.translate import _
 from openerp import SUPERUSER_ID
+
+from psycopg2 import OperationalError
+
 try:
     from openerp.addons.base.ir.ir_mail_server import MailTransientDeliveryException
 except:
@@ -505,63 +510,72 @@
         if context is None:
             context = {}
         ir_mail_server = self.pool.get('ir.mail_server')
-        self.write(cr, uid, ids, {'state': 'outgoing'}, context=context)
-        for message in self.browse(cr, uid, ids, context=context):
-            try:
-                attachments = []
-                for attach in message.attachment_ids:
-                    attachments.append((attach.datas_fname, base64.b64decode(attach.datas)))
-
-                body = message.body_html if message.subtype == 'html' else message.body_text
-                body_alternative = None
-                subtype_alternative = None
-                if message.subtype == 'html' and message.body_text:
-                    # we have a plain text alternative prepared, pass it to 
-                    # build_message instead of letting it build one
-                    body_alternative = message.body_text
-                    subtype_alternative = 'plain'
-
-                msg = ir_mail_server.build_email(
-                    email_from=message.email_from,
-                    email_to=to_email(message.email_to),
-                    subject=message.subject,
-                    body=body,
-                    body_alternative=body_alternative,
-                    email_cc=to_email(message.email_cc),
-                    email_bcc=to_email(message.email_bcc),
-                    reply_to=message.reply_to,
-                    attachments=attachments, message_id=message.message_id,
-                    references = message.references,
-                    object_id=message.res_id and ('%s-%s' % (message.res_id,message.model)),
-                    subtype=message.subtype,
-                    subtype_alternative=subtype_alternative,
-                    headers=message.headers and ast.literal_eval(message.headers))
-                res = ir_mail_server.send_email(cr, uid, msg,
-                                                mail_server_id=message.mail_server_id.id,
-                                                context=context)
-                if res:
-                    message.write({'state':'sent', 'message_id': res})
-                    message_sent = True
-                else:
+        for msg_id in ids:
+            with closing(pooler.get_db(cr.dbname).cursor()) as _cr:
+                try:
+                    _cr.execute('SELECT * FROM mail_message WHERE id = %s FOR UPDATE NOWAIT', [msg_id])
+                    message = self.browse(_cr, uid, msg_id, context=context)
+                    self.write(_cr, uid, msg_id, {'state': 'outgoing'}, context=context)
+
+                    attachments = []
+                    for attach in message.attachment_ids:
+                        attachments.append((attach.datas_fname, base64.b64decode(attach.datas)))
+
+                    body = message.body_html if message.subtype == 'html' else message.body_text
+                    body_alternative = None
+                    subtype_alternative = None
+                    if message.subtype == 'html' and message.body_text:
+                        # we have a plain text alternative prepared, pass it to 
+                        # build_message instead of letting it build one
+                        body_alternative = message.body_text
+                        subtype_alternative = 'plain'
+
+                    msg = ir_mail_server.build_email(
+                        email_from=message.email_from,
+                        email_to=to_email(message.email_to),
+                        subject=message.subject,
+                        body=body,
+                        body_alternative=body_alternative,
+                        email_cc=to_email(message.email_cc),
+                        email_bcc=to_email(message.email_bcc),
+                        reply_to=message.reply_to,
+                        attachments=attachments, message_id=message.message_id,
+                        references = message.references,
+                        object_id=message.res_id and ('%s-%s' % (message.res_id,message.model)),
+                        subtype=message.subtype,
+                        subtype_alternative=subtype_alternative,
+                        headers=message.headers and ast.literal_eval(message.headers))
+                    res = ir_mail_server.send_email(_cr, uid, msg,
+                                                    mail_server_id=message.mail_server_id.id,
+                                                    context=context)
+                    if res:
+                        message.write({'state':'sent', 'message_id': res})
+                        message_sent = True
+                    else:
+                        message.write({'state':'exception'})
+                        message_sent = False
+
+                    # if auto_delete=True then delete that sent messages as well as attachments
+                    if message_sent and message.auto_delete:
+                        self.pool.get('ir.attachment').unlink(_cr, uid,
+                                                              [x.id for x in message.attachment_ids \
+                                                                    if x.res_model == self._name and \
+                                                                       x.res_id == message.id],
+                                                              context=context)
+                        message.unlink()
+
+                    _cr.commit()
+                except MailTransientDeliveryException:
+                    pass
+                except OperationalError:
+                    _logger.exception('failed sending mail.message %s and unable to update state', msg_id)
+                    # We can't use this cursor any more - attempting to updating
+                    # the message state will just throw a new exception.
+                except Exception:
+                    _logger.exception('failed sending mail.message %s', msg_id)
                     message.write({'state':'exception'})
-                    message_sent = False
-
-                # if auto_delete=True then delete that sent messages as well as attachments
-                if message_sent and message.auto_delete:
-                    self.pool.get('ir.attachment').unlink(cr, uid,
-                                                          [x.id for x in message.attachment_ids \
-                                                                if x.res_model == self._name and \
-                                                                   x.res_id == message.id],
-                                                          context=context)
-                    message.unlink()
-            except MailTransientDeliveryException:
-                pass
-            except Exception:
-                _logger.exception('failed sending mail.message %s', message.id)
-                message.write({'state':'exception'})
-
-            if auto_commit == True:
-                cr.commit()
+                    _cr.commit()
+
         return True
 
     def cancel(self, cr, uid, ids, context=None):