-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
5ae91b2
commit 83421dd
Showing
23 changed files
with
519 additions
and
138 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
This example demonstrates how to configure your dependency injection (DI) framework (Dishka in this case) to work with Bazario: | ||
```python | ||
from bazario import Dispatcher, PipelineBehaviourRegistry | ||
from bazario.plugins.dishka import ( | ||
DishkaHandlerFinder, | ||
DishkaHandlerResolver, | ||
) | ||
from dishka import Provider, Scope, make_container | ||
|
||
def build_container() -> Container: | ||
main_provider = Provider(scope=Scope.REQUEST) | ||
|
||
main_provider.provide(AddPostHandler) | ||
main_provider.provide(WithParents[Dispatcher]) | ||
main_provider.provide(WithParents[DishkaHandlerFinder]) | ||
main_provider.provide(WithParents[DishkaHandlerResolver]) | ||
# Additional registrations (PostRepository, TransactionCommiter, etc.) | ||
|
||
return make_container(main_provider) | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
**Notifications** in Bazario represent events that are published in response to certain actions. They are used to notify other parts of the system about changes that have occurred, without requiring a return result. | ||
|
||
**Notification Handlers** are responsible for processing these notifications. | ||
|
||
Here's an example of defining a notification and its handlers: | ||
|
||
Define notifications and their handlers: | ||
```python | ||
from bazario import Notification, NotificationHandler | ||
|
||
@dataclass(frozen=True) | ||
class PostAdded(Notification): | ||
post_id: int | ||
user_id: int | ||
|
||
class PostAddedFirstHandler(NotificationHandler[PostAdded]): | ||
def handle(self, notification: PostAdded) -> None: | ||
logger.info( | ||
"Post first added: post_id=%s, user_id=%s", | ||
notification.post_id, notification.user_id, | ||
) | ||
|
||
class PostAddedSecondHandler(NotificationHandler[PostAdded]): | ||
def handle(self, notification: PostAdded) -> None: | ||
logger.info( | ||
"Post second added: post_id=%s, user_id=%s", | ||
notification.post_id, notification.user_id, | ||
) | ||
``` | ||
Register handlers in your container: | ||
``` python | ||
def build_container() -> Container: | ||
# ... | ||
main_provider.provide(PostAddedFirstHandler) | ||
main_provider.provide(PostAddedSecondHandler) | ||
# ... | ||
``` | ||
Implementation of notification publication within the request handler: | ||
``` python | ||
from bazario import Publisher | ||
|
||
class AddPostHandler(RequestHandler[AddPost, int]): | ||
def __init__( | ||
self, | ||
publisher: Publisher, # for notification publishing | ||
post_factory: PostFactory, | ||
user_provider: UserProvider, | ||
post_repository: PostRepository, | ||
transaction_commiter: TransactionCommiter, | ||
) -> None: | ||
self._publisher = publisher | ||
self._post_factory = post_factory | ||
self._user_provider = user_provider | ||
self._post_repository = post_repository | ||
self._transaction_commiter = transaction_commiter | ||
|
||
def handle(self, request: AddPost) -> int: | ||
user_id = self._user_provider.get_id() | ||
new_post = self._post_factory.create( | ||
title=request.title, | ||
content=request.content, | ||
owner_id=user_id, | ||
) | ||
self._post_repository.add(new_post) | ||
self._publisher.publish(PostAdded( | ||
post_id=new_post.id, | ||
user_id=user_id, | ||
)) # notification publishing | ||
self._transaction_commiter.commit() | ||
|
||
return new_post.id | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,134 @@ | ||
Pipeline behaviors in **Bazario** enable pre- and post-processing logic for requests and notifications. These behaviors form a chain around the core handler logic and can modify or enhance the data flow. | ||
|
||
### Defining Pipeline Behaviors | ||
```python | ||
from bazario import ( | ||
PipelineBehavior, | ||
Resolver, | ||
HandleNext, | ||
Request, | ||
Notification, | ||
) | ||
|
||
# Behavior for all requests | ||
class RequestLoggingBehavior(PipelineBehavior[Request, Any]): | ||
def handle( | ||
self, | ||
resolver: Resolver, | ||
target: Request, | ||
handle_next: HandleNext[Request, Any], | ||
) -> Any: | ||
logger = resolver.resolve(Logger) | ||
logger.log_info("Before request handler execution") | ||
response = handle_next(resolver, target) | ||
logger.log_info(f"After request handler execution. Response: {response}") | ||
|
||
return response | ||
|
||
# Behavior for all notifications | ||
class NotificationLoggingBehavior(PipelineBehavior[Notification, None]): | ||
def handle( | ||
self, | ||
resolver: Resolver, | ||
target: Notification, | ||
handle_next: HandleNext[Notification, None], | ||
) -> None: | ||
logger = resolver.resolve(Logger) | ||
logger.log_info("Before notification handler execution") | ||
handle_next(resolver, target) | ||
logger.log_info("After notification handler execution") | ||
|
||
# Behavior specific to AddPost request | ||
class AddPostLoggingBehavior(PipelineBehavior[AddPost, int]): | ||
def handle( | ||
self, | ||
resolver: Resolver, | ||
target: AddPost, | ||
handle_next: HandleNext[AddPost, int], | ||
) -> int: | ||
logger = resolver.resolve(Logger) | ||
logger.log_info("Before post addition") | ||
response = handle_next(resolver, target) | ||
logger.log_info(f"After post addition: id = {response}") | ||
|
||
return response | ||
|
||
# Behavior specific to PostAdded notification | ||
class PostAddedLoggingBehavior(PipelineBehavior[PostAdded, None]): | ||
def handle( | ||
self, | ||
resolver: Resolver, | ||
target: PostAdded, | ||
handle_next: HandleNext[PostAdded, None], | ||
) -> None: | ||
logger = resolver.resolve(Logger) | ||
logger.log_info("Before post added handler execution") | ||
handle_next(resolver, target) | ||
logger.log_info(f"After post added handler execution: id = {target.post_id}") | ||
``` | ||
|
||
### Registering Pipeline Behaviors | ||
Define the factory function for `PipelineBehaviorRegistry`. The order of behavior registration determines the execution sequence - behaviors are executed in the order they are added: | ||
|
||
```python | ||
from bazario import PipelineBehaviorRegistry | ||
|
||
def build_registry() -> PipelineBehaviorRegistry: | ||
registry = PipelineBehaviorRegistry() | ||
# Behaviors will execute in this order: | ||
# 1. RequestLoggingBehavior | ||
# 2. NotificationLoggingBehavior | ||
# 3. AddPostLoggingBehavior | ||
# 4. PostAddedLoggingBehavior | ||
registry.add_behaviours(Request, RequestLoggingBehaviour()) | ||
registry.add_behaviours(Notification, NotificationLoggingBehaviour()) | ||
registry.add_behaviours(AddPost, AddPostLoggingBehaviour()) | ||
registry.add_behaviours(PostAdded, PostAddedLoggingBehaviour()) | ||
|
||
return registry | ||
``` | ||
|
||
The execution order follows these rules: | ||
1. Global behaviors (registered for base types like `Request` or `Notification`) execute first | ||
2. Specific behaviors (registered for concrete types like `AddPost` or `PostAdded`) execute after global ones | ||
3. Within each category (global/specific), behaviors execute in the order they were registered | ||
4. For a single request/notification, all applicable behaviors form a chain in this order | ||
|
||
Example of execution flow for an `AddPost` request: | ||
```python | ||
def build_registry() -> PipelineBehaviourRegistry: | ||
registry = PipelineBehaviourRegistry() | ||
|
||
registry.add_behaviours(Request, RequestLoggingBehaviour()) | ||
registry.add_behaviours( | ||
AddPost, | ||
ValidationBehaviour(), | ||
MetricsBehaviour(), | ||
) | ||
|
||
return registry | ||
|
||
# Execution sequence for AddPost request: | ||
# 1. RequestLoggingBehaviour | ||
# 2. ValidationBehaviour | ||
# 3. MetricsBehaviour | ||
# 4. Actual AddPost handler | ||
``` | ||
|
||
Configure the IoC container: | ||
```python | ||
def build_container() -> Container: | ||
# ... | ||
main_provider.provide(build_registry) | ||
# Note: The Dispatcher depends on PipelineBehaviourRegistry. | ||
# If you're not using pipeline behaviors, register PipelineBehaviourRegistry directly: | ||
# main_provider.provide(PipelineBehaviourRegistry) | ||
# ... | ||
``` | ||
|
||
### Benefits of Pipeline Behaviors | ||
Pipeline behaviors solve several common issues: | ||
- Centralize cross-cutting concerns | ||
- Keep handlers focused on business logic | ||
- Enable flexible behavior execution order | ||
- Eliminate code duplication in validation and response modification |
Oops, something went wrong.