You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
This sample workflow processes an expense request. It demonstrates human-in-the loop processing and asynchronous activity completion.
3
+
This sample workflow processes an expense request. It demonstrates human-in-the loop processing using Temporal's signal mechanism.
4
4
5
5
## Overview
6
6
7
7
This sample demonstrates the following workflow:
8
8
9
9
1.**Create Expense**: The workflow executes the `create_expense_activity` to initialize a new expense report in the external system.
10
10
11
-
2.**Wait for Decision**: The workflow calls `wait_for_decision_activity`, which demonstrates asynchronous activity completion. The activity registers itself for external completion using its task token, then calls `activity.raise_complete_async()` to signal that it will complete later without blocking the worker.
11
+
2.**Register for Decision**: The workflow calls `register_for_decision_activity`, which registers the workflow with the external UI system so it can receive signals when decisions are made.
12
12
13
-
3.**Async Completion**: When a human approves or rejects the expense, an external process uses the stored task token to call `workflow_client.get_async_activity_handle(task_token).complete()`, notifying Temporal that the waiting activity has finished and providing the decision result.
13
+
3.**Wait for Signal**: The workflow uses `workflow.wait_condition()` to wait for an external signal containing the approval/rejection decision.
14
14
15
-
4.**Process Payment**: Once the workflow receives the approval decision, it executes the `payment_activity` to complete the simulated expense processing.
15
+
4.**Signal-Based Completion**: When a human approves or rejects the expense, the external UI system sends a signal to the workflow using `workflow_handle.signal()`, providing the decision result.
16
16
17
-
This pattern enables human-in-the-loop workflows where activities can wait as long as necessary for external decisions without consuming worker resources or timing out.
17
+
5.**Process Payment**: Once the workflow receives the approval decision via signal, it executes the `payment_activity` to complete the simulated expense processing.
18
+
19
+
This pattern enables human-in-the-loop workflows where workflows can wait as long as necessary for external decisions using Temporal's durable signal mechanism.
18
20
19
21
## Steps To Run Sample
20
22
@@ -29,35 +31,53 @@ This pattern enables human-in-the-loop workflows where activities can wait as lo
29
31
```
30
32
* Start expense workflow execution:
31
33
```bash
34
+
# Start workflow and return immediately (default)
32
35
uv run -m expense.starter
36
+
37
+
# Start workflow and wait for completion
38
+
uv run -m expense.starter --wait
39
+
40
+
# Start workflow with custom expense ID
41
+
uv run -m expense.starter --expense-id "my-expense-123"
42
+
43
+
# Start workflow with custom ID and wait for completion
44
+
uv run -m expense.starter --wait --expense-id "my-expense-123"
33
45
```
34
46
* When you see the console print out that the expense is created, go to [localhost:8099/list](http://localhost:8099/list) to approve the expense.
35
47
* You should see the workflow complete after you approve the expense. You can also reject the expense.
36
48
37
49
## Running Tests
38
50
39
51
```bash
40
-
# Run all tests
41
-
uv run pytest expense/test_workflow.py -v
52
+
# Run all expense tests
53
+
uv run -m pytest tests/expense/ -v
54
+
55
+
# Run specific test categories
56
+
uv run -m pytest tests/expense/test_expense_workflow.py -v # Workflow tests
57
+
uv run -m pytest tests/expense/test_expense_activities.py -v # Activity tests
58
+
uv run -m pytest tests/expense/test_expense_integration.py -v # Integration tests
59
+
uv run -m pytest tests/expense/test_ui.py -v # UI tests
42
60
43
61
# Run a specific test
44
-
uv run pytest expense/test_workflow.py::TestSampleExpenseWorkflow::test_workflow_with_mock_activities -v
62
+
uv run -m pytest tests/expense/test_expense_workflow.py::TestWorkflowPaths::test_workflow_approved_complete_flow -v
45
63
```
46
64
47
65
## Key Concepts Demonstrated
48
66
49
67
***Human-in-the-Loop Workflows**: Long-running workflows that wait for human interaction
50
-
***Async Activity Completion**: Using `activity.raise_complete_async()` to indicate an activity will complete asynchronously, then calling `complete()` on a handle to the async activity.
51
-
***External System Integration**: Communication between workflows and external systems via web services.
68
+
***Workflow Signals**: Using `workflow.signal()` and `workflow.wait_condition()` for external communication
69
+
***Signal-Based Completion**: External systems sending signals to workflows for asynchronous decision-making
70
+
***External System Integration**: Communication between workflows and external systems via web services and signals
If you see the workflow failed, the cause may be a port conflict. You can try to change to a different port number in `__init__.py`. Then rerun everything.
56
76
57
77
## Files
58
78
59
-
*`workflow.py` - The main expense processing workflow
60
-
*`activities.py` - Three activities: create expense, wait for decision, process payment
61
-
*`ui.py` - A demonstration expense approval system web UI
62
-
*`worker.py` - Worker to run workflows
63
-
*`starter.py` - Client to start workflow executions by submitting an expense report
79
+
*`workflow.py` - The main expense processing workflow with signal handling
80
+
*`activities.py` - Three activities: create expense, register for decision, process payment
81
+
*`ui.py` - A demonstration expense approval system web UI with signal sending
82
+
*`worker.py` - Worker to run workflows and activities with HTTP client lifecycle management
83
+
*`starter.py` - Client to start workflow executions with optional completion waiting
0 commit comments