diff options
| -rw-r--r-- | VERSION | 2 | ||||
| -rw-r--r-- | src_py/opcut/main.py | 8 | ||||
| -rw-r--r-- | src_py/opcut/server.py | 43 |
3 files changed, 46 insertions, 7 deletions
@@ -1 +1 @@ -0.4.3 +0.4.4 diff --git a/src_py/opcut/main.py b/src_py/opcut/main.py index 28bb49e..346afc3 100644 --- a/src_py/opcut/main.py +++ b/src_py/opcut/main.py @@ -70,6 +70,9 @@ def create_argument_parser() -> argparse.ArgumentParser: '--port', metavar='PORT', type=int, default=8080, help="listening TCP port (default 8080)") server.add_argument( + '--timeout', metavar='T', type=float, default=300, + help="single request timeout in seconds (default 300)") + server.add_argument( '--log-level', metavar='LEVEL', default='info', choices=['critical', 'error', 'warning', 'info', 'debug', 'notset'], help="log level (default info)") @@ -98,6 +101,7 @@ def main(): elif args.action == 'server': server(host=args.host, port=args.port, + timeout=args.timeout, log_level=args.log_level) else: @@ -165,6 +169,7 @@ def generate(input_format: typing.Optional[json.Format], def server(host: str, port: int, + timeout: float, log_level: str): logging.config.dictConfig({ 'version': 1, @@ -183,7 +188,8 @@ def server(host: str, async def run(): server = await opcut.server.create(host=host, - port=port) + port=port, + timeout=timeout) try: await server.wait_closing() diff --git a/src_py/opcut/server.py b/src_py/opcut/server.py index 8501aaa..d8665f6 100644 --- a/src_py/opcut/server.py +++ b/src_py/opcut/server.py @@ -12,9 +12,11 @@ from opcut import common async def create(host: str, - port: int + port: int, + timeout: float ) -> 'Server': server = Server() + server._timeout = timeout server._async_group = aio.Group() try: @@ -71,9 +73,14 @@ class Server(aio.Resource): params = common.params_from_json(data) try: - result = await _calculate(method, params) + result = await asyncio.wait_for(_calculate(method, params), + self._timeout) return aiohttp.web.json_response(result) + except asyncio.TimeoutError: + return aiohttp.web.Response(status=400, + text='Request timeout') + except common.UnresolvableError: return aiohttp.web.Response(status=400, text='Result is not solvable') @@ -92,7 +99,13 @@ class Server(aio.Resource): panel = request.query.get('panel') result = common.result_from_json(data) - output = await _generate(output_format, panel, result) + try: + output = await asyncio.wait_for( + _generate(output_format, panel, result), self._timeout) + + except asyncio.TimeoutError: + return aiohttp.web.Response(status=400, + text='Request timeout') if output_format == common.OutputFormat.PDF: content_type = 'application/pdf' @@ -116,7 +129,14 @@ async def _calculate(method, params): stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) - stdout_data, stderr_data = await p.communicate(stdint_data) + + stderr_data = None + try: + stdout_data, stderr_data = await p.communicate(stdint_data) + + finally: + if p.returncode is None: + p.terminate() if p.returncode == 0: return json.decode(stdout_data.decode('utf-8')) @@ -124,6 +144,9 @@ async def _calculate(method, params): if p.returncode == 42: raise common.UnresolvableError() + if not stderr_data: + raise Exception() + raise Exception(stderr_data.decode('utf-8')) @@ -137,9 +160,19 @@ async def _generate(output_format, panel, result): stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) - stdout_data, stderr_data = await p.communicate(stdint_data) + + stderr_data = None + try: + stdout_data, stderr_data = await p.communicate(stdint_data) + + finally: + if p.returncode is None: + p.terminate() if p.returncode == 0: return stdout_data + if not stderr_data: + raise Exception() + raise Exception(stderr_data.decode('utf-8')) |
