Skip to content

Commit 0c614e1

Browse files
authored
improve exception/timeout handling (#11)
* improve exception/timeout handling * replace asyncio.exceptions with asyncio for backwards compatibility with py3.7 * bump version to 0.4.0
1 parent f87a709 commit 0c614e1

File tree

2 files changed

+35
-10
lines changed

2 files changed

+35
-10
lines changed

enochecker3/enochecker.py

Lines changed: 34 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -276,7 +276,7 @@ async def _inject_dependencies(
276276
new_args.append(await stack.enter_async_context(arg))
277277
yield new_args
278278

279-
async def _call_method(self, task: BaseCheckerTaskMessage) -> Optional[str]:
279+
async def _call_method_raw(self, task: BaseCheckerTaskMessage) -> Optional[str]:
280280
variant_id = task.variant_id
281281
method = task.method
282282
try:
@@ -287,9 +287,26 @@ async def _call_method(self, task: BaseCheckerTaskMessage) -> Optional[str]:
287287
)
288288

289289
async with self._inject_dependencies(task, f) as args:
290+
return await f(*args)
291+
292+
async def _call_method(self, task: BaseCheckerTaskMessage) -> Optional[str]:
293+
try:
290294
return await asyncio.wait_for(
291-
f(*args), timeout=(task.timeout / 1000) - TIMEOUT_BUFFER
295+
self._call_method_raw(task),
296+
timeout=(task.timeout / 1000) - TIMEOUT_BUFFER,
297+
)
298+
except asyncio.TimeoutError:
299+
trace = traceback.format_exc()
300+
logger = self._get_logger_adapter(task)
301+
logger.error(f"Checker task timed out\n{trace}")
302+
raise MumbleException(
303+
"Service responding too slow, allowed time for checker task exceeded"
292304
)
305+
except (httpx.ConnectTimeout, httpx.ConnectError):
306+
trace = traceback.format_exc()
307+
logger = self._get_logger_adapter(task)
308+
logger.info(f"Failed to connect to service\n{trace}")
309+
raise OfflineException("Could not establish HTTP connection to service")
293310

294311
async def _call_putflag(
295312
self, task: PutflagCheckerTaskMessage
@@ -377,13 +394,17 @@ def _get_logger_adapter(
377394
)
378395

379396
@contextlib.asynccontextmanager
380-
async def _get_async_socket(self, task: BaseCheckerTaskMessage) -> AsyncSocket:
397+
async def _get_async_socket(
398+
self, task: BaseCheckerTaskMessage, logger: logging.LoggerAdapter
399+
) -> AsyncSocket:
381400
try:
382401
conn = await asyncio.streams.open_connection(
383402
task.address, self.service_port
384403
)
385-
except ConnectionError:
386-
raise OfflineException("Establishing socket connection to service failed")
404+
except (ConnectionError, asyncio.TimeoutError):
405+
trace = traceback.format_exc()
406+
logger.info(f"Failed to connect to service\n{trace}")
407+
raise OfflineException("Could not establish socket connection to service")
387408
try:
388409
yield conn
389410
finally:
@@ -472,6 +493,8 @@ def service() -> CheckerInfoMessage:
472493
async def checker(task: CheckerTaskMessage) -> CheckerResultMessage:
473494
cls = METHOD_TO_TASK_MESSAGE_MAPPING[task.method]
474495
_task = cls(**task.dict())
496+
logger = self._get_logger_adapter(_task)
497+
logger.debug(f"Received new checker task with payload: {_task}")
475498
try:
476499
if task.method == CheckerMethod.PUTFLAG:
477500
return await self._call_putflag(
@@ -501,24 +524,26 @@ async def checker(task: CheckerTaskMessage) -> CheckerResultMessage:
501524
message=f"Unsupported method: {task.method}",
502525
)
503526
except MumbleException as e:
504-
traceback.print_exc()
527+
trace = traceback.format_exc()
528+
logger.info(f"Encountered mumble exception:\n{trace}")
505529
return CheckerResultMessage(
506530
result=CheckerTaskResult.MUMBLE, message=e.message
507531
)
508532
except OfflineException as e:
509-
traceback.print_exc()
533+
trace = traceback.format_exc()
534+
logger.info(f"Encountered offline exception:\n{trace}")
510535
return CheckerResultMessage(
511536
result=CheckerTaskResult.OFFLINE, message=e.message
512537
)
513538
except InternalErrorException as e:
514-
traceback.print_exc()
539+
trace = traceback.format_exc()
540+
logger.info(f"Encountered explicit internal error exception:\n{trace}")
515541
return CheckerResultMessage(
516542
result=CheckerTaskResult.INTERNAL_ERROR, message=e.message
517543
)
518544
except Exception as e:
519545
traceback.print_exc()
520546
trace = traceback.format_exc()
521-
logger = self._get_logger_adapter(_task)
522547
logger.critical(f"Encountered internal exception:\n{trace}")
523548
return CheckerResultMessage(
524549
result=CheckerTaskResult.INTERNAL_ERROR,

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99

1010
setuptools.setup(
1111
name="enochecker3",
12-
version="0.3.0",
12+
version="0.4.0",
1313
author="ldruschk",
1414
author_email="[email protected]",
1515
description="FastAPI based library for building async python checkers for the EnoEngine A/D CTF Framework",

0 commit comments

Comments
 (0)