Skip to content

Commit

Permalink
Add Python Tour of Restate (#444)
Browse files Browse the repository at this point in the history
  • Loading branch information
gvdongen authored Sep 9, 2024
1 parent 953fcac commit b9b50ae
Show file tree
Hide file tree
Showing 12 changed files with 853 additions and 188 deletions.
32 changes: 32 additions & 0 deletions .github/workflows/pre-release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ on:
description: "sdk-typescript version (without prepending v)."
required: false
type: string
sdkPythonVersion:
description: "sdk-python version (without prepending v)."
required: false
type: string
sdkJavaVersion:
description: "sdk-java version (without prepending v)."
required: false
Expand Down Expand Up @@ -89,6 +93,14 @@ jobs:
field: TYPESCRIPT_SDK_VERSION
value: ${{ inputs.sdkTypescriptVersion }}

- name: Update restate.config.json with new Python sdk version
uses: jossef/[email protected]
if: ${{ inputs.sdkPythonVersion != '' }}
with:
file: restate.config.json
field: PYTHON_SDK_VERSION
value: ${{ inputs.sdkPythonVersion }}

- name: Update restate.config.json with new Java sdk version
uses: jossef/[email protected]
if: ${{ inputs.sdkJavaVersion != '' }}
Expand All @@ -109,6 +121,26 @@ jobs:
- name: Compile TypeScript code snippets
run: npm install --prefix code_snippets/ts && npm run build --prefix code_snippets/ts

# Upgrade Python code snippets if new version is provided
- name: Upgrade Python Restate SDK
if: github.event.inputs.sdkPythonVersion != ''
run: sed -i 's/restate_sdk==[0-9A-Za-z.-]*/restate_sdk=="${{ inputs.sdkPythonVersion }}"/' "code_snippets/python/requirements.txt"

# Test if Python code snippets compile
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.11'
- name: Install dependencies and check Python code snippets
run: |
cd code_snippets/python
python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
pip install mypy
python3 -m mypy .
deactivate
# Upgrade Java code snippets if new version is provided
- name: Find and replace restateVersion in build.gradle.kts for Java code snippets
if: ${{ inputs.sdkJavaVersion != '' }}
Expand Down
18 changes: 18 additions & 0 deletions .github/workflows/test-build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,24 @@ jobs:
exit 1
fi
# Setup Python
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.12'

# Test if Python code snippets compile
- name: Install dependencies and check Python code snippets
run: |
cd code_snippets/python
python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
pip install mypy
python3 -m mypy .
deactivate
# Setup Java
- uses: actions/setup-java@v3
with:
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,4 @@ yarn-error.log*
.yarn
/code_snippets/ts/node_modules/
/code_snippets/ts/dist/
/code_snippets/python/venv/
2 changes: 2 additions & 0 deletions code_snippets/python/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
restate_sdk==0.2.1
hypercorn
Empty file.
20 changes: 20 additions & 0 deletions code_snippets/python/src/get_started/auxiliary/email_client.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Copyright (c) 2024 - Restate Software, Inc., Restate GmbH
#
# This file is part of the Restate examples,
# which is released under the MIT license.
#
# You can find a copy of the license in the file LICENSE
# in the root directory of this repository or package or at
# https://github.com/restatedev/examples/

class EmailClient:

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
28 changes: 28 additions & 0 deletions code_snippets/python/src/get_started/auxiliary/payment_client.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# Copyright (c) 2024 - Restate Software, Inc., Restate GmbH
#
# This file is part of the Restate examples,
# which is released under the MIT license.
#
# You can find a copy of the license in the file LICENSE
# in the root directory of this repository or package or at
# https://github.com/restatedev/examples/

class PaymentClient:

def __init__(self):
self.i = 0

async def call(self, idempotency_key: str | None, 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")
29 changes: 29 additions & 0 deletions code_snippets/python/src/get_started/checkout.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import uuid

from restate import Service, ObjectContext

from auxiliary.email_client import EmailClient
from auxiliary.payment_client import PaymentClient
from tour import Order

payment_client = PaymentClient()
email_client = EmailClient()

checkout = Service("CheckoutService")


# <start_checkout>
@checkout.handler()
async def handle(ctx: ObjectContext, order: Order) -> bool:
# withClass highlight-line
total_price = len(order['tickets']) * 40

idempotency_key = await ctx.run("idempotency_key", lambda: str(uuid.uuid4()))

# withClass(1:3) highlight-line
async def pay():
return await payment_client.call(idempotency_key, total_price)
success = await ctx.run("payment", pay)

return success
# <end_checkout>
67 changes: 67 additions & 0 deletions code_snippets/python/src/get_started/tour.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
# Copyright (c) 2024 - Restate Software, Inc., Restate GmbH
#
# This file is part of the Restate examples,
# which is released under the MIT license.
#
# You can find a copy of the license in the file LICENSE
# in the root directory of this repository or package or at
# https://github.com/restatedev/examples/
import uuid
from datetime import timedelta
from typing import TypedDict, List

from restate import VirtualObject
from restate.context import ObjectContext, Serde
from restate.service import Service

from auxiliary.email_client import EmailClient
from auxiliary.payment_client import PaymentClient

cart = VirtualObject("CartObject")


@cart.handler()
async def my_handler(ctx: ObjectContext, order: str) -> bool:
ticket_id = ""

# <start_sleep>
await ctx.sleep(delta=timedelta(minutes=15))
# <end_sleep>

# <start_sleep_and_send>
await ctx.sleep(delta=timedelta(minutes=15))
ctx.object_send(unreserve, key=ticket_id, arg=None)
# <end_sleep_and_send>

return True


ticket = VirtualObject("TicketObject")


@ticket.handler()
async def unreserve(ctx: ObjectContext) -> bool:
return True


class Order(TypedDict):
user_id: str
tickets: List[str]


checkout = Service("CheckoutService")


# <start_uuid>
@checkout.handler()
async def handle(ctx: ObjectContext, order: Order) -> bool:
# withClass(1:3) highlight-line
idempotency_key = await ctx.run("idempotency_key", lambda: str(uuid.uuid4()))
print("My idempotency key is: ", idempotency_key)
raise Exception("Something happened!")

return True
# <end_uuid>



2 changes: 1 addition & 1 deletion code_snippets/ts/src/get_started/tour.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ const secondCheckoutService = restate.service({
const totalPrice = request.tickets.length * 40;

const idempotencyKey = ctx.rand.uuidv4();
// withClass highlight-line
// withClass(1:3) highlight-line
const success = await ctx.run(() =>
PaymentClient.get().call(idempotencyKey, totalPrice)
);
Expand Down
Loading

0 comments on commit b9b50ae

Please sign in to comment.