Skip to content

Commit f50993e

Browse files
authored
Merge branch 'temporalio:main' into activity-info-retry-policy
2 parents 51c23da + 9372d47 commit f50993e

29 files changed

+2002
-1435
lines changed

.github/workflows/build-binaries.yml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ on:
44
branches:
55
- main
66
- "releases/*"
7+
- fix-build-binaries
78

89
jobs:
910
# Compile the binaries and upload artifacts
@@ -65,7 +66,7 @@ jobs:
6566
if [ "$RUNNER_OS" = "Windows" ]; then
6667
bindir=Scripts
6768
fi
68-
./.venv/$bindir/pip install 'protobuf>=3.20,<6' 'types-protobuf>=3.20,<6' 'typing-extensions>=4.2.0,<5' pytest pytest_asyncio grpcio 'nexus-rpc>=1.1.0' pydantic opentelemetry-api opentelemetry-sdk python-dateutil openai-agents
69+
./.venv/$bindir/pip install 'protobuf>=3.20,<6' 'types-protobuf>=3.20,<6' 'typing-extensions>=4.2.0,<5' pytest pytest_asyncio grpcio 'nexus-rpc>=1.1.0' pydantic opentelemetry-api opentelemetry-sdk python-dateutil 'openai-agents>=0.2.3,<=0.2.9'
6970
./.venv/$bindir/pip install --no-index --find-links=../dist temporalio
7071
./.venv/$bindir/python -m pytest -s -k test_workflow_hello
7172

README.md

Lines changed: 44 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1489,21 +1489,21 @@ https://github.com/temporalio/samples-python/tree/nexus/hello_nexus).
14891489
14901490
### Plugins
14911491
1492-
Plugins provide a way to extend and customize the behavior of Temporal clients and workers through a chain of
1493-
responsibility pattern. They allow you to intercept and modify client creation, service connections, worker
1492+
Plugins provide a way to extend and customize the behavior of Temporal clients and workers through a chain of
1493+
responsibility pattern. They allow you to intercept and modify client creation, service connections, worker
14941494
configuration, and worker execution. Common customizations may include but are not limited to:
14951495
14961496
1. DataConverter
14971497
2. Activities
14981498
3. Workflows
14991499
4. Interceptors
15001500
1501-
A single plugin class can implement both client and worker plugin interfaces to share common logic between both
1501+
A single plugin class can implement both client and worker plugin interfaces to share common logic between both
15021502
contexts. When used with a client, it will automatically be propagated to any workers created with that client.
15031503
15041504
#### Client Plugins
15051505
1506-
Client plugins can intercept and modify client configuration and service connections. They are useful for adding
1506+
Client plugins can intercept and modify client configuration and service connections. They are useful for adding
15071507
authentication, modifying connection parameters, or adding custom behavior during client creation.
15081508
15091509
Here's an example of a client plugin that adds custom authentication:
@@ -1515,7 +1515,7 @@ import temporalio.service
15151515
class AuthenticationPlugin(Plugin):
15161516
def __init__(self, api_key: str):
15171517
self.api_key = api_key
1518-
1518+
15191519
def init_client_plugin(self, next: Plugin) -> None:
15201520
self.next_client_plugin = next
15211521
@@ -1540,10 +1540,10 @@ client = await Client.connect(
15401540

15411541
#### Worker Plugins
15421542

1543-
Worker plugins can modify worker configuration and intercept worker execution. They are useful for adding monitoring,
1544-
custom lifecycle management, or modifying worker settings. Worker plugins can also configure replay.
1545-
They should do this in the case that they modified the worker in a way which would also need to be present
1546-
for replay to function. For instance, changing the data converter or adding workflows.
1543+
Worker plugins can modify worker configuration and intercept worker execution. They are useful for adding monitoring,
1544+
custom lifecycle management, or modifying worker settings. Worker plugins can also configure replay.
1545+
They should do this in the case that they modified the worker in a way which would also need to be present
1546+
for replay to function. For instance, changing the data converter or adding workflows.
15471547

15481548
Here's an example of a worker plugin that adds custom monitoring:
15491549

@@ -1560,7 +1560,7 @@ class MonitoringPlugin(Plugin):
15601560

15611561
def init_worker_plugin(self, next: Plugin) -> None:
15621562
self.next_worker_plugin = next
1563-
1563+
15641564
def configure_worker(self, config: WorkerConfig) -> WorkerConfig:
15651565
# Modify worker configuration
15661566
original_task_queue = config["task_queue"]
@@ -1574,22 +1574,22 @@ class MonitoringPlugin(Plugin):
15741574
await self.next_worker_plugin.run_worker(worker)
15751575
finally:
15761576
self.logger.info("Worker execution completed")
1577-
1578-
def configure_replayer(self, config: ReplayerConfig) -> ReplayerConfig:
1579-
return self.next_worker_plugin.configure_replayer(config)
1580-
1581-
@asynccontextmanager
1582-
async def run_replayer(
1583-
self,
1584-
replayer: Replayer,
1585-
histories: AsyncIterator[temporalio.client.WorkflowHistory],
1586-
) -> AsyncIterator[AsyncIterator[WorkflowReplayResult]]:
1587-
self.logger.info("Starting replay execution")
1588-
try:
1589-
async with self.next_worker_plugin.run_replayer(replayer, histories) as results:
1590-
yield results
1591-
finally:
1592-
self.logger.info("Replay execution completed")
1577+
1578+
def configure_replayer(self, config: ReplayerConfig) -> ReplayerConfig:
1579+
return self.next_worker_plugin.configure_replayer(config)
1580+
1581+
@asynccontextmanager
1582+
async def run_replayer(
1583+
self,
1584+
replayer: Replayer,
1585+
histories: AsyncIterator[temporalio.client.WorkflowHistory],
1586+
) -> AsyncIterator[AsyncIterator[WorkflowReplayResult]]:
1587+
self.logger.info("Starting replay execution")
1588+
try:
1589+
async with self.next_worker_plugin.run_replayer(replayer, histories) as results:
1590+
yield results
1591+
finally:
1592+
self.logger.info("Replay execution completed")
15931593

15941594
# Use the plugin when creating a worker
15951595
worker = Worker(
@@ -1617,38 +1617,38 @@ class UnifiedPlugin(ClientPlugin, WorkerPlugin):
16171617

16181618
def init_worker_plugin(self, next: WorkerPlugin) -> None:
16191619
self.next_worker_plugin = next
1620-
1620+
16211621
def configure_client(self, config: ClientConfig) -> ClientConfig:
16221622
# Client-side customization
16231623
config["data_converter"] = pydantic_data_converter
16241624
return self.next_client_plugin.configure_client(config)
1625-
1625+
16261626
async def connect_service_client(
16271627
self, config: temporalio.service.ConnectConfig
16281628
) -> temporalio.service.ServiceClient:
16291629
# Add authentication to the connection
16301630
config.api_key = self.api_key
16311631
return await self.next_client_plugin.connect_service_client(config)
1632-
1632+
16331633
def configure_worker(self, config: WorkerConfig) -> WorkerConfig:
16341634
# Worker-side customization
16351635
return self.next_worker_plugin.configure_worker(config)
1636-
1636+
16371637
async def run_worker(self, worker: Worker) -> None:
16381638
print("Starting unified worker")
16391639
await self.next_worker_plugin.run_worker(worker)
1640-
1640+
16411641
def configure_replayer(self, config: ReplayerConfig) -> ReplayerConfig:
16421642
config["data_converter"] = pydantic_data_converter
16431643
return self.next_worker_plugin.configure_replayer(config)
1644-
1645-
def run_replayer(
1644+
1645+
async def run_replayer(
16461646
self,
16471647
replayer: Replayer,
16481648
histories: AsyncIterator[temporalio.client.WorkflowHistory],
16491649
) -> AbstractAsyncContextManager[AsyncIterator[WorkflowReplayResult]]:
16501650
return self.next_worker_plugin.run_replayer(replayer, histories)
1651-
1651+
16521652
# Create client with the unified plugin
16531653
client = await Client.connect(
16541654
"localhost:7233",
@@ -1902,20 +1902,18 @@ poe test -s --log-cli-level=DEBUG -k test_sync_activity_thread_cancel_caught
19021902

19031903
#### Proto Generation and Testing
19041904

1905-
To allow for backwards compatibility, protobuf code is generated on the 3.x series of the protobuf library. To generate
1906-
protobuf code, you must be on Python <= 3.10, and then run `uv add "protobuf<4"` + `uv sync --all-extras`. Then the
1907-
protobuf files can be generated via `poe gen-protos`. Tests can be run for protobuf version 3 by setting the
1908-
`TEMPORAL_TEST_PROTO3` env var to `1` prior to running tests.
1909-
1910-
Do not commit `uv.lock` or `pyproject.toml` changes. To go back from this downgrade, restore both of those files and run
1911-
`uv sync --all-extras`. Make sure you `poe format` the results.
1905+
If you have docker available, run
19121906

1913-
For a less system-intrusive approach, you can:
1914-
```shell
1915-
docker build -f scripts/_proto/Dockerfile .
1916-
docker run --rm -v "${PWD}/temporalio/api:/api_new" -v "${PWD}/temporalio/bridge/proto:/bridge_new" <just built image sha>
1917-
poe format
19181907
```
1908+
poe gen-protos-docker
1909+
```
1910+
1911+
Alternatively: to generate protobuf code, you must be on Python <= 3.10, and then run `uv add
1912+
"protobuf<4"` + `uv sync --all-extras`. Then the protobuf files can be generated via `poe
1913+
gen-protos` followed by `poe format`. Do not commit `uv.lock` or `pyproject.toml` changes. To go
1914+
back from this downgrade, restore both of those files and run `uv sync --all-extras`. Tests can be
1915+
run for protobuf version 3 by setting the `TEMPORAL_TEST_PROTO3` env var to `1` prior to running
1916+
tests.
19191917

19201918
### Style
19211919

pyproject.toml

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[project]
22
name = "temporalio"
3-
version = "1.16.0"
3+
version = "1.17.0"
44
description = "Temporal.io Python SDK"
55
authors = [{ name = "Temporal Technologies Inc", email = "[email protected]" }]
66
requires-python = ">=3.9"
@@ -26,7 +26,7 @@ opentelemetry = [
2626
]
2727
pydantic = ["pydantic>=2.0.0,<3"]
2828
openai-agents = [
29-
"openai-agents >= 0.2.3,<0.3",
29+
"openai-agents>=0.2.3,<=0.2.9", # 0.2.10 doesn't work: https://github.com/openai/openai-agents-python/issues/1639
3030
"eval-type-backport>=0.2.2; python_version < '3.10'"
3131
]
3232

@@ -57,15 +57,16 @@ dev = [
5757
"pytest-cov>=6.1.1",
5858
"httpx>=0.28.1",
5959
"pytest-pretty>=1.3.0",
60-
"openai-agents[litellm] >= 0.2.3,<0.3"
60+
"openai-agents[litellm]>=0.2.3,<=0.2.9", # 0.2.10 doesn't work: https://github.com/openai/openai-agents-python/issues/1639
6161
]
6262

6363
[tool.poe.tasks]
6464
build-develop = "uv run maturin develop --uv"
6565
build-develop-with-release = { cmd = "uv run maturin develop --release --uv" }
6666
format = [{cmd = "uv run ruff check --select I --fix"}, {cmd = "uv run ruff format"}, ]
67-
gen-docs = "uv run python scripts/gen_docs.py"
68-
gen-protos = "uv run python scripts/gen_protos.py"
67+
gen-docs = "uv run scripts/gen_docs.py"
68+
gen-protos = "uv run scripts/gen_protos.py"
69+
gen-protos-docker = "uv run scripts/gen_protos_docker.py"
6970
lint = [
7071
{cmd = "uv run ruff check --select I"},
7172
{cmd = "uv run ruff format --check"},

scripts/_proto/Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,4 @@ RUN uv add "protobuf<4"
1212
RUN uv sync --all-extras
1313
RUN poe gen-protos
1414

15-
CMD cp -r ./temporalio/api/* /api_new && cp -r ./temporalio/bridge/proto/* /bridge_new
15+
CMD ["sh", "-c", "cp -r ./temporalio/api/* /api_new && cp -r ./temporalio/bridge/proto/* /bridge_new"]

scripts/gen_protos_docker.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import os
2+
import subprocess
3+
4+
# Build the Docker image and capture its ID
5+
result = subprocess.run(
6+
["docker", "build", "-q", "-f", "scripts/_proto/Dockerfile", "."],
7+
capture_output=True,
8+
text=True,
9+
check=True,
10+
)
11+
image_id = result.stdout.strip()
12+
13+
subprocess.run(
14+
[
15+
"docker",
16+
"run",
17+
"--rm",
18+
"-v",
19+
f"{os.getcwd()}/temporalio/api:/api_new",
20+
"-v",
21+
f"{os.getcwd()}/temporalio/bridge/proto:/bridge_new",
22+
image_id,
23+
],
24+
check=True,
25+
)
26+
subprocess.run(["uv", "run", "poe", "format"], check=True)

temporalio/activity.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,7 @@ class ActivityCancellationDetails:
161161
not_found: bool = False
162162
cancel_requested: bool = False
163163
paused: bool = False
164+
reset: bool = False
164165
timed_out: bool = False
165166
worker_shutdown: bool = False
166167

@@ -174,6 +175,7 @@ def _from_proto(
174175
paused=proto.is_paused,
175176
timed_out=proto.is_timed_out,
176177
worker_shutdown=proto.is_worker_shutdown,
178+
reset=proto.is_reset,
177179
)
178180

179181

0 commit comments

Comments
 (0)