-
Notifications
You must be signed in to change notification settings - Fork 10
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
Showing
22 changed files
with
266 additions
and
31 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
# Elasticsearch | ||
|
||
To use Elasticsearch as a database provider, use the below configuration setting: | ||
|
||
```toml | ||
[databases.elasticsearch] | ||
provider = "elasticsearch" | ||
database_uri = "{'hosts': ['localhost']}" | ||
namespace_prefix = "${PROTEAN_ENV}" | ||
settings = "{'number_of_shards': 3}" | ||
``` | ||
|
||
## Options | ||
|
||
Additional options for finer control: | ||
|
||
### namespace_prefix =IE${lasticsearch instance are prefixed with the specified stri}norexample, if the namespace prefix is `prod`, the index for aggregate | ||
`Person` will be `prod-person`. | ||
|
||
### NAMESPACE_SEPARATOR | ||
|
||
Custom character to join namespace_prefix =n ${Default} yphen(`-`). For example, with `NAMESPACE_SEPARATOR` as `_` and namespace | ||
prefix as `prod`, the index of aggregate `Person` will be `prod_person`. | ||
|
||
### SETTINGS | ||
|
||
Index settings passed as-is to Elasticsearch instance. | ||
|
||
## Elasticsearch Model | ||
|
||
Note that if you supply a custom Elasticsearch Model with an `Index` inner class, the options specified in the | ||
inner class override those at the config level. | ||
|
||
In the sample below, with the configuration settings specified above, the options at Aggregate level will be | ||
overridden and the Elasticsearch Model will have the default index value `*` and number of shards as `1`. | ||
|
||
```python | ||
class Person(BaseAggregate): | ||
name = String() | ||
about = Text() | ||
|
||
class Meta: | ||
schema_name = "people" | ||
|
||
class PeopleModel(ElasticsearchModel): | ||
name = Text(fields={"raw": Keyword()}) | ||
about = Text() | ||
|
||
class Index: | ||
settings = {"number_of_shards": 1} | ||
``` |
This file was deleted.
Oops, something went wrong.
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
10 changes: 6 additions & 4 deletions
10
docs/guides/persist-state/index.md → docs/guides/change-state/index.md
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
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
File renamed without changes.
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
This file was deleted.
Oops, something went wrong.
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,65 @@ | ||
# Event Handlers | ||
|
||
Event handlers consume events raised in an aggregate and help sync the state of | ||
the aggregate with other aggregates and other systems. They are the preferred | ||
mechanism to update multiple aggregates. | ||
|
||
## Defining an Event Handler | ||
|
||
Event Handlers are defined with the `Domain.event_handler` decorator. Below is | ||
a simplified example of an Event Handler connected to `Inventory` aggregate | ||
syncing stock levels corresponding to changes in the `Order` aggregate. | ||
|
||
```python hl_lines="26-27 44" | ||
{! docs_src/guides/propagate-state/001.py !} | ||
``` | ||
|
||
1. `Order` aggregate fires `OrderShipped` event on book being shipped. | ||
|
||
2. Event handler picks up the event and updates stock levels in `Inventory` | ||
aggregate. | ||
|
||
Simulating a hypothetical example, we can see that the stock levels were | ||
decreased in response to the `OrderShipped` event. | ||
|
||
```shell hl_lines="21" | ||
In [1]: order = Order(book_id=1, quantity=10, total_amount=100) | ||
|
||
In [2]: domain.repository_for(Order).add(order) | ||
Out[2]: <Order: Order object (id: 62f8fa8d-2963-4539-bd21-860d3bab639e)> | ||
|
||
In [3]: inventory = Inventory(book_id=1, in_stock=100) | ||
|
||
In [4]: domain.repository_for(Inventory).add(inventory) | ||
Out[4]: <Inventory: Inventory object (id: 9272d70f-b796-417d-8f30-e01302d9f1a9)> | ||
|
||
In [5]: order.ship_order() | ||
|
||
In [6]: domain.repository_for(Order).add(order) | ||
Out[6]: <Order: Order object (id: 62f8fa8d-2963-4539-bd21-860d3bab639e)> | ||
|
||
In [7]: stock = domain.repository_for(Inventory).get(inventory.id) | ||
|
||
In [8]: stock.to_dict() | ||
Out[8]: { | ||
'book_id': '1', | ||
'in_stock': 90, | ||
'id': '9272d70f-b796-417d-8f30-e01302d9f1a9' | ||
} | ||
|
||
In [9]: | ||
``` | ||
|
||
## Configuration Options | ||
|
||
- **`part_of`**: The aggregate to which the event handler is connected. | ||
- **`stream_name`**: The event handler listens to events on this stream. | ||
The stream name defaults to the aggregate's stream. This option comes handy | ||
when the event handler belongs to an aggregate and needs to listen to another | ||
aggregate's events. | ||
- **`source_stream`**: When specified, the event handler only consumes events | ||
generated in response to events or commands from this original stream. | ||
For example, `EmailNotifications` event handler listening to `OrderShipped` | ||
events can be configured to generate a `NotificationSent` event only when the | ||
`OrderShipped` event (in stream `orders`) is generated in response to a | ||
`ShipOrder` (in stream `manage_order`) command. |
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 @@ | ||
# Propagate State |
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
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,51 @@ | ||
from protean import Domain, handle | ||
from protean.fields import Identifier, Integer, String | ||
|
||
domain = Domain(__file__, load_toml=False) | ||
domain.config["event_processing"] = "sync" | ||
|
||
|
||
@domain.event(part_of="Order") | ||
class OrderShipped: | ||
order_id = Identifier(required=True) | ||
book_id = Identifier(required=True) | ||
quantity = Integer(required=True) | ||
total_amount = Integer(required=True) | ||
|
||
|
||
@domain.aggregate | ||
class Order: | ||
book_id = Identifier(required=True) | ||
quantity = Integer(required=True) | ||
total_amount = Integer(required=True) | ||
status = String(choices=["PENDING", "SHIPPED", "DELIVERED"], default="PENDING") | ||
|
||
def ship_order(self): | ||
self.status = "SHIPPED" | ||
|
||
self.raise_( # (1) | ||
OrderShipped( | ||
order_id=self.id, | ||
book_id=self.book_id, | ||
quantity=self.quantity, | ||
total_amount=self.total_amount, | ||
) | ||
) | ||
|
||
|
||
@domain.aggregate | ||
class Inventory: | ||
book_id = Identifier(required=True) | ||
in_stock = Integer(required=True) | ||
|
||
|
||
@domain.event_handler(part_of=Inventory, stream_name="order") | ||
class ManageInventory: | ||
@handle(OrderShipped) | ||
def reduce_stock_level(self, event: OrderShipped): | ||
repo = domain.repository_for(Inventory) | ||
inventory = repo._dao.find_by(book_id=event.book_id) | ||
|
||
inventory.in_stock -= event.quantity # (2) | ||
|
||
repo.add(inventory) |
Oops, something went wrong.