From 44856a3f75c3eb6c53aadf3bfe6cc047ffd30f82 Mon Sep 17 00:00:00 2001
From: John Chilton
+ The tool was executed with one or more empty input datasets, this isn't
+ always a problem and may not have been but frequently this is a source
+ of error.
+ `);
+ }
+ if (has_duplicate_inputs) {
+ reportEl.after(`
+
+ The tool was executed with one or more duplicate input datasets, this isn't
+ always a problem and may not have been but frequently this is a source
+ of error.
+ `);
+ }
+ }
+ },
+
/** Render the view */
render_error_page: function(dataset, job) {
this.$el.empty().append(`
@@ -88,23 +129,24 @@ var View = Backbone.View.extend({
const job_stderr = job.job_stderr;
const job_messages = job.job_messages;
if (!tool_stderr && !job_stderr && !job_messages) {
- return '';
+ return ' Execution resulted in the following messages: Execution resulted in the following messages:Error Details
';
+ var message = "Error Details
";
if (job_messages) {
- message += '${_.escape(job_message['desc'])}
${_.escape(job_message["desc"])}`;
}
}
if (tool_stderr) {
- message += 'Tool generated the following standard error:
'; + message += "Tool generated the following standard error:
"; message += `${_.escape(tool_stderr)}`;
}
if (job_stderr) {
- message += 'Galaxy job runner generated the following standard error:
'; + message += "Galaxy job runner generated the following standard error:
"; message += `${_.escape(job_stderr)}`;
}
+ message += ``;
return message;
},
diff --git a/lib/galaxy/webapps/galaxy/api/jobs.py b/lib/galaxy/webapps/galaxy/api/jobs.py
index 9254ca9630a..6a42001ba51 100644
--- a/lib/galaxy/webapps/galaxy/api/jobs.py
+++ b/lib/galaxy/webapps/galaxy/api/jobs.py
@@ -167,6 +167,30 @@ class JobController(BaseAPIController, UsesLibraryMixinItems):
job_dict['job_metrics'] = [metric_to_dict(metric) for metric in job.metrics]
return job_dict
+ @expose_api
+ def common_problems(self, trans, id, **kwd):
+ """
+ * GET /api/jobs/{id}/common_problems
+ check inputs and job for common potential problems to aid in error reporting
+ """
+ job = self.__get_job(trans, id)
+ seen_ids = set()
+ has_empty_inputs = False
+ has_duplicate_inputs = False
+ for job_input_assoc in job.input_datasets:
+ input_dataset_instance = job_input_assoc.dataset
+ if input_dataset_instance.get_total_size() == 0:
+ has_empty_inputs = True
+ input_instance_id = input_dataset_instance.id
+ if input_instance_id in seen_ids:
+ has_duplicate_inputs = True
+ else:
+ seen_ids.add(input_instance_id)
+ # TODO: check percent of failing jobs around a window on job.update_time for handler - report if high.
+ # TODO: check percent of failing jobs around a window on job.update_time for destination_id - report if high.
+ # TODO: sniff inputs (add flag to allow checking files?)
+ return {"has_empty_inputs": has_empty_inputs, "has_duplicate_inputs": has_duplicate_inputs}
+
@expose_api
def inputs(self, trans, id, **kwd):
"""
diff --git a/lib/galaxy/webapps/galaxy/buildapp.py b/lib/galaxy/webapps/galaxy/buildapp.py
index b10c23002f4..6eb8fa7a76c 100644
--- a/lib/galaxy/webapps/galaxy/buildapp.py
+++ b/lib/galaxy/webapps/galaxy/buildapp.py
@@ -888,6 +888,7 @@ def populate_api_routes(webapp, app):
webapp.mapper.connect('build_for_rerun', '/api/jobs/{id}/build_for_rerun', controller='jobs', action='build_for_rerun', conditions=dict(method=['GET']))
webapp.mapper.connect('resume', '/api/jobs/{id}/resume', controller='jobs', action='resume', conditions=dict(method=['PUT']))
webapp.mapper.connect('job_error', '/api/jobs/{id}/error', controller='jobs', action='error', conditions=dict(method=['POST']))
+ webapp.mapper.connect('common_problems', '/api/jobs/{id}/common_problems', controller='jobs', action='common_problems', conditions=dict(method=['GET']))
# Job files controllers. Only for consumption by remote job runners.
webapp.mapper.resource('file',
diff --git a/test/api/test_jobs.py b/test/api/test_jobs.py
index 22dc29d1d51..e3a5908dacd 100644
--- a/test/api/test_jobs.py
+++ b/test/api/test_jobs.py
@@ -190,6 +190,34 @@ class JobsApiTestCase(api.ApiTestCase):
assert_ok=False)
assert not dataset['visible']
+ @skip_without_tool('empty_output')
+ def test_common_problems(self):
+ with self.dataset_populator.test_history() as history_id:
+ empty_run_response = self.dataset_populator.run_tool(
+ tool_id='empty_output',
+ inputs={},
+ history_id=history_id,
+ )
+ empty_hda = empty_run_response["outputs"][0]
+ cat_empty_twice_run_response = self.dataset_populator.run_tool(
+ tool_id='cat1',
+ inputs={
+ 'input1': {'src': 'hda', 'id': empty_hda['id']},
+ 'queries_0|input2': {'src': 'hda', 'id': empty_hda['id']}
+ },
+ history_id=history_id,
+ )
+ empty_output_job = empty_run_response["jobs"][0]
+ cat_empty_job = cat_empty_twice_run_response["jobs"][0]
+ empty_output_common_problems_response = self._get('jobs/%s/common_problems' % empty_output_job["id"]).json()
+ cat_empty_common_problems_response = self._get('jobs/%s/common_problems' % cat_empty_job["id"]).json()
+ self._assert_has_keys(empty_output_common_problems_response, "has_empty_inputs", "has_duplicate_inputs")
+ self._assert_has_keys(cat_empty_common_problems_response, "has_empty_inputs", "has_duplicate_inputs")
+ assert not empty_output_common_problems_response["has_empty_inputs"]
+ assert cat_empty_common_problems_response["has_empty_inputs"]
+ assert not empty_output_common_problems_response["has_duplicate_inputs"]
+ assert cat_empty_common_problems_response["has_duplicate_inputs"]
+
@skip_without_tool('detect_errors_aggressive')
def test_report_error(self):
with self.dataset_populator.test_history() as history_id: