Core Events¶
This document describes the events dispatched by HARP Proxy’s core.
You can read about the concept and mechanics of the event-driven architecture of HARP Proxy in the contributor’s guide.
Configuration Events¶
During the setup and teardown phase, the harp.config module dispatches events to allow applications and other
components to register themselves with the system.
You can add listeners to those events using the Application Protocol.
⚡️ EVENT_BIND¶
Dispatched by SystemBuilder.dispatch_bind_event(...) when the container is
being configured.
Its main purpose is to allow applications to define services, by registering some service definitions with the container.
Dispatched as EVENT_BIND with a OnBindEvent instance.
Example
Here is an example of a listener coroutine for the EVENT_BIND event:
from whistle import AsyncEventDispatcher
from harp.config.events import EVENT_BIND, OnBindEvent
async def on_bind(event: OnBindEvent):
print("System is being bound")
if __name__ == "__main__":
# for example completeness only, you should use the system dispatcher
dispatcher = AsyncEventDispatcher()
dispatcher.add_listener(EVENT_BIND, on_bind)
⚡️ EVENT_BOUND¶
Dispatched by SystemBuilder.dispatch_bound_event(...) after the container has
been compiled to a provider. At this point, all service dependencies are resolved, instances
can be requested from the provider.
Its main purpose is to allow applications to instanciate and manipulate live services on startup.
Dispatched as EVENT_BOUND with a OnBoundEvent instance.
Example
Here is an example of a listener coroutine for the EVENT_BOUND event:
from whistle import AsyncEventDispatcher
from harp.config.events import EVENT_BOUND, OnBoundEvent
async def on_bound(event: OnBoundEvent):
print("System is bound")
if __name__ == "__main__":
# for example completeness only, you should use the system dispatcher
dispatcher = AsyncEventDispatcher()
dispatcher.add_listener(EVENT_BOUND, on_bound)
⚡️ EVENT_READY¶
Dispatched by SystemBuilder.dispatch_ready_event(...) after the system has been fully assembled and is (about to be) ready to start processing requests.
Dispatched as EVENT_READY with a OnReadyEvent instance.
The soon-to-be-served ASGI Application is available here, and this event is mostly used to decorate it
with ASGI middlewares (e.g. Sentry or Prometheus integrations).
Example
Here is an example of a listener coroutine for the EVENT_READY event:
from whistle import AsyncEventDispatcher
from harp.config.events import EVENT_READY, OnReadyEvent
async def on_ready(event: OnReadyEvent):
print("System is ready")
if __name__ == "__main__":
# for example completeness only, you should use the system dispatcher
dispatcher = AsyncEventDispatcher()
dispatcher.add_listener(EVENT_READY, on_ready)
⚡️ EVENT_SHUTDOWN¶
Dispatched by System.dispose(...) when the system is being shut
down.
Dispatched as EVENT_SHUTDOWN with a OnShutdown instance.
This event purpose is to allow applications to clean up resources on shutdown. For example, if applications define background asynchronous tasks, it’s a good idea to terminate them here.
Example
Here is an example of a listener coroutine for the EVENT_SHUTDOWN event:
from whistle import AsyncEventDispatcher
from harp.config.events import EVENT_SHUTDOWN, OnShutdownEvent
async def on_shutdown(event: OnShutdownEvent):
print("System is shutting down")
if __name__ == "__main__":
dispatcher = AsyncEventDispatcher()
dispatcher.add_listener(EVENT_SHUTDOWN, on_shutdown)
⇄️ Sequence Diagram¶
Todo
Add sequence diagram
🌲 Class Diagram¶
Core / ASGI Events¶
During the lifecycle of an ASGI Request, the harp.asgi module dispatches events to allow (low-level) applications
to process or filter inbound requests and outbound responses.
Note
The ASGI events are rather low-level, and are usually only used to implement framework-level features by the HARP Core. You should not need to use them in your application code, or at least, it should not be the first thing you go for.
If you need to hook into the request/response lifecycle, you are probably better of using either the Proxy Events for inbound request processing (and their associated responses), or the Http Client Events for outgoing requests (and their associated responses).
⚡️ EVENT_CORE_STARTED¶
Dispatched by the ASGIKernel when the “lifespan.startup” ASGI message is received.
It happens once per process, before any other ASGI messages are recevived.
Dispatched as EVENT_CORE_STARTED with a whistle.Event instance (default event class that contains no
specific context).
Example
Here is an example of a listener coroutine for the EVENT_CORE_STARTED event:
from whistle import AsyncEventDispatcher, Event
from harp.asgi.events import EVENT_CORE_STARTED
async def on_core_started(event: Event):
print(f"ASGI Core started: {event}")
if __name__ == "__main__":
# for example completeness only, you should use the system dispatcher
dispatcher = AsyncEventDispatcher()
dispatcher.add_listener(EVENT_CORE_STARTED, on_core_started)
⚡️ EVENT_CORE_REQUEST¶
Dispatched by the ASGIKernel when an inbound HttpRequest is received, before anything is done with it.
Listeners can use event.set_controller(...), bypassing further controller
resolution.
Dispatched as EVENT_CORE_REQUEST with a RequestEvent instance.
Example
Here is an example of a listener coroutine for the EVENT_CORE_REQUEST event:
from whistle import AsyncEventDispatcher
from harp.asgi.events import EVENT_CORE_REQUEST, RequestEvent
async def on_core_request(event: RequestEvent):
print(f"Request received: {event}")
if __name__ == "__main__":
# for example completeness only, you should use the system dispatcher
dispatcher = AsyncEventDispatcher()
dispatcher.add_listener(EVENT_CORE_REQUEST, on_core_request)
⚡️ EVENT_CORE_CONTROLLER¶
Dispatched by the ASGIKernel when a controller callable has been resolved by the
kernel’s controller resolver.
It is used to eventually modify the controller, for example with decorators, or change it altogether.
Dispatched as EVENT_CORE_CONTROLLER with a ControllerEvent instance.
Example
Here is an example of a listener coroutine for the EVENT_CORE_CONTROLLER event:
from whistle import AsyncEventDispatcher
from harp.asgi.events import EVENT_CORE_REQUEST, ControllerEvent
async def on_core_controller(event: ControllerEvent):
print(f"Controller requested: {event}")
if __name__ == "__main__":
# for example completeness only, you should use the system dispatcher
dispatcher = AsyncEventDispatcher()
dispatcher.add_listener(EVENT_CORE_REQUEST, on_core_controller)
⚡️ EVENT_CORE_VIEW¶
EVENT_CORE_VIEW is dispatched by the ASGIKernel when a controller
callable has been called but it did not return an HttpResponse.
It is used to implement custom response handlers, for example dictionaries return values.
If after it has been fully dispatched, the event does not contain a response, then a HTTP 500 response is returned.
Dispatched as EVENT_CORE_VIEW with a ViewEvent instance.
Example
Here is an example of a listener coroutine for the EVENT_CORE_VIEW event:
from whistle import AsyncEventDispatcher
from harp.asgi.events import EVENT_CORE_VIEW, ViewEvent
async def on_core_view(event: ViewEvent):
print(f"View received: {event}")
if __name__ == "__main__":
# for example completeness only, you should use the system dispatcher
dispatcher = AsyncEventDispatcher()
dispatcher.add_listener(EVENT_CORE_VIEW, on_core_view)
⚡️ EVENT_CORE_RESPONSE¶
EVENT_CORE_RESPONSE is dispatched by the ASGIKernel when an outbound
HttpResponse is about to be sent.
Listeners can use event.response = ... event attribute to change the response.
Dispatched as EVENT_CORE_RESPONSE with a ResponseEvent instance.
Example
Here is an example of a listener coroutine for the EVENT_CORE_RESPONSE event:
from whistle import AsyncEventDispatcher
from harp.asgi.events import EVENT_CORE_RESPONSE, ResponseEvent
async def on_core_response(event: ResponseEvent):
print(f"Response received: {event}")
if __name__ == "__main__":
# for example completeness only, you should use the system dispatcher
dispatcher = AsyncEventDispatcher()
dispatcher.add_listener(EVENT_CORE_RESPONSE, on_core_response)
⇄️ Sequence Diagram¶
Todo
Add sequence diagram