Skip to content

Commit 4362c80

Browse files
committed
Merge remote-tracking branch 'origin/main' into convert-activities-to-sync
2 parents 6c450c8 + cd23a9c commit 4362c80

45 files changed

Lines changed: 3480 additions & 3815 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/ci.yml

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ jobs:
2121
runsOn: macos-14
2222
runs-on: ${{ matrix.runsOn || matrix.os }}
2323
steps:
24+
- uses: astral-sh/setup-uv@v5
2425
- name: Print build information
2526
run: "echo head_ref: ${{ github.head_ref }}, ref: ${{ github.ref }}, os: ${{ matrix.os }}, python: ${{ matrix.python }}"
2627
- uses: actions/checkout@v4
@@ -29,10 +30,8 @@ jobs:
2930
- uses: actions/setup-python@v5
3031
with:
3132
python-version: ${{ matrix.python }}
32-
# Using fixed Poetry version until
33-
# https://github.com/python-poetry/poetry/pull/7694 is fixed
34-
- run: python -m pip install --upgrade wheel "poetry==1.4.0" poethepoet
35-
- run: poetry install --with pydantic_converter --with dsl --with encryption --with trio_async
33+
- run: uv tool install poethepoet
34+
- run: uv sync --group=dsl --group=encryption --group=trio-async
3635
- run: poe lint
3736
- run: mkdir junit-xml
3837
- run: poe test -s --junit-xml=junit-xml/${{ matrix.python }}--${{ matrix.os }}.xml
@@ -41,17 +40,17 @@ jobs:
4140
- name: Uninstall pydantic
4241
shell: bash
4342
run: |
44-
echo y | poetry run pip uninstall pydantic
45-
echo y | poetry run pip uninstall pydantic-core
46-
poetry run pip install pydantic==1.10
43+
echo y | uv run pip uninstall pydantic
44+
echo y | uv run pip uninstall pydantic-core
45+
uv run pip install pydantic==1.10
4746
poe test -s --junit-xml=junit-xml/${{ matrix.python }}--${{ matrix.os }}--pydantic-v1.xml tests/pydantic_converter_v1/workflow_test.py
4847
4948
# On latest, run gevent test
5049
- name: Gevent test
5150
if: ${{ matrix.python == '3.12' }}
5251
run: |
53-
poetry install --with gevent
54-
poetry run python gevent_async/test/run_combined.py
52+
uv sync --group gevent
53+
uv run gevent_async/test/run_combined.py
5554
5655
- name: Upload junit-xml artifacts
5756
uses: actions/upload-artifact@v4

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
.venv
22
.idea
33
__pycache__
4+
/.vscode/

README.md

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,26 @@
11
# Temporal Python SDK Samples
22

3-
This is the set of Python samples for the [Python SDK](https://github.com/temporalio/sdk-python).
3+
This is a collection of samples showing how to use the [Python SDK](https://github.com/temporalio/sdk-python).
44

55
## Usage
66

77
Prerequisites:
88

9-
* Python >= 3.9
10-
* [Poetry](https://python-poetry.org)
9+
* [uv](https://docs.astral.sh/uv/)
1110
* [Temporal CLI installed](https://docs.temporal.io/cli#install)
1211
* [Local Temporal server running](https://docs.temporal.io/cli/server#start-dev)
1312

13+
The SDK requires Python >= 3.9. You can install Python using uv. For example,
14+
15+
uv python install 3.13
16+
1417
With this repository cloned, run the following at the root of the directory:
1518

16-
poetry install
19+
uv sync
1720

18-
That loads all required dependencies. Then to run a sample, usually you just run it in Python. For example:
21+
That loads all required dependencies. Then to run a sample, usually you just run it under uv. For example:
1922

20-
poetry run python hello/hello_activity.py
23+
uv run hello/hello_activity.py
2124

2225
Some examples require extra dependencies. See each sample's directory for specific instructions.
2326

@@ -81,7 +84,7 @@ Some examples require extra dependencies. See each sample's directory for specif
8184

8285
Running the tests requires `poe` to be installed.
8386

84-
python -m pip install poethepoet
87+
uv tool install poethepoet
8588

8689
Once you have `poe` installed you can run:
8790

activity_worker/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,6 @@ First run the Go workflow worker by running this in the `go_workflow` directory
88

99
Then in another terminal, run the sample from this directory:
1010

11-
poetry run python activity_worker.py
11+
uv run activity_worker.py
1212

1313
The Python code will invoke the Go workflow which will execute the Python activity and return.

bedrock/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,6 @@ These examples use Amazon's Python SDK (Boto3). To configure Boto3 to use your A
2020

2121
For these sample, the optional `bedrock` dependency group must be included. To include, run:
2222

23-
poetry install --with bedrock
23+
uv sync --group bedrock
2424

2525
There are 3 Bedrock samples, see the README.md in each sub-directory for instructions on running each.

bedrock/basic/README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ A basic Bedrock workflow. Starts a workflow with a prompt, generates a response
44

55
To run, first see `samples-python` [README.md](../../README.md), and `bedrock` [README.md](../README.md) for prerequisites specific to this sample. Once set up, run the following from this directory:
66

7-
1. Run the worker: `poetry run python run_worker.py`
7+
1. Run the worker: `uv run run_worker.py`
88
2. In another terminal run the client with a prompt:
99

10-
e.g. `poetry run python send_message.py 'What animals are marsupials?'`
10+
e.g. `uv run send_message.py 'What animals are marsupials?'`

bedrock/entity/README.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,16 @@ Multi-Turn Chat using an Entity Workflow. The workflow runs forever unless expli
44

55
To run, first see `samples-python` [README.md](../../README.md), and `bedrock` [README.md](../README.md) for prerequisites specific to this sample. Once set up, run the following from this directory:
66

7-
1. Run the worker: `poetry run python run_worker.py`
7+
1. Run the worker: `uv run run_worker.py`
88
2. In another terminal run the client with a prompt.
99

10-
Example: `poetry run python send_message.py 'What animals are marsupials?'`
10+
Example: `uv run send_message.py 'What animals are marsupials?'`
1111

1212
3. View the worker's output for the response.
1313
4. Give followup prompts by signaling the workflow.
1414

15-
Example: `poetry run python send_message.py 'Do they lay eggs?'`
15+
Example: `uv run send_message.py 'Do they lay eggs?'`
1616
5. Get the conversation history summary by querying the workflow.
1717

18-
Example: `poetry run python get_history.py`
19-
6. To end the chat session, run `poetry run python end_chat.py`
18+
Example: `uv run get_history.py`
19+
6. To end the chat session, run `uv run end_chat.py`

bedrock/signals_and_queries/README.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,16 @@ Adding signals & queries to the [basic Bedrock sample](../1_basic). Starts a wor
44

55
To run, first see `samples-python` [README.md](../../README.md), and `bedrock` [README.md](../README.md) for prerequisites specific to this sample. Once set up, run the following from this directory:
66

7-
1. Run the worker: `poetry run python run_worker.py`
7+
1. Run the worker: `uv run run_worker.py`
88
2. In another terminal run the client with a prompt.
99

10-
Example: `poetry run python send_message.py 'What animals are marsupials?'`
10+
Example: `uv run send_message.py 'What animals are marsupials?'`
1111

1212
3. View the worker's output for the response.
1313
4. Give followup prompts by signaling the workflow.
1414

15-
Example: `poetry run python send_message.py 'Do they lay eggs?'`
15+
Example: `uv run send_message.py 'Do they lay eggs?'`
1616
5. Get the conversation history by querying the workflow.
1717

18-
Example: `poetry run python get_history.py`
18+
Example: `uv run get_history.py`
1919
6. The workflow will timeout after inactivity.

canary/README.md

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
# Event Loop Canary Sample
2+
3+
This can help you determine if your event loop is clogged.
4+
5+
The idea is that you could add this canary workflow
6+
to your worker initialization, and
7+
it will log the delays in your event loop.
8+
9+
> Note: it doesn't tell you what is clogging it, but it tells you
10+
> whether something is clogging it.
11+
12+
## Example
13+
14+
In one terminal, run:
15+
16+
```txt
17+
$ poetry run python canary/your_workflows.py
18+
19+
# no output
20+
```
21+
22+
And in another, run the following:
23+
24+
```txt
25+
$ poetry run python canary/run_canary_worker.py
26+
27+
Your activity finished after 0.5 seconds
28+
Your activity finished after 1.3 seconds
29+
Your activity finished after 1.3 seconds
30+
The canary detected 1.1774 seconds of event loop delay.
31+
Your activity finished after 1.4 seconds
32+
Your activity finished after 1.1 seconds
33+
Your activity finished after 1.2 seconds
34+
The canary detected 0.7662 seconds of event loop delay.
35+
Your activity finished after 1.3 seconds
36+
Your activity finished after 0.8 seconds
37+
Your activity finished after 1.3 seconds
38+
The canary detected 0.4724 seconds of event loop delay.
39+
Your activity finished after 0.9 seconds
40+
Your activity finished after 1.3 seconds
41+
Your activity finished after 1.3 seconds
42+
The canary detected 0.6033 seconds of event loop delay.
43+
Your activity finished after 1.4 seconds
44+
Your activity finished after 1.4 seconds
45+
Your activity finished after 0.7 seconds
46+
The canary detected 0.5424 seconds of event loop delay.
47+
Your activity finished after 1.2 seconds
48+
Your activity finished after 0.7 seconds
49+
Your activity finished after 0.7 seconds
50+
Your activity finished after 0.9 seconds
51+
The canary detected 0.6584 seconds of event loop delay.
52+
...
53+
```

canary/run_canary_worker.py

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
"""
2+
In your worker initialization, you can add the canary workflow.
3+
"""
4+
5+
from datetime import timedelta
6+
import asyncio
7+
import time
8+
9+
from temporalio import activity, workflow
10+
from temporalio.client import Client
11+
from temporalio.worker import Worker
12+
13+
from canary.your_workflows import YourWorkflow, your_activity
14+
15+
_SECONDS_BETWEEN_CANARY_CHECKS = 3
16+
17+
18+
@activity.defn
19+
async def canary_activity() -> None:
20+
"""
21+
Here's the activity that can probe your worker and see if it's
22+
still responsive.
23+
"""
24+
t_prev = time.time()
25+
while True:
26+
await asyncio.sleep(_SECONDS_BETWEEN_CANARY_CHECKS)
27+
t_new = time.time()
28+
delay = t_new - (t_prev + _SECONDS_BETWEEN_CANARY_CHECKS)
29+
t_prev = t_new
30+
31+
# Log the extra time taken by the event loop to get back after the await
32+
# If you want, you can turn this into a histogram and show the distribution.
33+
# maybe you could even put it in your metrics.
34+
activity.logger.info(
35+
f"The canary detected {round(delay,4)} seconds of event loop delay."
36+
)
37+
print(f"The canary detected {round(delay,4)} seconds of event loop delay.")
38+
39+
40+
@workflow.defn
41+
class CanaryWorkflow:
42+
"""
43+
Here's the workflow that can probe your worker and see if it's
44+
still responsive.
45+
"""
46+
47+
@workflow.run
48+
async def run(self) -> str:
49+
50+
return await workflow.execute_activity(
51+
canary_activity,
52+
# these timeouts are going to be tricky because if the event loop
53+
# is indeed blocked, the heartbeats etc may not behave as expected.
54+
start_to_close_timeout=timedelta(seconds=60 * 100),
55+
)
56+
57+
58+
async def main():
59+
client = await Client.connect("localhost:7233")
60+
61+
async with Worker(
62+
client,
63+
task_queue="canary-task-queue",
64+
workflows=[CanaryWorkflow, YourWorkflow],
65+
activities=[canary_activity, your_activity],
66+
):
67+
68+
# add this to your code
69+
await client.execute_workflow(
70+
CanaryWorkflow.run,
71+
id="canary",
72+
task_queue="canary-task-queue",
73+
)
74+
75+
76+
if __name__ == "__main__":
77+
asyncio.run(main())

0 commit comments

Comments
 (0)