[FIX] reuse session between calls

This commit is contained in:
Guewen Baconnier @ Camptocamp
2012-11-26 11:09:33 +01:00
parent fbcfbb3fcc
commit 34051eb0bb
2 changed files with 153 additions and 124 deletions

View File

@@ -56,7 +56,8 @@ class Pingen(object):
def __init__(self, token, staging=True): def __init__(self, token, staging=True):
self._token = token self._token = token
self.staging = True self.staging = staging
self._session = None
super(Pingen, self).__init__() super(Pingen, self).__init__()
@property @property
@@ -65,6 +66,32 @@ class Pingen(object):
return 'https://stage-api.pingen.com' return 'https://stage-api.pingen.com'
return 'https://api.pingen.com' return 'https://api.pingen.com'
@property
def session(self):
""" Build a requests session """
if self._session is not None:
return self._session
self._session = requests.Session(
params={'token': self._token},
# with safe_mode, requests catch errors and
# returns a blank response with an error
config={'safe_mode': True},
# verify = False required for staging environment
# because the SSL certificate is wrong
verify=not self.staging)
return self._session
def __enter__(self):
return self
def __exit__(self, *args):
self.close()
def close(self):
"""Dispose of any internal state. """
if self._session:
self._session.close()
def _send(self, method, endpoint, **kwargs): def _send(self, method, endpoint, **kwargs):
""" Send a request to the pingen API using requests """ Send a request to the pingen API using requests
@@ -77,23 +104,6 @@ class Pingen(object):
""" """
complete_url = urlparse.urljoin(self.url, endpoint) complete_url = urlparse.urljoin(self.url, endpoint)
auth_param = {'token': self._token}
if 'params' in kwargs:
kwargs['params'].update(auth_param)
else:
kwargs['params'] = auth_param
# with safe_mode, requests catch errors and
# returns a blank response with an error
config = {'safe_mode': True}
if 'config' in kwargs:
kwargs['config'].update(config)
else:
kwargs['config'] = config
# verify = False required for staging environment
# because the SSL certificate is wrong
kwargs['verify'] = not self.staging
response = method(complete_url, **kwargs) response = method(complete_url, **kwargs)
if not response.ok: if not response.ok:
@@ -140,7 +150,7 @@ class Pingen(object):
multipart, content_type = encode_multipart_formdata(formdata) multipart, content_type = encode_multipart_formdata(formdata)
response = self._send( response = self._send(
requests.post, self.session.post,
'document/upload', 'document/upload',
headers={'Content-Type': content_type}, headers={'Content-Type': content_type},
data=multipart) data=multipart)
@@ -169,7 +179,7 @@ class Pingen(object):
'color': color, 'color': color,
} }
response = self._send( response = self._send(
requests.post, self.session.post,
'document/send', 'document/send',
params={'id': document_id}, params={'id': document_id},
data={'data': json.dumps(data)}) data={'data': json.dumps(data)})
@@ -183,7 +193,7 @@ class Pingen(object):
:return: dict of infos of the post :return: dict of infos of the post
""" """
response = self._send( response = self._send(
requests.get, self.session.get,
'post/get', 'post/get',
params={'id': post_id}) params={'id': post_id})

View File

@@ -25,7 +25,6 @@ from cStringIO import StringIO
from contextlib import closing from contextlib import closing
from openerp.osv import osv, orm, fields from openerp.osv import osv, orm, fields
from openerp import tools
from openerp.tools.translate import _ from openerp.tools.translate import _
from openerp import pooler from openerp import pooler
from .pingen import APIError, ConnectionError, POST_SENDING_STATUS from .pingen import APIError, ConnectionError, POST_SENDING_STATUS
@@ -91,16 +90,24 @@ class pingen_document(orm.Model):
'Only one Pingen document is allowed per attachment.'), 'Only one Pingen document is allowed per attachment.'),
] ]
def _push_to_pingen(self, cr, uid, document, context=None): def _get_pingen_session(self, cr, uid, context=None):
""" Push a document to pingen.com """ """ Returns a pingen session for a user"""
company = self.pool.get('res.users').browse(
cr, uid, uid, context=context).company_id
return self.pool.get('res.company')._pingen(cr, uid, company, context=context)
def _push_to_pingen(self, cr, uid, document, pingen=None, context=None):
""" Push a document to pingen.com
:param Pingen pingen: optional pingen object to, reuse session
"""
attachment_obj = self.pool.get('ir.attachment') attachment_obj = self.pool.get('ir.attachment')
decoded_document = attachment_obj._decoded_content( decoded_document = attachment_obj._decoded_content(
cr, uid, document.attachment_id, context=context) cr, uid, document.attachment_id, context=context)
company = self.pool.get('res.users').browse( if pingen is None:
cr, uid, uid, context=context).company_id pingen = self._get_pingen_session(cr, uid, context=context)
pingen = self.pool.get('res.company')._pingen(cr, uid, company, context=context)
try: try:
doc_id, post_id, infos = pingen.push_document( doc_id, post_id, infos = pingen.push_document(
document.datas_fname, document.datas_fname,
@@ -145,27 +152,29 @@ class pingen_document(orm.Model):
Wrapper method for multiple ids (when triggered from button for Wrapper method for multiple ids (when triggered from button for
instance) for public interface. instance) for public interface.
""" """
for document in self.browse(cr, uid, ids, context=context): with self._get_pingen_session(cr, uid, context=context) as session:
try: for document in self.browse(cr, uid, ids, context=context):
self._push_to_pingen(cr, uid, document, context=context) try:
except ConnectionError as e: self._push_to_pingen(
raise osv.except_osv( cr, uid, document, pingen=session, context=context)
_('Pingen Connection Error'), except ConnectionError as e:
_('Connection Error when asking for sending the document %s to Pingen') % document.name) raise osv.except_osv(
_('Pingen Connection Error'),
_('Connection Error when asking for sending the document %s to Pingen') % document.name)
except APIError as e: except APIError as e:
raise osv.except_osv( raise osv.except_osv(
_('Pingen Error'), _('Pingen Error'),
_('Error when asking Pingen to send the document %s: ' _('Error when asking Pingen to send the document %s: '
'\n%s') % (document.name, e)) '\n%s') % (document.name, e))
except: except:
_logger.exception( _logger.exception(
'Unexcepted Error when updating the status of pingen.document %s: ' % 'Unexcepted Error when updating the status of pingen.document %s: ' %
document.id) document.id)
raise osv.except_osv( raise osv.except_osv(
_('Error'), _('Error'),
_('Unexcepted Error when updating the status of Document %s') % document.name) _('Unexcepted Error when updating the status of Document %s') % document.name)
return True return True
def _push_and_send_to_pingen_cron(self, cr, uid, ids, context=None): def _push_and_send_to_pingen_cron(self, cr, uid, ids, context=None):
@@ -186,28 +195,35 @@ class pingen_document(orm.Model):
context=context) context=context)
with closing(pooler.get_db(cr.dbname).cursor()) as loc_cr: with closing(pooler.get_db(cr.dbname).cursor()) as loc_cr:
for document in self.browse(loc_cr, uid, ids, context=context): with self._get_pingen_session(cr, uid, context=context) as session:
for document in self.browse(loc_cr, uid, ids, context=context):
if document.state == 'error': if document.state == 'error':
self._resolve_error(loc_cr, uid, document, context=context) self._resolve_error(loc_cr, uid, document, context=context)
document.refresh() document.refresh()
try: try:
if document.state == 'pending': if document.state == 'pending':
self._push_to_pingen(loc_cr, uid, document, context=context) self._push_to_pingen(
loc_cr, uid, document, pingen=session, context=context)
elif document.state == 'pushed': elif document.state == 'pushed':
self._ask_pingen_send(loc_cr, uid, document, context=context) self._ask_pingen_send(
except ConnectionError as e: loc_cr, uid, document, pingen=session, context=context)
document.write({'last_error_message': e, 'state': 'error'}, context=context) except ConnectionError as e:
except APIError as e: document.write({'last_error_message': e,
document.write({'last_error_message': e, 'state': 'pingen_error'}, context=context) 'state': 'error'},
except: context=context)
_logger.error('Unexcepted error in pingen cron') except APIError as e:
loc_cr.rollback() document.write({'last_error_message': e,
raise 'state': 'pingen_error'},
context=context)
except:
_logger.error('Unexcepted error in pingen cron')
loc_cr.rollback()
raise
loc_cr.commit() loc_cr.commit()
return True return True
@@ -227,17 +243,16 @@ class pingen_document(orm.Model):
self._resolve_error(cr, uid, document, context=context) self._resolve_error(cr, uid, document, context=context)
return True return True
def _ask_pingen_send(self, cr, uid, document, context=None): def _ask_pingen_send(self, cr, uid, document, pingen, context=None):
""" For a document already pushed to pingen, ask to send it. """ For a document already pushed to pingen, ask to send it.
:param Pingen pingen: pingen object to reuse
""" """
# sending has been explicitely asked so we change the option # sending has been explicitely asked so we change the option
# for consistency # for consistency
if not document.pingen_send: if not document.pingen_send:
document.write({'pingen_send': True}, context=context) document.write({'pingen_send': True}, context=context)
company = self.pool.get('res.users').browse(
cr, uid, uid, context=context).company_id
pingen = self.pool.get('res.company')._pingen(cr, uid, company, context=context)
try: try:
post_id = pingen.send_document( post_id = pingen.send_document(
document.pingen_id, document.pingen_id,
@@ -267,39 +282,39 @@ class pingen_document(orm.Model):
Wrapper method for multiple ids (when triggered from button for Wrapper method for multiple ids (when triggered from button for
instance) for public interface. instance) for public interface.
""" """
for document in self.browse(cr, uid, ids, context=context): with self._get_pingen_session(cr, uid, context=context) as session:
try: for document in self.browse(cr, uid, ids, context=context):
self._ask_pingen_send(cr, uid, document, context=context) try:
except ConnectionError as e: self._ask_pingen_send(cr, uid, document, pingen=session, context=context)
raise osv.except_osv( except ConnectionError as e:
_('Pingen Connection Error'), raise osv.except_osv(
_('Connection Error when asking for ' _('Pingen Connection Error'),
'sending the document %s to Pingen') % document.name) _('Connection Error when asking for '
'sending the document %s to Pingen') % document.name)
except APIError as e: except APIError as e:
raise osv.except_osv( raise osv.except_osv(
_('Pingen Error'), _('Pingen Error'),
_('Error when asking Pingen to send the document %s: ' _('Error when asking Pingen to send the document %s: '
'\n%s') % (document.name, e)) '\n%s') % (document.name, e))
except: except:
_logger.exception( _logger.exception(
'Unexcepted Error when updating the status of pingen.document %s: ' % 'Unexcepted Error when updating the status of pingen.document %s: ' %
document.id) document.id)
raise osv.except_osv( raise osv.except_osv(
_('Error'), _('Error'),
_('Unexcepted Error when updating the status of Document %s') % document.name) _('Unexcepted Error when updating the status of Document %s') % document.name)
return True return True
def _update_post_infos(self, cr, uid, document, context=None): def _update_post_infos(self, cr, uid, document, pingen, context=None):
""" Update the informations from pingen of a document in the Sendcenter """ Update the informations from pingen of a document in the Sendcenter
:param Pingen pingen: pingen object to reuse
""" """
if not document.post_id: if not document.post_id:
return return
company = self.pool.get('res.users').browse(
cr, uid, uid, context=context).company_id
pingen = self.pool.get('res.company')._pingen(cr, uid, company, context=context)
try: try:
post_infos = pingen.post_infos(document.post_id) post_infos = pingen.post_infos(document.post_id)
except ConnectionError as e: except ConnectionError as e:
@@ -350,19 +365,21 @@ class pingen_document(orm.Model):
context=context) context=context)
with closing(pooler.get_db(cr.dbname).cursor()) as loc_cr: with closing(pooler.get_db(cr.dbname).cursor()) as loc_cr:
for document in self.browse(loc_cr, uid, ids, context=context): with self._get_pingen_session(cr, uid, context=context) as session:
try: for document in self.browse(loc_cr, uid, ids, context=context):
self._update_post_infos(loc_cr, uid, document, context=context) try:
except (ConnectionError, APIError): self._update_post_infos(
# will be retried the next time loc_cr, uid, document, pingen=session, context=context)
# In any case, the error has been logged by _update_post_infos except (ConnectionError, APIError):
loc_cr.rollback() # will be retried the next time
except: # In any case, the error has been logged by _update_post_infos
_logger.error('Unexcepted error in pingen cron') loc_cr.rollback()
loc_cr.rollback() except:
raise _logger.error('Unexcepted error in pingen cron')
loc_cr.rollback()
raise
loc_cr.commit() loc_cr.commit()
return True return True
def update_post_infos(self, cr, uid, ids, context=None): def update_post_infos(self, cr, uid, ids, context=None):
@@ -371,27 +388,29 @@ class pingen_document(orm.Model):
Wrapper method for multiple ids (when triggered from button for Wrapper method for multiple ids (when triggered from button for
instance) for public interface. instance) for public interface.
""" """
for document in self.browse(cr, uid, ids, context=context): with self._get_pingen_session(cr, uid, context=context) as session:
try: for document in self.browse(cr, uid, ids, context=context):
self._update_post_infos(cr, uid, document, context=context) try:
except ConnectionError as e: self._update_post_infos(
raise osv.except_osv( cr, uid, document, pingen=session, context=context)
_('Pingen Connection Error'), except ConnectionError as e:
_('Connection Error when updating the status of Document %s' raise osv.except_osv(
' from Pingen') % document.name) _('Pingen Connection Error'),
_('Connection Error when updating the status of Document %s'
' from Pingen') % document.name)
except APIError as e: except APIError as e:
raise osv.except_osv( raise osv.except_osv(
_('Pingen Error'), _('Pingen Error'),
_('Error when updating the status of Document %s from Pingen: ' _('Error when updating the status of Document %s from Pingen: '
'\n%s') % (document.name, e)) '\n%s') % (document.name, e))
except: except:
_logger.exception( _logger.exception(
'Unexcepted Error when updating the status of pingen.document %s: ' % 'Unexcepted Error when updating the status of pingen.document %s: ' %
document.id) document.id)
raise osv.except_osv( raise osv.except_osv(
_('Error'), _('Error'),
_('Unexcepted Error when updating the status of Document %s') % document.name) _('Unexcepted Error when updating the status of Document %s') % document.name)
return True return True