-
Notifications
You must be signed in to change notification settings - Fork 9
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
11 changed files
with
226 additions
and
0 deletions.
There are no files selected for viewing
3 changes: 3 additions & 0 deletions
3
patterns-use-cases/ticket-reservation/ticket-reservation-python/.gitignore
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,3 @@ | ||
venv | ||
.venv | ||
__pycache__/ |
55 changes: 55 additions & 0 deletions
55
patterns-use-cases/ticket-reservation/ticket-reservation-python/README.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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
# Restate Example: Ticket reservation system Python | ||
|
||
This example shows a subset of a ticket booking system. | ||
|
||
Restate is a system for easily building resilient applications using **distributed durable building blocks**. | ||
|
||
❓ Learn more about Restate from the [Restate documentation](https://docs.restate.dev). | ||
|
||
## Running the example | ||
|
||
To set up the example, use the following sequence of commands. | ||
|
||
Setup the virtual env: | ||
|
||
```shell | ||
python3 -m venv .venv | ||
source venv/bin/activate | ||
``` | ||
|
||
Install the requirements: | ||
|
||
```shell | ||
pip install -r requirements.txt | ||
``` | ||
|
||
Start the app as follows: | ||
|
||
```shell | ||
python3 -m hypercorn example/app:app | ||
``` | ||
|
||
Start the Restate Server ([other options here]()): | ||
|
||
```shell | ||
restate-server | ||
``` | ||
|
||
Register the service: | ||
|
||
```shell | ||
restate dp register http://localhost:8000 | ||
``` | ||
|
||
Then add a ticket to Mary's cart: | ||
|
||
```shell | ||
curl localhost:8080/cart/Mary/add_ticket -H 'content-type: application/json' -d '"seat2B"' | ||
``` | ||
|
||
Let Mary buy the ticket via: | ||
```shell | ||
curl -X POST localhost:8080/cart/Mary/checkout | ||
``` | ||
|
||
That's it! We managed to run the example, add a ticket to the user session cart, and buy it! |
Empty file.
7 changes: 7 additions & 0 deletions
7
patterns-use-cases/ticket-reservation/ticket-reservation-python/example/app.py
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,7 @@ | ||
import restate | ||
|
||
from example.cart_object import cart | ||
from example.checkout_service import checkout | ||
from example.ticket_object import ticket | ||
|
||
app = restate.app(services=[cart, checkout, ticket]) |
58 changes: 58 additions & 0 deletions
58
patterns-use-cases/ticket-reservation/ticket-reservation-python/example/cart_object.py
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,58 @@ | ||
from datetime import timedelta | ||
|
||
from restate.context import ObjectContext | ||
from restate.object import VirtualObject | ||
|
||
from example.checkout_service import handle | ||
from example.ticket_object import reserve, mark_as_sold, unreserve | ||
|
||
cart = VirtualObject("cart") | ||
|
||
|
||
@cart.handler() | ||
async def add_ticket(ctx: ObjectContext, ticket_id: str) -> bool: | ||
reserved = await ctx.object_call(reserve, key=ticket_id, arg=None) | ||
|
||
if reserved: | ||
tickets = await ctx.get("tickets") or [] | ||
tickets.append(ticket_id) | ||
ctx.set("tickets", tickets) | ||
|
||
ctx.object_send(expire_ticket, key=ctx.key(), arg=ticket_id, send_delay=timedelta(minutes=15)) | ||
|
||
return reserved | ||
|
||
|
||
@cart.handler() | ||
async def checkout(ctx: ObjectContext) -> bool: | ||
tickets = await ctx.get("tickets") or [] | ||
|
||
if len(tickets) == 0: | ||
return False | ||
|
||
success = await ctx.service_call(handle, arg={'user_id': ctx.key(), | ||
'tickets': tickets}) | ||
|
||
if success: | ||
for ticket in tickets: | ||
ctx.object_send(mark_as_sold, key=ticket, arg=None) | ||
|
||
ctx.clear("tickets") | ||
|
||
return success | ||
|
||
|
||
@cart.handler() | ||
async def expire_ticket(ctx: ObjectContext, ticket_id: str): | ||
tickets = await ctx.get("tickets") or [] | ||
|
||
try: | ||
ticket_index = tickets.index(ticket_id) | ||
except ValueError: | ||
ticket_index = -1 | ||
|
||
if ticket_index != -1: | ||
tickets.pop(ticket_index) | ||
ctx.set("tickets", tickets) | ||
|
||
ctx.object_send(unreserve, key=ticket_id, arg=None) |
36 changes: 36 additions & 0 deletions
36
patterns-use-cases/ticket-reservation/ticket-reservation-python/example/checkout_service.py
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,36 @@ | ||
import uuid | ||
from typing import TypedDict, List | ||
from restate.context import ObjectContext, Serde | ||
from restate.service import Service | ||
|
||
from example.utils.email_client import EmailClient | ||
from example.utils.payment_client import PaymentClient | ||
|
||
|
||
class Order(TypedDict): | ||
user_id: str | ||
tickets: List[str] | ||
|
||
|
||
payment_client = PaymentClient() | ||
email_client = EmailClient() | ||
|
||
checkout = Service("checkout") | ||
|
||
|
||
@checkout.handler() | ||
async def handle(ctx: ObjectContext, order: Order) -> bool: | ||
total_price = len(order['tickets']) * 40 | ||
|
||
idempotency_key = await ctx.run("idempotency_key", lambda: str(uuid.uuid4())) | ||
|
||
async def pay(): | ||
return await payment_client.call(idempotency_key, total_price) | ||
success = await ctx.run("payment", pay) | ||
|
||
if success: | ||
await ctx.run("send_success_email", lambda: email_client.notify_user_of_payment_success(order['user_id'])) | ||
else: | ||
await ctx.run("send_failure_email", lambda: email_client.notify_user_of_payment_failure(order['user_id'])) | ||
|
||
return success |
32 changes: 32 additions & 0 deletions
32
patterns-use-cases/ticket-reservation/ticket-reservation-python/example/ticket_object.py
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,32 @@ | ||
from restate.context import ObjectContext | ||
from restate.object import VirtualObject | ||
|
||
|
||
ticket = VirtualObject("ticket") | ||
|
||
|
||
@ticket.handler() | ||
async def reserve(ctx: ObjectContext) -> bool: | ||
status = await ctx.get("status") or "AVAILABLE" | ||
|
||
if status == "AVAILABLE": | ||
ctx.set("status", "RESERVED") | ||
return True | ||
else: | ||
return False | ||
|
||
|
||
@ticket.handler() | ||
async def unreserve(ctx: ObjectContext): | ||
status = await ctx.get("status") or "AVAILABLE" | ||
|
||
if status != "SOLD": | ||
ctx.clear("status") | ||
|
||
|
||
@ticket.handler() | ||
async def mark_as_sold(ctx: ObjectContext): | ||
status = await ctx.get("status") or "AVAILABLE" | ||
|
||
if status == "RESERVED": | ||
ctx.set("status", "SOLD") |
Empty file.
14 changes: 14 additions & 0 deletions
14
...erns-use-cases/ticket-reservation/ticket-reservation-python/example/utils/email_client.py
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,14 @@ | ||
class EmailClient: | ||
|
||
def __init__(self): | ||
self.i = 0 | ||
|
||
def notify_user_of_payment_success(self, user_id: str): | ||
print(f"Notifying user {user_id} of payment success") | ||
# send the email | ||
return True | ||
|
||
def notify_user_of_payment_failure(self, user_id: str): | ||
print(f"Notifying user {user_id} of payment failure") | ||
# send the email | ||
return True |
19 changes: 19 additions & 0 deletions
19
...ns-use-cases/ticket-reservation/ticket-reservation-python/example/utils/payment_client.py
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,19 @@ | ||
class PaymentClient: | ||
|
||
def __init__(self): | ||
self.i = 0 | ||
|
||
async def call(self, idempotency_key: str, amount: float) -> bool: | ||
print(f"Payment call succeeded for idempotency key {idempotency_key} and amount {amount}") | ||
# do the call | ||
return True | ||
|
||
async def failing_call(self, idempotency_key: str, amount: float) -> bool: | ||
if self.i >= 2: | ||
print(f"Payment call succeeded for idempotency key {idempotency_key} and amount {amount}") | ||
i = 0 | ||
return True | ||
else: | ||
print(f"Payment call failed for idempotency key {idempotency_key} and amount {amount}. Retrying...") | ||
self.i += 1 | ||
raise Exception("Payment call failed") |
2 changes: 2 additions & 0 deletions
2
patterns-use-cases/ticket-reservation/ticket-reservation-python/requirements.txt
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,2 @@ | ||
restate_sdk | ||
hypercorn |