Avoid blocking the application when computing the calculator report.

This commit is contained in:
Phil Elson 2021-07-08 15:24:33 +02:00
parent 1fca4d24b7
commit 0e52b38eb3
2 changed files with 34 additions and 7 deletions

View file

@ -1,6 +1,8 @@
# This module is part of CARA. Please see the repository at
# https://gitlab.cern.ch/cara/cara for details of the license and terms of use.
import asyncio
import concurrent.futures
import datetime
import base64
import html
@ -87,7 +89,7 @@ class Missing404Handler(BaseRequestHandler):
class ConcentrationModel(BaseRequestHandler):
def post(self):
async def post(self):
requested_model_config = {
name: self.get_argument(name) for name in self.request.arguments
}
@ -107,20 +109,27 @@ class ConcentrationModel(BaseRequestHandler):
return
base_url = self.request.protocol + "://" + self.request.host
report_generator = self.settings['report_generator']
report = report_generator.build_report(base_url, form)
report_generator: ReportGenerator = self.settings['report_generator']
report_task = self.settings["worker_pool"].submit(
report_generator.build_report, base_url, form,
)
report: str = await asyncio.wrap_future(report_task)
self.finish(report)
class StaticModel(BaseRequestHandler):
def get(self):
async def get(self):
form = model_generator.FormData.from_dict(model_generator.baseline_raw_form_data())
base_url = self.request.protocol + "://" + self.request.host
report_generator = self.settings['report_generator']
report = report_generator.build_report(base_url, form)
report_generator: ReportGenerator = self.settings['report_generator']
report_task = self.settings["worker_pool"].submit(
report_generator.build_report, base_url, form,
)
report: str = await asyncio.wrap_future(report_task)
self.finish(report)
class LandingPage(BaseRequestHandler):
def get(self):
template = self.settings["template_environment"].get_template(
@ -226,4 +235,5 @@ def make_app(
# COOKIE_SECRET being undefined will result in no login information being
# presented to the user.
cookie_secret=os.environ.get('COOKIE_SECRET', '<undefined>'),
worker_pool=concurrent.futures.ProcessPoolExecutor(),
)

View file

@ -48,7 +48,23 @@ class TestBasicApp(tornado.testing.AsyncHTTPTestCase):
@tornado.testing.gen_test(timeout=_TIMEOUT)
def test_report(self):
response = yield self.http_client.fetch(self.get_url('/calculator/baseline-model/result'))
requests = [
self.http_client.fetch(self.get_url('/calculator/baseline-model/result')),
# At the same time, request a non-report page (to check whether the report is blocking).
self.http_client.fetch(self.get_url('/calculator/')),
]
response = yield requests[0]
other_response = yield requests[1]
def end_time(resp):
return resp.start_time + resp.request_time
# The start time is before the other request,
# but the end time is after the other request (because it takes longer
# to process a report than a simple page).
assert response.start_time < other_response.start_time
assert end_time(response) > end_time(other_response)
self.assertEqual(response.code, 200)
assert 'CERN HSE' not in response.body.decode()
assert 'expected number of new cases is' in response.body.decode()
@ -66,6 +82,7 @@ class TestCernApp(tornado.testing.AsyncHTTPTestCase):
assert 'CERN HSE' in response.body.decode()
assert 'expected number of new cases is' in response.body.decode()
class TestOpenApp(tornado.testing.AsyncHTTPTestCase):
def get_app(self):
return cara.apps.calculator.make_app(calculator_prefix="/mycalc")