|
| 1 | +import asyncio |
| 2 | +import uuid |
| 3 | +from typing import Optional, Tuple |
| 4 | + |
| 5 | +from temporalio import common |
| 6 | +from temporalio.client import ( |
| 7 | + Client, |
| 8 | + WithStartWorkflowOperation, |
| 9 | + WorkflowHandle, |
| 10 | + WorkflowUpdateFailedError, |
| 11 | +) |
| 12 | +from temporalio.exceptions import ApplicationError |
| 13 | + |
| 14 | +from message_passing.update_with_start.lazy_initialization import TASK_QUEUE |
| 15 | +from message_passing.update_with_start.lazy_initialization.workflows import ( |
| 16 | + ShoppingCartItem, |
| 17 | + ShoppingCartWorkflow, |
| 18 | +) |
| 19 | + |
| 20 | + |
| 21 | +async def handle_add_item_request( |
| 22 | + session_id: str, item_id: str, quantity: int, temporal_client: Client |
| 23 | +) -> Tuple[Optional[int], WorkflowHandle]: |
| 24 | + """ |
| 25 | + Handle a client request to add an item to the shopping cart. The user is not logged in, but a session ID is |
| 26 | + available from a cookie, and we use this as the cart ID. The Temporal client was created at service-start |
| 27 | + time and is shared by all request handlers. |
| 28 | +
|
| 29 | + A Workflow Type exists that can be used to represent a shopping cart. The method uses update-with-start to |
| 30 | + add an item to the shopping cart, creating the cart if it doesn't already exist. |
| 31 | +
|
| 32 | + Note that the workflow handle is available, even if the Update fails. |
| 33 | + """ |
| 34 | + cart_id = f"cart-{session_id}" |
| 35 | + start_op = WithStartWorkflowOperation( |
| 36 | + ShoppingCartWorkflow.run, |
| 37 | + id=cart_id, |
| 38 | + id_conflict_policy=common.WorkflowIDConflictPolicy.USE_EXISTING, |
| 39 | + task_queue=TASK_QUEUE, |
| 40 | + ) |
| 41 | + try: |
| 42 | + price = await temporal_client.execute_update_with_start_workflow( |
| 43 | + ShoppingCartWorkflow.add_item, |
| 44 | + ShoppingCartItem(sku=item_id, quantity=quantity), |
| 45 | + start_workflow_operation=start_op, |
| 46 | + ) |
| 47 | + except WorkflowUpdateFailedError as err: |
| 48 | + if ( |
| 49 | + isinstance(err.cause, ApplicationError) |
| 50 | + and err.cause.type == "ItemUnavailableError" |
| 51 | + ): |
| 52 | + price = None |
| 53 | + else: |
| 54 | + raise err |
| 55 | + |
| 56 | + workflow_handle = await start_op.workflow_handle() |
| 57 | + |
| 58 | + return price, workflow_handle |
| 59 | + |
| 60 | + |
| 61 | +async def main(): |
| 62 | + print("🛒") |
| 63 | + session_id = f"session-{uuid.uuid4()}" |
| 64 | + temporal_client = await Client.connect("localhost:7233") |
| 65 | + subtotal_1, _ = await handle_add_item_request( |
| 66 | + session_id, "sku-123", 1, temporal_client |
| 67 | + ) |
| 68 | + subtotal_2, wf_handle = await handle_add_item_request( |
| 69 | + session_id, "sku-456", 1, temporal_client |
| 70 | + ) |
| 71 | + print(f"subtotals were, {[subtotal_1, subtotal_2]}") |
| 72 | + await wf_handle.signal(ShoppingCartWorkflow.checkout) |
| 73 | + final_order = await wf_handle.result() |
| 74 | + print(f"final order: {final_order}") |
| 75 | + |
| 76 | + |
| 77 | +if __name__ == "__main__": |
| 78 | + asyncio.run(main()) |
0 commit comments