diff --git a/README.md b/README.md index f33b1b0..44cdbc9 100644 --- a/README.md +++ b/README.md @@ -36,6 +36,23 @@ poetry run python run_workflow.py ![](stat/../static/webui_failure.png) ![](static/failure.gif) + +### Demo: Recover forward + +Enter your booking information in the Flask app . then see the tasks in the Web UI at . +Select your running or completed Workflow ID. +Under **Recent** events, select the failed Activity, `book_flight` (in compact view). +Under **ActivityTaskStarted** you'll see the Attempts (5), and the stack trace message letting you know the last failed attempt. + +### Demo: Recover backwards + +In the `book_workflow.py` modify the global variable `ATTEMPTS_FLIGHT = 5` to `ATTEMPTS_FLIGHT = 2`, so that the `book_flight` Activity attempts a retry twice. +Renter your booking information in the Flask app , then see the tasks in the Web UI at . +Select your running or completed Workflow ID. +Under **Recent** events, select the failed Activity, `book_flight` (in compact view). +Under **ActivityTaskStarted** you'll see the Attempts (2), and the stack trace message letting you know the last failed attempt. +Then notice how the Workflow executes the compensations. + ## Design The booking saga is implemented using the Temporal Workflow framework, which provides a robust and fault-tolerant platform for coordinating distributed transactions. diff --git a/activities.py b/activities.py index 875da48..e745614 100644 --- a/activities.py +++ b/activities.py @@ -1,7 +1,8 @@ -from temporalio import activity import asyncio from dataclasses import dataclass +from temporalio import activity + @dataclass class BookVacationInput: @@ -25,7 +26,7 @@ async def book_hotel(input: BookVacationInput) -> str: @activity.defn async def book_flight(input: BookVacationInput) -> str: - if activity.info().attempt < 5: + if activity.info().attempt < 4: activity.heartbeat( f"Invoking activity, attempt number {activity.info().attempt}" ) diff --git a/book_workflow.py b/book_workflow.py index fb85240..4c81131 100644 --- a/book_workflow.py +++ b/book_workflow.py @@ -1,11 +1,13 @@ -from temporalio import workflow from datetime import timedelta + +from temporalio import workflow from temporalio.common import RetryPolicy with workflow.unsafe.imports_passed_through(): - from activities import book_car, book_hotel, book_flight, BookVacationInput + from activities import BookVacationInput, book_car, book_flight, book_hotel + +ATTEMPTS_FLIGHT = 5 -ATTEMPTS_FLIGHT = 3 @workflow.defn class BookWorkflow: @@ -15,7 +17,7 @@ async def run(self, input: BookVacationInput): try: compensations.append("undo_book_car") - output = " " + await workflow.execute_activity( + output = await workflow.execute_activity( book_car, input, start_to_close_timeout=timedelta(seconds=10), diff --git a/run_worker.py b/run_worker.py index 44c584b..c29c0d2 100644 --- a/run_worker.py +++ b/run_worker.py @@ -2,13 +2,14 @@ from temporalio.client import Client from temporalio.worker import Worker + from activities import ( book_car, - book_hotel, book_flight, + book_hotel, undo_book_car, - undo_book_hotel, undo_book_flight, + undo_book_hotel, ) from book_workflow import BookWorkflow diff --git a/run_workflow.py b/run_workflow.py index d3daf66..c57e63a 100644 --- a/run_workflow.py +++ b/run_workflow.py @@ -1,10 +1,12 @@ +import uuid + +from flask import Flask, render_template, request from temporalio.client import Client +from activities import BookVacationInput + # Import the workflow from the previous code from book_workflow import BookWorkflow -from activities import BookVacationInput -from flask import Flask, request, render_template -import uuid app = Flask(__name__) @@ -16,7 +18,7 @@ async def display_form(): @app.route("/book", methods=["POST"]) async def book_vacation(): - user_id = f'{request.form.get("name")}-{str(uuid.uuid4( ))}' + user_id = f'{request.form.get("name").replace(" ", "-").lower()}-{str(uuid.uuid4().int)[:6]}' car = request.form.get("car") hotel = request.form.get("hotel") flight = request.form.get("flight") diff --git a/templates/book_vacation.html b/templates/book_vacation.html index 2a0b8a7..87d35ad 100644 --- a/templates/book_vacation.html +++ b/templates/book_vacation.html @@ -1,7 +1,9 @@ - Book a Vacation + Temporal Book a Vacation + + -

Book a Vacation

+

Temporal Book a Vacation

+

GitHub: github.com/temporalio

+

Docs: docs.temporal.io

+

Eliminate complex error or retry logic, avoid callbacks, and ensure that every workflow you start, completes. Temporal delivers durable execution for your services and applications.

Book a Vacation type="text" name="car" id="car" - value="Toyota Supra" + value="Ford 150" required - placeholder="Toyota Supra" + placeholder="Ford 150" />