From fc74e701c3bf3de89ce5fc25bd451e6735e478a3 Mon Sep 17 00:00:00 2001 From: Alex Mazzeo Date: Tue, 25 Aug 2026 10:22:37 -0700 Subject: [PATCH 1/2] Update Temporal Python SDK to 1.32.0 --- lambda_worker/pyproject.toml | 2 +- lambda_worker/uv.lock | 20 ++-- pyproject.toml | 16 +-- uv.lock | 214 +++++++++++++++++------------------ 4 files changed, 127 insertions(+), 125 deletions(-) diff --git a/lambda_worker/pyproject.toml b/lambda_worker/pyproject.toml index 77a65440c..e25191e1b 100644 --- a/lambda_worker/pyproject.toml +++ b/lambda_worker/pyproject.toml @@ -6,7 +6,7 @@ authors = [{ name = "Temporal Technologies Inc", email = "sdk@temporal.io" }] requires-python = ">=3.10" readme = "README.md" license = "MIT" -dependencies = ["temporalio[lambda-worker-otel]>=1.26.0,<2"] +dependencies = ["temporalio[lambda-worker-otel]>=1.32.0,<2"] [dependency-groups] dev = [ diff --git a/lambda_worker/uv.lock b/lambda_worker/uv.lock index 54e548f7f..14c4f313e 100644 --- a/lambda_worker/uv.lock +++ b/lambda_worker/uv.lock @@ -402,7 +402,7 @@ name = "python-dateutil" version = "2.9.0.post0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "six" }, + { name = "six", marker = "python_full_version < '3.13'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/66/c0/0c8b6ad9f17a802ee498c46e004a0eb49bc148f2fd230864601a86dcf6db/python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3", size = 342432, upload-time = "2024-03-01T18:36:20.211Z" } wheels = [ @@ -509,7 +509,7 @@ wheels = [ [[package]] name = "temporalio" -version = "1.26.0" +version = "1.32.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "nexus-rpc" }, @@ -518,13 +518,15 @@ dependencies = [ { name = "types-protobuf" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/ae/d4/fa21150a225393f87732ed6fef3cc9735d9e751edc6be415fe6e375105c6/temporalio-1.26.0.tar.gz", hash = "sha256:f4bfb35125e6f5e8c7f7ed1277c7354d812c6fac7ed5f8dbd50536cf289aaaa7", size = 2388994, upload-time = "2026-04-15T23:43:00.911Z" } +sdist = { url = "https://files.pythonhosted.org/packages/1b/d8/18cf5bbbcc4b4c884d7723c9b54bf8d1d2556d9fbef3e99599dd3db12034/temporalio-1.32.0.tar.gz", hash = "sha256:2cfa50ec7ebdab66902b80c3a09da3258883d68540811ebfbf44f7f293a4d7d0", size = 2997642, upload-time = "2026-08-24T21:24:37.631Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/1e/27/8c421c622d18cc8e034247d5d72b89e6456937344b5bec1de40abef3c085/temporalio-1.26.0-cp310-abi3-macosx_10_12_x86_64.whl", hash = "sha256:5489040c0cf621edeb36984199dd9e4fbd2b3a07d61a4f2a8da1f2cb9820ef26", size = 14221070, upload-time = "2026-04-15T23:42:26.21Z" }, - { url = "https://files.pythonhosted.org/packages/49/7c/d2b691d16ec5db87198c2e08dbfba58e286c096faee15753613a581abdce/temporalio-1.26.0-cp310-abi3-macosx_11_0_arm64.whl", hash = "sha256:b18dd85771509c19ef059a31908bcd4e6130d1f67037c4db519702f3f2ad6d4a", size = 13583991, upload-time = "2026-04-15T23:42:34.357Z" }, - { url = "https://files.pythonhosted.org/packages/05/ca/b8728451320ca9d8bb6e1680b9bd23767118f86d5b8644edf2304d533f1b/temporalio-1.26.0-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:46187d5f82ca2ae81f35ea5916a76db0e2f067210dc6b1852c3749475721946e", size = 13808036, upload-time = "2026-04-15T23:42:42.757Z" }, - { url = "https://files.pythonhosted.org/packages/cb/54/3113f5e0ac58655790abac64656373e06191b351d74bfb94692e81bd6784/temporalio-1.26.0-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:03300c3e5237443367ac61bb20bd726c656b3daa50310bdd436599d5bdc7cf97", size = 14336604, upload-time = "2026-04-15T23:42:49.851Z" }, - { url = "https://files.pythonhosted.org/packages/fd/9b/c50840a26af3587c0c8d9af04d9976743e22496996dc1a377efc75dcd316/temporalio-1.26.0-cp310-abi3-win_amd64.whl", hash = "sha256:1c4a0d82f0a3796cbf78864c799f8dca0b94cdaec68e7b8b224c859005686ec4", size = 14525849, upload-time = "2026-04-15T23:42:57.589Z" }, + { url = "https://files.pythonhosted.org/packages/37/0b/adad9dcd8b96c760cd04dcc75f0a0f136aabdb78c4b180219589749469a4/temporalio-1.32.0-cp310-abi3-macosx_10_12_x86_64.whl", hash = "sha256:47c128732e5d49235c9daeeb084d55093cee5ebc200ccc3afaeb4468f08d809e", size = 13796063, upload-time = "2026-08-24T21:24:16.638Z" }, + { url = "https://files.pythonhosted.org/packages/d0/84/6cc96518a2aff3ce9fb132479811bb29db563fbcdc947c279df8f089721a/temporalio-1.32.0-cp310-abi3-macosx_11_0_arm64.whl", hash = "sha256:e78a209dc5ef3303bc6a3033fe11ffd813b778e4b176ec18d20386d65952daa9", size = 13467827, upload-time = "2026-08-24T21:24:19.731Z" }, + { url = "https://files.pythonhosted.org/packages/92/d0/720e5e9bb51ae1af6b9fea4d5c56d6ac6e94fbf4c8b86a6b0b318b6aef1e/temporalio-1.32.0-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a86be3a6d237ea6cc2d632015a5df4cead2aa3143b9601721428b53b87df81e2", size = 13854003, upload-time = "2026-08-24T21:24:22.743Z" }, + { url = "https://files.pythonhosted.org/packages/e9/6b/8c8973ad314efc8c124e9a0f602ae96533c7e624b3cde7fcc9704aa46dd2/temporalio-1.32.0-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4dd44a60ba54901560011a32f085353c0f5e7dac6b8d7a7e0c7c4ba508c6bf5d", size = 14193177, upload-time = "2026-08-24T21:24:25.849Z" }, + { url = "https://files.pythonhosted.org/packages/5b/ad/7496f8424a6ccc9b6ce6c629f9375744e8a439e9a692bd27b4f77b99977a/temporalio-1.32.0-cp310-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:6a7100b1f1bf781f8f1800f89bb787b3dd7ce883e78603442d0c7a40e1143a86", size = 13920043, upload-time = "2026-08-24T21:24:28.667Z" }, + { url = "https://files.pythonhosted.org/packages/5b/16/73fa24d69e70035323217e87d33cb3df6415e1906db07b2112c9a6b09e33/temporalio-1.32.0-cp310-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:311abb9f0650f4ad9f24944ef16d8ed47954ddc3075c1e8c73dcd968d70ccdce", size = 14309243, upload-time = "2026-08-24T21:24:31.727Z" }, + { url = "https://files.pythonhosted.org/packages/07/72/4a49f38f294f9cc1ba15c0b5272adfa7d2a0da38e924ed7f0b1ea2e5bbc9/temporalio-1.32.0-cp310-abi3-win_amd64.whl", hash = "sha256:158386bcd9a6dce1ab63d732fc967c5a5830e15c3012ffaa4b8772bdac099e0f", size = 15196754, upload-time = "2026-08-24T21:24:34.931Z" }, ] [package.optional-dependencies] @@ -552,7 +554,7 @@ dev = [ ] [package.metadata] -requires-dist = [{ name = "temporalio", extras = ["lambda-worker-otel"], specifier = ">=1.26.0,<2" }] +requires-dist = [{ name = "temporalio", extras = ["lambda-worker-otel"], specifier = ">=1.32.0,<2" }] [package.metadata.requires-dev] dev = [ diff --git a/pyproject.toml b/pyproject.toml index fd6481154..63bbed3d8 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -33,7 +33,7 @@ deepagents = [ "langchain>=1.3.11,<2 ; python_version >= '3.11'", "langchain-core>=1.4.8,<2 ; python_version >= '3.11'", "langchain-anthropic>=1.4.7,<2 ; python_version >= '3.11'", - "temporalio[langsmith]>=1.31.0 ; python_version >= '3.11'", + "temporalio[langsmith]>=1.32.0 ; python_version >= '3.11'", ] dsl = ["pyyaml>=6.0.1,<7", "types-pyyaml>=6.0.12,<7", "dacite>=1.8.1,<2"] encryption = ["cryptography>=38.0.1,<39", "aiohttp>=3.13.3,<4"] @@ -45,14 +45,14 @@ external-storage = [ ] external-storage-redis = ["redis>=5.0.0,<8"] gevent = ["gevent>=25.4.2 ; python_version >= '3.8'"] -google-adk = ["temporalio[google-adk] >= 1.31.0", "google-adk>=2.2.0,<3"] +google-adk = ["temporalio[google-adk] >= 1.32.0", "google-adk>=2.2.0,<3"] google-genai = [ "mcp>=1.0.0", - "temporalio[google-genai,pydantic]>=1.31.0", + "temporalio[google-genai,pydantic]>=1.32.0", ] langfuse-tracing = [ "openai>=1.4.0", - "temporalio[opentelemetry]>=1.30.0,<2", + "temporalio[opentelemetry]>=1.32.0,<2", # Langfuse's OTLP endpoint is HTTP-only (no gRPC), so use the http exporter. "opentelemetry-exporter-otlp-proto-http>=1.30.0,<2", "openinference-instrumentation-openai>=0.1.52", @@ -61,13 +61,13 @@ langfuse-tracing = [ langsmith-tracing = [ "openai>=1.4.0", "langsmith>=0.7.0", - "temporalio[pydantic,langsmith]>=1.31.0", + "temporalio[pydantic,langsmith]>=1.32.0", ] langgraph = [ "langgraph>=1.1.3", "langchain>=0.3.0", "langchain-anthropic>=0.3.0", - "temporalio[langgraph,langsmith]>=1.31.0", + "temporalio[langgraph,langsmith]>=1.32.0", ] litellm = ["litellm>=1.85.0,<2"] nexus = ["nexus-rpc>=1.1.0,<2"] @@ -77,7 +77,7 @@ open-telemetry = [ ] openai-agents = [ "openai-agents[litellm] >= 0.14.1", - "temporalio[openai-agents,opentelemetry] >= 1.31.0", + "temporalio[openai-agents,opentelemetry] >= 1.32.0", "requests>=2.32.0,<3", ] pydantic-converter = ["pydantic>=2.10.6,<3"] @@ -87,7 +87,7 @@ strands-agents = [ "strands-agents-tools>=0.5.2", "mcp>=1.0.0", "boto3>=1.34.92,<2", - "temporalio[strands-agents,pydantic]>=1.31.0", + "temporalio[strands-agents,pydantic]>=1.32.0", ] trio-async = ["trio>=0.28.0,<0.29", "trio-asyncio>=0.15.0,<0.16"] cloud-export-to-parquet = [ diff --git a/uv.lock b/uv.lock index 5d9b1dae0..537beabdd 100644 --- a/uv.lock +++ b/uv.lock @@ -244,14 +244,14 @@ resolution-markers = [ "python_full_version < '3.11'", ] dependencies = [ - { name = "anyio" }, - { name = "distro" }, - { name = "docstring-parser" }, - { name = "httpx" }, - { name = "jiter" }, - { name = "pydantic" }, - { name = "sniffio" }, - { name = "typing-extensions" }, + { name = "anyio", marker = "python_full_version < '3.11'" }, + { name = "distro", marker = "python_full_version < '3.11'" }, + { name = "docstring-parser", marker = "python_full_version < '3.11'" }, + { name = "httpx", marker = "python_full_version < '3.11'" }, + { name = "jiter", marker = "python_full_version < '3.11'" }, + { name = "pydantic", marker = "python_full_version < '3.11'" }, + { name = "sniffio", marker = "python_full_version < '3.11'" }, + { name = "typing-extensions", marker = "python_full_version < '3.11'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/fb/57/0b758b08cf4606c94d63a997d67a0063f7438efbaf81cfedd0d7c0c69d67/anthropic-0.103.1.tar.gz", hash = "sha256:21c12f4fc0fdd87a2e80d58479cd0af640062b3cfb82bbfa01c7977acd4defeb", size = 848877, upload-time = "2026-05-19T15:43:27.698Z" } wheels = [ @@ -270,14 +270,14 @@ resolution-markers = [ "python_full_version == '3.11.*'", ] dependencies = [ - { name = "anyio" }, - { name = "distro" }, - { name = "docstring-parser" }, - { name = "httpx" }, - { name = "jiter" }, - { name = "pydantic" }, - { name = "sniffio" }, - { name = "typing-extensions" }, + { name = "anyio", marker = "python_full_version >= '3.11'" }, + { name = "distro", marker = "python_full_version >= '3.11'" }, + { name = "docstring-parser", marker = "python_full_version >= '3.11'" }, + { name = "httpx", marker = "python_full_version >= '3.11'" }, + { name = "jiter", marker = "python_full_version >= '3.11'" }, + { name = "pydantic", marker = "python_full_version >= '3.11'" }, + { name = "sniffio", marker = "python_full_version >= '3.11'" }, + { name = "typing-extensions", marker = "python_full_version >= '3.11'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/0f/ca/3cb2c20ee729736fbd4546d5d8b67e818288529fe70cb7a80dbf80aef70b/anthropic-0.121.0.tar.gz", hash = "sha256:e79d6e08ab3376602fc9a70d4d5ea3540817c76cf7e16658bed790834e1833d6", size = 1013292, upload-time = "2026-08-07T17:11:07.241Z" } wheels = [ @@ -709,12 +709,12 @@ name = "deepagents" version = "0.6.12" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "langchain", version = "1.3.15", source = { registry = "https://pypi.org/simple" } }, - { name = "langchain-anthropic", version = "1.5.5", source = { registry = "https://pypi.org/simple" } }, - { name = "langchain-core", version = "1.5.4", source = { registry = "https://pypi.org/simple" } }, - { name = "langchain-google-genai" }, - { name = "langsmith", version = "0.8.18", source = { registry = "https://pypi.org/simple" } }, - { name = "wcmatch" }, + { name = "langchain", version = "1.3.15", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, + { name = "langchain-anthropic", version = "1.5.5", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, + { name = "langchain-core", version = "1.5.4", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, + { name = "langchain-google-genai", marker = "python_full_version >= '3.11'" }, + { name = "langsmith", version = "0.8.18", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, + { name = "wcmatch", marker = "python_full_version >= '3.11'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/e0/db/a6acdc72a9e90c3f07ed10de35c951734a02d4facb693bb59684ad368801/deepagents-0.6.12.tar.gz", hash = "sha256:1f281c0bc5a63132f62e2ee345c1dc593b23188da6e23016401f6879fbe54b5f", size = 211364, upload-time = "2026-06-25T17:26:52.775Z" } wheels = [ @@ -767,7 +767,7 @@ name = "exceptiongroup" version = "1.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "typing-extensions" }, + { name = "typing-extensions", marker = "python_full_version < '3.11'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/50/79/66800aadf48771f6b62f7eb014e352e5d06856655206165d775e675a02c9/exceptiongroup-1.3.1.tar.gz", hash = "sha256:8b412432c6055b0b7d14c310000ae93352ed6754f70fa8f7c34141f91c4e3219", size = 30371, upload-time = "2025-11-21T23:01:54.787Z" } wheels = [ @@ -1689,9 +1689,9 @@ resolution-markers = [ "python_full_version < '3.11'", ] dependencies = [ - { name = "langchain-core", version = "1.4.0", source = { registry = "https://pypi.org/simple" } }, - { name = "langgraph", version = "1.2.0", source = { registry = "https://pypi.org/simple" } }, - { name = "pydantic" }, + { name = "langchain-core", version = "1.4.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, + { name = "langgraph", version = "1.2.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, + { name = "pydantic", marker = "python_full_version < '3.11'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/11/e5/6350e77a9e2764eaafcb2d581cbf0b800f53c6bc98fdf5ebc85f3a931ded/langchain-1.3.1.tar.gz", hash = "sha256:bc283c220233230f48b8e50ab1fbf1b688bcb206d933fa448d40a9b143177f62", size = 581329, upload-time = "2026-05-15T18:14:55.368Z" } wheels = [ @@ -1710,9 +1710,9 @@ resolution-markers = [ "python_full_version == '3.11.*'", ] dependencies = [ - { name = "langchain-core", version = "1.5.4", source = { registry = "https://pypi.org/simple" } }, - { name = "langgraph", version = "1.2.11", source = { registry = "https://pypi.org/simple" } }, - { name = "pydantic" }, + { name = "langchain-core", version = "1.5.4", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, + { name = "langgraph", version = "1.2.11", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, + { name = "pydantic", marker = "python_full_version >= '3.11'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/6a/1c/b84579174a8e82ed79f4c3e0cd5a7f2323facc5ccd4d1b8390e7d175b663/langchain-1.3.15.tar.gz", hash = "sha256:ab4b775b9703f7e37babe0b325dbbaef25573bda60ecf79f7850bc875f252795", size = 665047, upload-time = "2026-08-11T19:10:52.455Z" } wheels = [ @@ -1727,9 +1727,9 @@ resolution-markers = [ "python_full_version < '3.11'", ] dependencies = [ - { name = "anthropic", version = "0.103.1", source = { registry = "https://pypi.org/simple" } }, - { name = "langchain-core", version = "1.4.0", source = { registry = "https://pypi.org/simple" } }, - { name = "pydantic" }, + { name = "anthropic", version = "0.103.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, + { name = "langchain-core", version = "1.4.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, + { name = "pydantic", marker = "python_full_version < '3.11'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/fa/e3/d2f9dec95602524b1cfb4be2747ba5bc38d32501b2a56cb4bcb76e80bb45/langchain_anthropic-1.4.3.tar.gz", hash = "sha256:f8a2442463c0629b1b3110eaeaa56fdbdc87df2a802f8c7f5ecf611eb4874ec8", size = 685219, upload-time = "2026-05-03T17:33:27.118Z" } wheels = [ @@ -1748,9 +1748,9 @@ resolution-markers = [ "python_full_version == '3.11.*'", ] dependencies = [ - { name = "anthropic", version = "0.121.0", source = { registry = "https://pypi.org/simple" } }, - { name = "langchain-core", version = "1.5.4", source = { registry = "https://pypi.org/simple" } }, - { name = "pydantic" }, + { name = "anthropic", version = "0.121.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, + { name = "langchain-core", version = "1.5.4", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, + { name = "pydantic", marker = "python_full_version >= '3.11'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/38/ce/5fdff0c55c4711da9d87a4a0a066d0b14b633402dc9d441214cc64889be9/langchain_anthropic-1.5.5.tar.gz", hash = "sha256:e8697f13b93fe95b7c7c17679f5d0143c239a8fcf45c0f498349c54482322dc9", size = 720572, upload-time = "2026-08-11T19:16:38.842Z" } wheels = [ @@ -1765,15 +1765,15 @@ resolution-markers = [ "python_full_version < '3.11'", ] dependencies = [ - { name = "jsonpatch" }, - { name = "langchain-protocol", version = "0.0.15", source = { registry = "https://pypi.org/simple" } }, - { name = "langsmith", version = "0.8.9", source = { registry = "https://pypi.org/simple" } }, - { name = "packaging" }, - { name = "pydantic" }, - { name = "pyyaml" }, - { name = "tenacity" }, - { name = "typing-extensions" }, - { name = "uuid-utils" }, + { name = "jsonpatch", marker = "python_full_version < '3.11'" }, + { name = "langchain-protocol", version = "0.0.15", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, + { name = "langsmith", version = "0.8.9", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, + { name = "packaging", marker = "python_full_version < '3.11'" }, + { name = "pydantic", marker = "python_full_version < '3.11'" }, + { name = "pyyaml", marker = "python_full_version < '3.11'" }, + { name = "tenacity", marker = "python_full_version < '3.11'" }, + { name = "typing-extensions", marker = "python_full_version < '3.11'" }, + { name = "uuid-utils", marker = "python_full_version < '3.11'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/59/de/679a53472c25860837e32c0442c962fa86e95317a36460e2c9d5c91b17c2/langchain_core-1.4.0.tar.gz", hash = "sha256:1dc341eed802ed9c117c0df3923c991e5e9e226571e5725c194eeb5bd93d1a7f", size = 920260, upload-time = "2026-05-11T18:42:35.919Z" } wheels = [ @@ -1792,15 +1792,15 @@ resolution-markers = [ "python_full_version == '3.11.*'", ] dependencies = [ - { name = "jsonpatch" }, - { name = "langchain-protocol", version = "0.0.18", source = { registry = "https://pypi.org/simple" } }, - { name = "langsmith", version = "0.8.18", source = { registry = "https://pypi.org/simple" } }, - { name = "packaging" }, - { name = "pydantic" }, - { name = "pyyaml" }, - { name = "tenacity" }, - { name = "typing-extensions" }, - { name = "uuid-utils" }, + { name = "jsonpatch", marker = "python_full_version >= '3.11'" }, + { name = "langchain-protocol", version = "0.0.18", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, + { name = "langsmith", version = "0.8.18", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, + { name = "packaging", marker = "python_full_version >= '3.11'" }, + { name = "pydantic", marker = "python_full_version >= '3.11'" }, + { name = "pyyaml", marker = "python_full_version >= '3.11'" }, + { name = "tenacity", marker = "python_full_version >= '3.11'" }, + { name = "typing-extensions", marker = "python_full_version >= '3.11'" }, + { name = "uuid-utils", marker = "python_full_version >= '3.11'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/9e/18/20c3eec05ccf2fff8e553866bec3bb2f92880aea3cb878603e5a854bd5c0/langchain_core-1.5.4.tar.gz", hash = "sha256:aa76104f30b6c7305f292cb2c364e67cb52c321940ae812d7969471dce32a89a", size = 980540, upload-time = "2026-08-11T18:02:52.239Z" } wheels = [ @@ -1812,10 +1812,10 @@ name = "langchain-google-genai" version = "4.3.3" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "filetype" }, - { name = "google-genai" }, - { name = "langchain-core", version = "1.5.4", source = { registry = "https://pypi.org/simple" } }, - { name = "pydantic" }, + { name = "filetype", marker = "python_full_version >= '3.11'" }, + { name = "google-genai", marker = "python_full_version >= '3.11'" }, + { name = "langchain-core", version = "1.5.4", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, + { name = "pydantic", marker = "python_full_version >= '3.11'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/11/98/39b62fb50236fc582449beb96e0392d108bd7baac7ac6158d656bfac1561/langchain_google_genai-4.3.3.tar.gz", hash = "sha256:f051b98aaf223cf9092fc27c280dfec63070fc0022dc513640b2da138c9fa2f0", size = 286010, upload-time = "2026-08-10T18:34:26.499Z" } wheels = [ @@ -1830,7 +1830,7 @@ resolution-markers = [ "python_full_version < '3.11'", ] dependencies = [ - { name = "typing-extensions" }, + { name = "typing-extensions", marker = "python_full_version < '3.11'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/4f/24/9777489d6fbbee64af0c8f96d4f840239c408cf694f3394672807dafc490/langchain_protocol-0.0.15.tar.gz", hash = "sha256:9ab2d11ee73944754f10e037e717098d3a6796f0e58afa9cadda6154e7655ade", size = 5862, upload-time = "2026-05-01T22:30:04.748Z" } wheels = [ @@ -1849,7 +1849,7 @@ resolution-markers = [ "python_full_version == '3.11.*'", ] dependencies = [ - { name = "typing-extensions" }, + { name = "typing-extensions", marker = "python_full_version >= '3.11'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/d2/59/b5959aea96faa9146e2e49a7a22882b3528c62efafe9a6a95beab30c2305/langchain_protocol-0.0.18.tar.gz", hash = "sha256:ec3e11782f1ed0c9db38e5a9ed01b0e7a0d3fba406faa8aef6594b73c56a63e6", size = 6150, upload-time = "2026-06-18T17:08:26.959Z" } wheels = [ @@ -1864,12 +1864,12 @@ resolution-markers = [ "python_full_version < '3.11'", ] dependencies = [ - { name = "langchain-core", version = "1.4.0", source = { registry = "https://pypi.org/simple" } }, - { name = "langgraph-checkpoint" }, - { name = "langgraph-prebuilt" }, - { name = "langgraph-sdk", version = "0.3.14", source = { registry = "https://pypi.org/simple" } }, - { name = "pydantic" }, - { name = "xxhash" }, + { name = "langchain-core", version = "1.4.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, + { name = "langgraph-checkpoint", marker = "python_full_version < '3.11'" }, + { name = "langgraph-prebuilt", marker = "python_full_version < '3.11'" }, + { name = "langgraph-sdk", version = "0.3.14", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, + { name = "pydantic", marker = "python_full_version < '3.11'" }, + { name = "xxhash", marker = "python_full_version < '3.11'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/58/61/d5d25e783035aa307d289b37e082258a6061c0fb4caa4a284f3bf1e87169/langgraph-1.2.0.tar.gz", hash = "sha256:4a9baaf62afc5d5f63144a50095140a34b9aa9b7cea695d25326d564775348e7", size = 690248, upload-time = "2026-05-12T03:46:39.164Z" } wheels = [ @@ -1888,12 +1888,12 @@ resolution-markers = [ "python_full_version == '3.11.*'", ] dependencies = [ - { name = "langchain-core", version = "1.5.4", source = { registry = "https://pypi.org/simple" } }, - { name = "langgraph-checkpoint" }, - { name = "langgraph-prebuilt" }, - { name = "langgraph-sdk", version = "0.4.2", source = { registry = "https://pypi.org/simple" } }, - { name = "pydantic" }, - { name = "xxhash" }, + { name = "langchain-core", version = "1.5.4", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, + { name = "langgraph-checkpoint", marker = "python_full_version >= '3.11'" }, + { name = "langgraph-prebuilt", marker = "python_full_version >= '3.11'" }, + { name = "langgraph-sdk", version = "0.4.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, + { name = "pydantic", marker = "python_full_version >= '3.11'" }, + { name = "xxhash", marker = "python_full_version >= '3.11'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/56/0d/c8e7ee98896659e1b6555db0ab115a9ca899844744645d5d894032bab1d7/langgraph-1.2.11.tar.gz", hash = "sha256:9ecfe11e50d338b34b15cf4d8a442642de103e8ae6971320efba84e4542eb363", size = 725753, upload-time = "2026-08-11T14:00:36.945Z" } wheels = [ @@ -1936,8 +1936,8 @@ resolution-markers = [ "python_full_version < '3.11'", ] dependencies = [ - { name = "httpx" }, - { name = "orjson" }, + { name = "httpx", marker = "python_full_version < '3.11'" }, + { name = "orjson", marker = "python_full_version < '3.11'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/02/f1/134046c20bc4a4a15d410d1d21c9e298a3e9923777b4cc867b8669bc636b/langgraph_sdk-0.3.14.tar.gz", hash = "sha256:acd1674c538e97f3cdaa610f6dd7e34bc9bad30167f0ccc482dcd563325e81f5", size = 198162, upload-time = "2026-05-05T18:40:03.524Z" } wheels = [ @@ -1956,11 +1956,11 @@ resolution-markers = [ "python_full_version == '3.11.*'", ] dependencies = [ - { name = "httpx" }, - { name = "langchain-core", version = "1.5.4", source = { registry = "https://pypi.org/simple" } }, - { name = "langchain-protocol", version = "0.0.18", source = { registry = "https://pypi.org/simple" } }, - { name = "orjson" }, - { name = "websockets" }, + { name = "httpx", marker = "python_full_version >= '3.11'" }, + { name = "langchain-core", version = "1.5.4", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, + { name = "langchain-protocol", version = "0.0.18", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, + { name = "orjson", marker = "python_full_version >= '3.11'" }, + { name = "websockets", marker = "python_full_version >= '3.11'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/b4/2b/bd8ac26d4e97f6df88ef05ce5b6a38945a3903e1025d926f4752aa88aa97/langgraph_sdk-0.4.2.tar.gz", hash = "sha256:b88f0f5f6328ac0680d6790614a905b2bcfa257f2276dba4e38f0e86db0aa738", size = 348327, upload-time = "2026-06-01T17:51:19.856Z" } wheels = [ @@ -1975,16 +1975,16 @@ resolution-markers = [ "python_full_version < '3.11'", ] dependencies = [ - { name = "httpx" }, - { name = "orjson", marker = "platform_python_implementation != 'PyPy'" }, - { name = "packaging" }, - { name = "pydantic" }, - { name = "requests" }, - { name = "requests-toolbelt" }, - { name = "uuid-utils" }, - { name = "websockets" }, - { name = "xxhash" }, - { name = "zstandard" }, + { name = "httpx", marker = "python_full_version < '3.11'" }, + { name = "orjson", marker = "python_full_version < '3.11' and platform_python_implementation != 'PyPy'" }, + { name = "packaging", marker = "python_full_version < '3.11'" }, + { name = "pydantic", marker = "python_full_version < '3.11'" }, + { name = "requests", marker = "python_full_version < '3.11'" }, + { name = "requests-toolbelt", marker = "python_full_version < '3.11'" }, + { name = "uuid-utils", marker = "python_full_version < '3.11'" }, + { name = "websockets", marker = "python_full_version < '3.11'" }, + { name = "xxhash", marker = "python_full_version < '3.11'" }, + { name = "zstandard", marker = "python_full_version < '3.11'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/e4/dd/f4c8a12987318e505b10760d30c3c2d45e8dc87ba8f47a004c753a9e7b35/langsmith-0.8.9.tar.gz", hash = "sha256:f16e37fcd5a8a2d4db30eae0e399a866a65ce5cc86218825c59409ed57a3bf53", size = 4428684, upload-time = "2026-06-03T17:56:09.448Z" } wheels = [ @@ -2003,16 +2003,16 @@ resolution-markers = [ "python_full_version == '3.11.*'", ] dependencies = [ - { name = "httpx" }, - { name = "orjson", marker = "platform_python_implementation != 'PyPy'" }, - { name = "packaging" }, - { name = "pydantic" }, - { name = "requests" }, - { name = "requests-toolbelt" }, - { name = "uuid-utils" }, - { name = "websockets" }, - { name = "xxhash" }, - { name = "zstandard" }, + { name = "httpx", marker = "python_full_version >= '3.11'" }, + { name = "orjson", marker = "python_full_version >= '3.11' and platform_python_implementation != 'PyPy'" }, + { name = "packaging", marker = "python_full_version >= '3.11'" }, + { name = "pydantic", marker = "python_full_version >= '3.11'" }, + { name = "requests", marker = "python_full_version >= '3.11'" }, + { name = "requests-toolbelt", marker = "python_full_version >= '3.11'" }, + { name = "uuid-utils", marker = "python_full_version >= '3.11'" }, + { name = "websockets", marker = "python_full_version >= '3.11'" }, + { name = "xxhash", marker = "python_full_version >= '3.11'" }, + { name = "zstandard", marker = "python_full_version >= '3.11'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/9a/d9/a6681aa9847bbbc5ec21abe20a5e233b94e5edcfe39624db607ac7e8ccb4/langsmith-0.8.18.tar.gz", hash = "sha256:32dde9c0e67e053e0fb738921fc8ced768af7b8fa83d7a0e3fd63597cf8776dd", size = 4526988, upload-time = "2026-06-19T13:12:17.123Z" } wheels = [ @@ -4656,7 +4656,7 @@ deepagents = [ { name = "langchain", marker = "python_full_version >= '3.11'", specifier = ">=1.3.11,<2" }, { name = "langchain-anthropic", marker = "python_full_version >= '3.11'", specifier = ">=1.4.7,<2" }, { name = "langchain-core", marker = "python_full_version >= '3.11'", specifier = ">=1.4.8,<2" }, - { name = "temporalio", extras = ["langsmith"], marker = "python_full_version >= '3.11'", specifier = ">=1.31.0" }, + { name = "temporalio", extras = ["langsmith"], marker = "python_full_version >= '3.11'", specifier = ">=1.32.0" }, ] dev = [ { name = "fakeredis", specifier = ">=2,<3" }, @@ -4689,29 +4689,29 @@ external-storage-redis = [{ name = "redis", specifier = ">=5.0.0,<8" }] gevent = [{ name = "gevent", marker = "python_full_version >= '3.8'", specifier = ">=25.4.2" }] google-adk = [ { name = "google-adk", specifier = ">=2.2.0,<3" }, - { name = "temporalio", extras = ["google-adk"], specifier = ">=1.31.0" }, + { name = "temporalio", extras = ["google-adk"], specifier = ">=1.32.0" }, ] google-genai = [ { name = "mcp", specifier = ">=1.0.0" }, - { name = "temporalio", extras = ["google-genai", "pydantic"], specifier = ">=1.31.0" }, + { name = "temporalio", extras = ["google-genai", "pydantic"], specifier = ">=1.32.0" }, ] langfuse-tracing = [ { name = "openai", specifier = ">=1.4.0" }, { name = "openinference-instrumentation-openai", specifier = ">=0.1.52" }, { name = "opentelemetry-exporter-otlp-proto-http", specifier = ">=1.30.0,<2" }, { name = "opentelemetry-instrumentation-openai-v2", specifier = ">=2.1b0" }, - { name = "temporalio", extras = ["opentelemetry"], specifier = ">=1.30.0,<2" }, + { name = "temporalio", extras = ["opentelemetry"], specifier = ">=1.32.0,<2" }, ] langgraph = [ { name = "langchain", specifier = ">=0.3.0" }, { name = "langchain-anthropic", specifier = ">=0.3.0" }, { name = "langgraph", specifier = ">=1.1.3" }, - { name = "temporalio", extras = ["langgraph", "langsmith"], specifier = ">=1.31.0" }, + { name = "temporalio", extras = ["langgraph", "langsmith"], specifier = ">=1.32.0" }, ] langsmith-tracing = [ { name = "langsmith", specifier = ">=0.7.0" }, { name = "openai", specifier = ">=1.4.0" }, - { name = "temporalio", extras = ["pydantic", "langsmith"], specifier = ">=1.31.0" }, + { name = "temporalio", extras = ["pydantic", "langsmith"], specifier = ">=1.32.0" }, ] litellm = [{ name = "litellm", specifier = ">=1.85.0,<2" }] nexus = [{ name = "nexus-rpc", specifier = ">=1.1.0,<2" }] @@ -4722,7 +4722,7 @@ open-telemetry = [ openai-agents = [ { name = "openai-agents", extras = ["litellm"], specifier = ">=0.14.1" }, { name = "requests", specifier = ">=2.32.0,<3" }, - { name = "temporalio", extras = ["openai-agents", "opentelemetry"], specifier = ">=1.31.0" }, + { name = "temporalio", extras = ["openai-agents", "opentelemetry"], specifier = ">=1.32.0" }, ] pydantic-converter = [{ name = "pydantic", specifier = ">=2.10.6,<3" }] sentry = [{ name = "sentry-sdk", specifier = ">=2.13.0" }] @@ -4731,7 +4731,7 @@ strands-agents = [ { name = "mcp", specifier = ">=1.0.0" }, { name = "strands-agents", specifier = ">=1.39.0" }, { name = "strands-agents-tools", specifier = ">=0.5.2" }, - { name = "temporalio", extras = ["strands-agents", "pydantic"], specifier = ">=1.31.0" }, + { name = "temporalio", extras = ["strands-agents", "pydantic"], specifier = ">=1.32.0" }, ] trio-async = [ { name = "trio", specifier = ">=0.28.0,<0.29" }, @@ -5195,7 +5195,7 @@ name = "wcmatch" version = "11.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "bracex" }, + { name = "bracex", marker = "python_full_version >= '3.11'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/16/25/1da725838132221e33568973da484ff43813662ccc06ebf7f6e3abddfcd5/wcmatch-11.0.tar.gz", hash = "sha256:55d95c2447789712774b198ceec72939e88b5618f1f8f0a9b605bf7740b63b96", size = 141360, upload-time = "2026-07-10T05:50:24.183Z" } wheels = [ From ca8f826475a8bcfdcbdc4f51cc75be252ccd436b Mon Sep 17 00:00:00 2001 From: Alex Mazzeo Date: Wed, 12 Aug 2026 10:36:46 -0700 Subject: [PATCH 2/2] Add Nexus SAA sample --- README.md | 1 + nexus_standalone_activity/README.md | 59 +++++++++++++++++++ nexus_standalone_activity/__init__.py | 1 + nexus_standalone_activity/activity.py | 10 ++++ nexus_standalone_activity/handler.py | 36 +++++++++++ nexus_standalone_activity/service.py | 20 +++++++ nexus_standalone_activity/starter.py | 34 +++++++++++ nexus_standalone_activity/worker.py | 41 +++++++++++++ tests/conftest.py | 4 ++ tests/nexus_standalone_activity/__init__.py | 1 + .../nexus_standalone_activity_test.py | 57 ++++++++++++++++++ 11 files changed, 264 insertions(+) create mode 100644 nexus_standalone_activity/README.md create mode 100644 nexus_standalone_activity/__init__.py create mode 100644 nexus_standalone_activity/activity.py create mode 100644 nexus_standalone_activity/handler.py create mode 100644 nexus_standalone_activity/service.py create mode 100644 nexus_standalone_activity/starter.py create mode 100644 nexus_standalone_activity/worker.py create mode 100644 tests/nexus_standalone_activity/__init__.py create mode 100644 tests/nexus_standalone_activity/nexus_standalone_activity_test.py diff --git a/README.md b/README.md index 164263995..2954d242e 100644 --- a/README.md +++ b/README.md @@ -93,6 +93,7 @@ Some examples require extra dependencies. See each sample's directory for specif This contains two samples, one sending messages to an existing workflow and a second that creates a workflow through Nexus and sends messages to it. * [nexus_multiple_args](nexus_multiple_args) - Map a Nexus operation to a handler workflow that takes multiple arguments. +* [nexus_standalone_activity](nexus_standalone_activity) - Back a Nexus operation with a standalone Activity. * [nexus_standalone_operations](nexus_standalone_operations) - Execute Nexus operations directly from client code, without wrapping them in a workflow. * [open_telemetry](open_telemetry) - Trace workflows with OpenTelemetry. diff --git a/nexus_standalone_activity/README.md b/nexus_standalone_activity/README.md new file mode 100644 index 000000000..1f7954241 --- /dev/null +++ b/nexus_standalone_activity/README.md @@ -0,0 +1,59 @@ +# Nexus operation backed by a standalone Activity + +This sample shows how to implement a `TemporalOperationHandler` that starts a +standalone Activity as the backing execution for a Nexus operation. When the Activity +finishes, Temporal delivers its result to the Nexus caller. The default handler +cancellation implementation also forwards Nexus cancellation to the Activity. + +The APIs used by this sample are experimental and may change incompatibly. + +### Sample structure + +- [service.py](./service.py) defines the Nexus service shared by caller and handler. +- [activity.py](./activity.py) defines the standalone Activity. +- [handler.py](./handler.py) implements `TemporalOperationHandler.start_operation`. +- [worker.py](./worker.py) hosts the Nexus handler and Activity. +- [starter.py](./starter.py) executes the Nexus operation from client code. + +## Run locally + +This sample requires the [Temporal dev server build that supports standalone Nexus operations](https://docs.temporal.io/standalone-nexus-operation#temporal-cli-support) and Activity +callbacks enabled. + +1. Start the server with caller and handler namespaces: + + ```bash + ./temporal server start-dev \ + --dynamic-config-value activity.enableCallbacks=true \ + --namespace nexus-standalone-activity-caller \ + --namespace nexus-standalone-activity-handler + ``` + +2. Create an endpoint targeting the handler namespace and task queue: + + ```bash + ./temporal operator nexus endpoint create \ + --name nexus-standalone-activity-endpoint \ + --target-namespace nexus-standalone-activity-handler \ + --target-task-queue nexus-standalone-activity-handler + ``` + +3. Start the handler Worker: + + ```bash + TEMPORAL_NAMESPACE=nexus-standalone-activity-handler \ + uv run nexus_standalone_activity/worker.py + ``` + +4. Execute the operation from the caller namespace: + + ```bash + TEMPORAL_NAMESPACE=nexus-standalone-activity-caller \ + uv run nexus_standalone_activity/starter.py + ``` + +Expected output: + +```text +Hello, World! +``` diff --git a/nexus_standalone_activity/__init__.py b/nexus_standalone_activity/__init__.py new file mode 100644 index 000000000..6dca48d18 --- /dev/null +++ b/nexus_standalone_activity/__init__.py @@ -0,0 +1 @@ +"""Nexus operation backed by a standalone Activity sample.""" diff --git a/nexus_standalone_activity/activity.py b/nexus_standalone_activity/activity.py new file mode 100644 index 000000000..a2ed8a502 --- /dev/null +++ b/nexus_standalone_activity/activity.py @@ -0,0 +1,10 @@ +"""Activity used as the backing execution for the Nexus operation.""" + +from temporalio import activity + +from nexus_standalone_activity.service import GreetingInput, GreetingOutput + + +@activity.defn +async def create_greeting(input: GreetingInput) -> GreetingOutput: + return GreetingOutput(message=f"Hello, {input.name}!") diff --git a/nexus_standalone_activity/handler.py b/nexus_standalone_activity/handler.py new file mode 100644 index 000000000..960d75d05 --- /dev/null +++ b/nexus_standalone_activity/handler.py @@ -0,0 +1,36 @@ +"""Temporal operation handler that starts a standalone Activity.""" + +from datetime import timedelta + +import nexusrpc.handler +from temporalio import nexus + +from nexus_standalone_activity.activity import create_greeting +from nexus_standalone_activity.service import ( + GreetingInput, + GreetingOutput, + GreetingService, +) + + +def get_activity_id(input: GreetingInput) -> str: + return f"greeting-{input.name}" + + +@nexusrpc.handler.service_handler(service=GreetingService) +class GreetingServiceHandler: + @nexus.temporal_operation + async def greet( + self, + _ctx: nexus.TemporalStartOperationContext, + client: nexus.TemporalNexusClient, + input: GreetingInput, + ) -> nexus.TemporalOperationResult[GreetingOutput]: + # The standalone Activity becomes the asynchronous backing execution for + # this Nexus operation. Omitting task_queue uses the Nexus Worker's queue. + return await client.start_activity( + create_greeting, + input, + id=get_activity_id(input), + start_to_close_timeout=timedelta(seconds=10), + ) diff --git a/nexus_standalone_activity/service.py b/nexus_standalone_activity/service.py new file mode 100644 index 000000000..ad3dad25c --- /dev/null +++ b/nexus_standalone_activity/service.py @@ -0,0 +1,20 @@ +"""Nexus service definition shared by the caller and handler.""" + +from dataclasses import dataclass + +import nexusrpc + + +@dataclass +class GreetingInput: + name: str + + +@dataclass +class GreetingOutput: + message: str + + +@nexusrpc.service +class GreetingService: + greet: nexusrpc.Operation[GreetingInput, GreetingOutput] diff --git a/nexus_standalone_activity/starter.py b/nexus_standalone_activity/starter.py new file mode 100644 index 000000000..1db47e11a --- /dev/null +++ b/nexus_standalone_activity/starter.py @@ -0,0 +1,34 @@ +"""Client that executes the activity-backed Nexus operation.""" + +import asyncio +import uuid +from datetime import timedelta + +from temporalio.client import Client +from temporalio.envconfig import ClientConfig + +from nexus_standalone_activity.service import GreetingInput, GreetingService + +ENDPOINT_NAME = "nexus-standalone-activity-endpoint" + + +async def main() -> None: + config = ClientConfig.load_client_connect_config() + _ = config.setdefault("target_host", "localhost:7233") + client = await Client.connect(**config) + + nexus_client = client.create_nexus_client( + service=GreetingService, + endpoint=ENDPOINT_NAME, + ) + result = await nexus_client.execute_operation( + GreetingService.greet, + GreetingInput(name="World"), + id=f"greeting-{uuid.uuid4()}", + schedule_to_close_timeout=timedelta(seconds=10), + ) + print(result.message) + + +if __name__ == "__main__": + asyncio.run(main()) diff --git a/nexus_standalone_activity/worker.py b/nexus_standalone_activity/worker.py new file mode 100644 index 000000000..e4a15a0f2 --- /dev/null +++ b/nexus_standalone_activity/worker.py @@ -0,0 +1,41 @@ +"""Worker hosting the Nexus handler and its standalone Activity.""" + +import asyncio +import logging + +from temporalio.client import Client +from temporalio.envconfig import ClientConfig +from temporalio.worker import Worker + +from nexus_standalone_activity.activity import create_greeting +from nexus_standalone_activity.handler import GreetingServiceHandler + +TASK_QUEUE = "nexus-standalone-activity-handler" + +interrupt_event = asyncio.Event() + + +async def main() -> None: + logging.basicConfig(level=logging.INFO) + + config = ClientConfig.load_client_connect_config() + _ = config.setdefault("target_host", "localhost:7233") + client = await Client.connect(**config) + + async with Worker( + client, + task_queue=TASK_QUEUE, + activities=[create_greeting], + nexus_service_handlers=[GreetingServiceHandler()], + ): + logging.info("Worker started, ctrl+c to exit") + _ = await interrupt_event.wait() + + +if __name__ == "__main__": + loop = asyncio.new_event_loop() + try: + loop.run_until_complete(main()) + except KeyboardInterrupt: + interrupt_event.set() + loop.run_until_complete(loop.shutdown_asyncgens()) diff --git a/tests/conftest.py b/tests/conftest.py index b857e0d96..7f7fe066f 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -42,6 +42,10 @@ async def env(request) -> AsyncGenerator[WorkflowEnvironment, None]: env_type = request.config.getoption("--workflow-environment") if env_type == "local": env = await WorkflowEnvironment.start_local( + dev_server_extra_args=[ + "--dynamic-config-value", + "activity.enableCallbacks=true", + ], dev_server_download_version="v1.7.4-standalone-nexus-operations", ) elif env_type == "time-skipping": diff --git a/tests/nexus_standalone_activity/__init__.py b/tests/nexus_standalone_activity/__init__.py new file mode 100644 index 000000000..7d425474b --- /dev/null +++ b/tests/nexus_standalone_activity/__init__.py @@ -0,0 +1 @@ +"""Tests for the Nexus standalone Activity sample.""" diff --git a/tests/nexus_standalone_activity/nexus_standalone_activity_test.py b/tests/nexus_standalone_activity/nexus_standalone_activity_test.py new file mode 100644 index 000000000..e146c9607 --- /dev/null +++ b/tests/nexus_standalone_activity/nexus_standalone_activity_test.py @@ -0,0 +1,57 @@ +import uuid +from datetime import timedelta + +import pytest +from temporalio.client import Client +from temporalio.testing import WorkflowEnvironment +from temporalio.worker import Worker + +from nexus_standalone_activity.activity import create_greeting +from nexus_standalone_activity.handler import GreetingServiceHandler +from nexus_standalone_activity.service import ( + GreetingInput, + GreetingOutput, + GreetingService, +) +from nexus_standalone_activity.worker import TASK_QUEUE +from tests.helpers.nexus import create_nexus_endpoint, delete_nexus_endpoint + + +async def test_nexus_operation_backed_by_standalone_activity( + client: Client, env: WorkflowEnvironment +) -> None: + if env.supports_time_skipping: + pytest.skip("Time-skipping server does not support standalone Nexus operations") + + endpoint_name = f"test-nexus-standalone-activity-{uuid.uuid4()}" + create_response = await create_nexus_endpoint( + name=endpoint_name, + task_queue=TASK_QUEUE, + client=client, + ) + try: + async with Worker( + client, + task_queue=TASK_QUEUE, + activities=[create_greeting], + nexus_service_handlers=[GreetingServiceHandler()], + ): + nexus_client = client.create_nexus_client( + service=GreetingService, + endpoint=endpoint_name, + ) + result = await nexus_client.execute_operation( + GreetingService.greet, + GreetingInput(name="Test"), + id=str(uuid.uuid4()), + schedule_to_close_timeout=timedelta(seconds=10), + ) + + assert isinstance(result, GreetingOutput) + assert result.message == "Hello, Test!" + finally: + _ = await delete_nexus_endpoint( + id=create_response.endpoint.id, + version=create_response.endpoint.version, + client=client, + )