workflows: log invalid payload in webservice calls (#74150) #713

Merged
fpeters merged 1 commits from wip/74150-log-invalid-payload into main 2023-09-29 07:33:48 +02:00
3 changed files with 41 additions and 2 deletions

View File

@ -89,3 +89,19 @@ def test_wscall_record_errors(pub):
'label': None,
'data_b64': '8Q==\n',
}
# error with payload that cannot be converted to JSON
pub.loggederror_class.wipe()
formdata.evolution[-1].parts = []
formdata.store()
wscall.method = 'POST'
wscall.post_data = {'xxx': '=Ellipsis'}
wscall.perform(formdata)
assert pub.loggederror_class.count() == 1
assert (
formdata.workflow_data['varname_payload_error'] == 'Object of type ellipsis is not JSON serializable'
)
assert (
pub.loggederror_class.select()[0].summary
== 'Invalid payload (Object of type ellipsis is not JSON serializable)'
)

View File

@ -34,7 +34,7 @@ from wcs.workflows import (
WorkflowStatusItem,
register_item_class,
)
from wcs.wscalls import call_webservice, get_app_error_code
from wcs.wscalls import PayloadError, call_webservice, get_app_error_code
from ..qommon import _, force_str, pgettext
from ..qommon.errors import ConnectionError
@ -461,6 +461,19 @@ class WebserviceCallStatusItem(WorkflowStatusItem):
formdata.store()
self.action_on_error(self.action_on_network_errors, formdata, exception=e)
return
except PayloadError as e:
if self.varname:
workflow_data['%s_payload_error' % self.varname] = str(e)
formdata.update_workflow_data(workflow_data)
formdata.store()
# always log errors from our side
get_publisher().record_error(
_('Invalid payload (%s)') % str(e),
formdata=formdata,
status_item=self,
exception=e,
)
return
Review

J'ai hésité à ajouter une gestion d'erreur particulière ici, comme on a pour les erreurs HTTP du webservice mais j'ai finalement décidé que non, comme une action "données de traitement" qui foirerait, l'enregistrement de l'erreur suffit.

J'ai hésité à ajouter une gestion d'erreur particulière ici, comme on a pour les erreurs HTTP du webservice mais j'ai finalement décidé que non, comme une action "données de traitement" qui foirerait, l'enregistrement de l'erreur suffit.
app_error_code = get_app_error_code(response, data, self.response_type)
app_error_code_header = response.headers.get('x-error-code')

View File

@ -44,6 +44,10 @@ from .qommon.template import Template
from .qommon.xml_storage import XmlStorableObject
class PayloadError(Exception):
pass
def get_app_error_code(response, data, response_type):
app_error_code = 0
app_error_code_header = response.headers.get('x-error-code')
@ -174,7 +178,13 @@ def call_webservice(
if method in ('PATCH', 'PUT', 'POST', 'DELETE'):
if payload:
headers['Content-type'] = 'application/json'
payload = json.dumps(payload, cls=JSONEncoder)
try:
payload = json.dumps(payload, cls=JSONEncoder)
except TypeError as e:
get_publisher().record_error(
exception=e, context='[WSCALL]', notify=notify_on_errors, record=record_on_errors
)
raise PayloadError(str(e)) from e
response, status, data, dummy = misc._http_request(method=method, body=payload, **request_kwargs)
else:
response, status, data, dummy = misc.http_get_page(**request_kwargs)