Draft: feat: add draft high-level Pubsub @message_handler(...) support
This MR is ready for initial feedback/suggestions/review, but not ready to merge yet. The @message_handler(...)
decorator working and can be used from examples/main.py (instructions in comment). Some examples of things that I know I want/need to do still:
- expose
@message_handler(...)
from the mainucam_faas
module (right now it's only exported fromucam_faas.messages
. - decide on what we do with
@ucam_faas.cloud_event()
- In addition to
@message_handler
, This MR adds@ucam_faas.cloud_events.cloud_event_handler()
, which can provide@ucam_faas.cloud_event()
's functionality, with more flexibility —@message_handler
is built on top of it. - I'm tempted to implement
@cloud_event
's API in terms of@cloud_event_handler
for backwards compatibility, and to give its users the benefit of the testing/observability behaviour from the new@cloud_event_handler()
, but as discussed in #19, its naming/API behaviour has proved confusing for developers, and Mike and I were thinking of deprecating/removing it. - I want to reduce the boilerplate required to implement
ExecutionInfo
subclasses by usingdefault_factory
for context, rather than its current approach of requiring implementing theget_init_args_from_context()
method. - Iterate on logging a bit — I've got it working but not been playing with it in practice much, so the fields that we automatically include and how it gets represented could do with some thought/polish.
- More tests, e.g. the logging and HTTP response sending is not covered yet
- In addition to
I'm going to go through the code and add some comments to call out things of note.
This commit/MR is the squashed work-in-progress from by development branch implementing support for higher-level handler functions, to address issue #19, on confusion between CloudEvents and Pubsub message data, as well as the developer-experience issue of ucam_faas users needing to handle decoding/validating Pubsub messages themselves each time they create a function.
The main thing added by this change is the @ucam_faas.messages.message_handler(message_type=...) decorator. This decorator creates handler functions that receive an instance of a Pydantic model, protobuf Message, or return value of a parser function they provide.
The decorator takes care of validating the CloudEvent data is the correct Pubsub type, as well as validating the Pubsub-specific data within the CloudEvent, and the application-specific data within the Pubsub message (that the message_type=...
argument describes).
In addition, it also provides support for unit-testing handler functions, without needing to do end-to-end integration tests with a running server. The function decorated by @message_handler(...)
has a .execute(CloudEvent)
method, which executes the handler with a CloudEvent object, and returns a value describing the function's result.
Functions can now return a ExecutionInfo value, which is a Pydantic model that is automatically populated with properties from the function context, such as details of the CloudEvent, function execution ID, Pubsub message details, etc. Developers can add their own properties by subclassing the model and returning an instance from their function.
These ExecutionInfo values are intended to provide observability into the function's behaviour, both for the purpose of automated testing, and for observability when deployed in production. The ExecutionInfo value is logged as JSON at the end of the function's execution, both when it fails or completes normally.