diff --git a/.github/workflows/servc.yml b/.github/workflows/servc.yml index c18c8be..10f620a 100644 --- a/.github/workflows/servc.yml +++ b/.github/workflows/servc.yml @@ -4,7 +4,7 @@ on: push: env: - SERVC_VERSION: 0.5.0 + SERVC_VERSION: 0.5.1 permissions: contents: write diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 35e4481..e07b791 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -50,7 +50,7 @@ jobs: pip install -r requirements-dev.txt - name: Type check - run: mypy servc + run: mypy servc --check-untyped-defs - name: Run tests env: diff --git a/servc/svc/com/worker/__init__.py b/servc/svc/com/worker/__init__.py index aecd98a..cc4bd74 100644 --- a/servc/svc/com/worker/__init__.py +++ b/servc/svc/com/worker/__init__.py @@ -1,10 +1,10 @@ -from typing import Any, List +from typing import Any, List, Tuple from servc.svc import ComponentType, Middleware from servc.svc.com.bus import BusComponent, OnConsuming from servc.svc.com.cache import CacheComponent from servc.svc.com.worker.hooks import evaluate_post_hooks, evaluate_pre_hooks -from servc.svc.com.worker.types import RESOLVER_CONTEXT, RESOLVER_MAPPING +from servc.svc.com.worker.types import RESOLVER, RESOLVER_CONTEXT, RESOLVER_MAPPING from servc.svc.config import Config from servc.svc.io.input import InputType from servc.svc.io.output import ( @@ -12,6 +12,7 @@ MethodNotFoundException, NoProcessingException, NotAuthorizedException, + ResponseArtifact, StatusCode, ) from servc.svc.io.response import getAnswerArtifact, getErrorArtifact @@ -102,6 +103,35 @@ def connect(self): bindEventExchange=self._bindToEventExchange, ) + def run_resolver( + self, method: RESOLVER, context: RESOLVER_CONTEXT, args: Tuple[str, Any] + ) -> Tuple[StatusCode, ResponseArtifact | None]: + id, payload = args + try: + response = method(id, payload, context) + return StatusCode.OK, getAnswerArtifact(id, response) + except NotAuthorizedException as e: + return StatusCode.NOT_AUTHORIZED, getErrorArtifact( + id, str(e), StatusCode.NOT_AUTHORIZED + ) + except InvalidInputsException as e: + return StatusCode.INVALID_INPUTS, getErrorArtifact( + id, str(e), StatusCode.INVALID_INPUTS + ) + except NoProcessingException: + return StatusCode.NO_PROCESSING, None + except MethodNotFoundException as e: + return StatusCode.METHOD_NOT_FOUND, getErrorArtifact( + id, str(e), StatusCode.METHOD_NOT_FOUND + ) + except Exception as e: + if self._config.get(f"conf.{self.name}.exiton5xx"): + print("Exiting due to 5xx error", e, flush=True) + exit(1) + return StatusCode.SERVER_ERROR, getErrorArtifact( + id, str(e), StatusCode.SERVER_ERROR + ) + def inputProcessor(self, message: Any) -> StatusCode: bus = self._busClass( self._config.get(f"conf.{self._bus.name}"), @@ -126,8 +156,14 @@ def inputProcessor(self, message: Any) -> StatusCode: return StatusCode.INVALID_INPUTS if message["event"] not in self._eventResolvers: return StatusCode.METHOD_NOT_FOUND - self._eventResolvers[message["event"]]("", {**message}, context) - return StatusCode.OK + + status_code, response = self.run_resolver( + self._eventResolvers[message["event"]], + context, + ("", {**message}), + ) + + return status_code if message["type"] in [InputType.INPUT.value, InputType.INPUT]: if "id" not in message: @@ -177,45 +213,17 @@ def inputProcessor(self, message: Any) -> StatusCode: if not continueExecution: return StatusCode.OK - statusCode: StatusCode = StatusCode.OK - try: - response = self._resolvers[artifact["method"]]( - message["id"], - artifact["inputs"], - context, - ) - cache.setKey(message["id"], getAnswerArtifact(message["id"], response)) - except NotAuthorizedException as e: - cache.setKey( - message["id"], - getErrorArtifact(message["id"], str(e), StatusCode.NOT_AUTHORIZED), - ) - statusCode = StatusCode.NOT_AUTHORIZED - except InvalidInputsException as e: - cache.setKey( - message["id"], - getErrorArtifact(message["id"], str(e), StatusCode.INVALID_INPUTS), - ) - statusCode = StatusCode.INVALID_INPUTS - except NoProcessingException: + statusCode, response = self.run_resolver( + self._resolvers[artifact["method"]], + context, + (message["id"], artifact["inputs"]), + ) + if statusCode == StatusCode.NO_PROCESSING: return StatusCode.NO_PROCESSING - except MethodNotFoundException as e: - cache.setKey( - message["id"], - getErrorArtifact( - message["id"], str(e), StatusCode.METHOD_NOT_FOUND - ), - ) - statusCode = StatusCode.METHOD_NOT_FOUND - except Exception as e: - cache.setKey( - message["id"], - getErrorArtifact(message["id"], str(e), StatusCode.SERVER_ERROR), - ) - statusCode = StatusCode.SERVER_ERROR - finally: - evaluate_post_hooks(bus, cache, message, artifact) - return statusCode + + cache.setKey(message["id"], response) + evaluate_post_hooks(bus, cache, message, artifact) + return statusCode cache.setKey( message["id"], diff --git a/servc/svc/config/__init__.py b/servc/svc/config/__init__.py index e38aea7..9616640 100644 --- a/servc/svc/config/__init__.py +++ b/servc/svc/config/__init__.py @@ -18,8 +18,12 @@ "conf.bus.routemap": json.loads(os.getenv("CONF__BUS__ROUTEMAP", json.dumps({}))), "conf.bus.prefix": "", "conf.worker.bindtoeventexchange": True, + "conf.worker.exiton5xx": True, } +BOOLEAN_CONFIGS = os.getenv( + "SERVC_BOOLEAN_CONFIGS", "conf.worker.exiton5xx,conf.worker.bindtoeventexchange" +).split(",") DOT_MARKER = os.getenv("SERVC_DOT_MARKER", "_DOT_") DASH_MARKER = os.getenv("SERVC_DASH_MARKER", "_DASH_") @@ -53,7 +57,10 @@ def __init__(self, config_path: str | None = None): "CONF__FILE", "CONF__BUS__ROUTEMAP", ): - self.setValue(key.replace(DASH_MARKER, "-").replace("__", "."), value) + newkey = key.replace(DASH_MARKER, "-").replace("__", ".") + if newkey.lower() in BOOLEAN_CONFIGS: + value = value.lower() in ("yes", "true", "t", "1") + self.setValue(newkey, value) self.setValue("conf.bus.instanceid", self.get("conf.instanceid"))