Skip to main content

No project description provided

Project description

Metis-App

Introduction

Metis-App contains useful functions for the use primarily in Python-based AWS Lambda serverless functions. The majority of the functions are generic (rather than AWS-specifc), however, all these functions have been useful in building distributed serverless functions, based on local patterns.

The objective is to collect together useful functions found during the development of Lambda services.

For example, we have used monads (PyMonad) extensively for building composable pipelines and avoiding raising exceptions. In the monad lib there is also a try decorator than wraps exception-throwing functions. We have a simple circuit-breaker mechanism, and a method of performing an oauth client credentials grant.

This lib is not an AWS Lambda paved road or framework. Consider it as a collection of helpers.

The App Pipeline

The app pipeline is a common "middleware" manager for a Lambda event. The function initiates the pipeline right from the handle function. The pipeline takes care of building the request event structures, applying routing based on the event type (currently s3 nd http lambda events are supported), calls the function's handler, and generates the response. Other middleware services are also provided, such as creating a policy decision point (PDP) by parsing any token and calling an appropriate userinfo point.

The handler invokes the middleware as follows:

return app.pipeline(event=event,
                    context=context,
                    env=env.Env().env,
                    params_parser=request_builder,
                    pip_initiator=pip,
                    handler_guard_fn=check_env_established)
  • event. Mandatory. Dict. The Lambda provided event.
  • context. Mandatory. Dict. The Lambda provided context.
  • params_parser: Mandatory. Callable. Takes the request object optionally transforms it, and returns it wrapper in an Either. If no transformation is required simply return the request wrapped in an Either, e.g. return monad.Right(request)
  • pip_initiator: Mandatory. Callable. Policy Information Point
  • factory_overrides: Optional. Dict. Overrides the routing factory token constructor. Only supports S3 overrides. For an s3 override provide a Dict in the form of {'s3': callable_function}. With s3 the standard factory token constructor takes the bucket name, and splits on ".", returning the token prior to the first ".". As a convention it is expecting environment specific bucket names to be separated by ".", e.g. bucket-name.uat.example.io, with the resulting token being bucket-name. However, if this is not the format of the bucket name implement the override function. The function takes a List[S3Object] and must return a string to be looked up in the routing table. Note, should the event not be handled, return the const app.NO_MATCHING_ROUTE
  • handler_guard_fn: A pre-processing guard fn to determine whether the handler should be invoked. It returns an Either. When the handler shouldnt run the Either wraps an Exception. In this case, the request is passed directly to the responder

Using PowerTools Observability

Metis-app supports the integration of the AWS Powertools Logger, Tracer, and Metrics modules and decorators. To use them, install the dependencies and then build a Observer configuration in the handler module.

poetry add aws-lambda-powertools[aws-sdk]

# if using metrics...
poetry add aws-xray-sdk
from metis_app import observable

obs = observable.Observer().configure(service_name="test-service", metrics_namespace='module1')

Then use them as normal. Note, however, the logger, tracer, and metrics objects are now available through the observer object.

from aws_lambda_powertools.metrics import MetricUnit

@obs.metrics.log_metrics(capture_cold_start_metric=True)
def handler(event, ctx=None):
  ...
    

@obs.tracer.capture_method
def a_command(request):
    obs.tracer.put_annotation(key="Resource", value=request.event.path_params.get('id1'))
    obs.logger.info("Search for resource", uuid=request.event.path_params.get('id1'))
    obs.metrics.add_metric(name="Resource:Search", unit=MetricUnit.Count, value=1)
    ...

When the Observer is configured, it is also added to the Request object and passed to the command handler.

def a_command(request):
    request.observer.logger.info("Search for resource", uuid=request.event.path_params.get('id1'))
    ...

Getting a Self Token

Configuration

Provide the token service with a configuration as follows:

from metis_app import self_token

self_token.TokenConfig().configure(token_persistence_provider=TokenPersistenceProvider(),
                                   env=Env(),
                                   circuit_state_provider=circuit_store.CircuitStore(circuit_name="auth0"))
  • token_persistence_provider. A class that conforms to TokenPersistenceProviderProtocol. It has a write and read method.

    • The writer takes a key and value. The key defaults to BEARER_TOKEN, and the value is the JWT. It is the responsibility of the writer to persist where required. The writer must return the token wrapped in a Monad ; e.g. monad.Right('eyJ0eXAiOiJK....')
    • The reader takes a key and returns the value wrapped in a Monad; e.g. monad.Right('eyJ0eXAiOiJK....')
  • env. This should be a class that has the following methods:

    • client_id. Returns a client id as a string.
    • client_secret. Returns a client secret as a string.
    • identity_token_endpoint. Returns the url of the Oauth2 token endpoint as a str.
  • circuit_state_provider. Optional. A circuit state manager can optionally be provided. Doing so adds circuit breaker functionality to the call to the token endpoint. If not provided, failures do not enact the circuit breaker behaviour. The provider must conform to the circuit.CircuitStateProviderProtocol. This is a special case of a circuit; one that is used by the token getter. It will configure the circuit based on this arg. There is a more general way to use circuits for non-token interfaces. See the circuit breaker section.

Circuit Breaker

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

metis_app-1.1.0.tar.gz (65.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

metis_app-1.1.0-py3-none-any.whl (75.7 kB view details)

Uploaded Python 3

File details

Details for the file metis_app-1.1.0.tar.gz.

File metadata

  • Download URL: metis_app-1.1.0.tar.gz
  • Upload date:
  • Size: 65.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: poetry/1.8.2 CPython/3.11.6 Darwin/24.0.0

File hashes

Hashes for metis_app-1.1.0.tar.gz
Algorithm Hash digest
SHA256 37b1afd133307e60c97d6e79092e77d84381d639034ea47cbcca2be5168237be
MD5 1459f868e74c85a51000b6fe4021e304
BLAKE2b-256 2318b97da6293daa67b70ca1c77a8368be577477c3d8756adff248e83b8d7c6c

See more details on using hashes here.

File details

Details for the file metis_app-1.1.0-py3-none-any.whl.

File metadata

  • Download URL: metis_app-1.1.0-py3-none-any.whl
  • Upload date:
  • Size: 75.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: poetry/1.8.2 CPython/3.11.6 Darwin/24.0.0

File hashes

Hashes for metis_app-1.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 1646c3767650fc870fadb10c4fcc6d513a81297aedc887d5f44c942d912c20f8
MD5 65d689e75d38309d826a158f81bde5f1
BLAKE2b-256 bf9d7b09d56f4536927190fe95e16219910e573275e68485c7e526f1b2ee2814

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page