Skip to content

[Look at my other PR first pls!] fix(release): use official durabletask release#939

Closed
sicoyle wants to merge 9 commits intodapr:release-1.17from
sicoyle:fix-use-dt-official-release
Closed

[Look at my other PR first pls!] fix(release): use official durabletask release#939
sicoyle wants to merge 9 commits intodapr:release-1.17from
sicoyle:fix-use-dt-official-release

Conversation

@sicoyle
Copy link
Contributor

@sicoyle sicoyle commented Mar 5, 2026

Description

Durabletask python has only ever had prereleases. I justtttt cut a v0.17.0 so we can use an official release here and in dapr agents instead of a pre-release. This PR builds on top of my other PR so pls review this one last as it is only 2 lines of changes to use the newest durabletask version.

Look at this other PR first pls #938

https://pypi.org/project/durabletask-dapr/#history

Issue reference

We strive to have all PR being opened based on an issue, where the problem or feature have been discussed prior to implementation.

Please reference the issue this PR will close: #[issue number]

Checklist

Please make sure you've completed the relevant tasks for this PR, out of the following list:

  • Code compiles correctly
  • Created/updated tests
  • Extended the documentation

JoshVanL and others added 9 commits March 5, 2026 14:10
* Workflow: remove sleeps from example

Remove arbitrary sleeps from workflow examples

Signed-off-by: joshvanl <me@joshvanl.dev>

* tox -e ruff

Signed-off-by: joshvanl <me@joshvanl.dev>

---------

Signed-off-by: joshvanl <me@joshvanl.dev>
Signed-off-by: Samantha Coyle <sam@diagrid.io>
Signed-off-by: Albert Callarisa <albert@diagrid.io>
Signed-off-by: Samantha Coyle <sam@diagrid.io>
dapr#901)

* fix: signal when dt reader stream is ready within wf client start call

Signed-off-by: Samantha Coyle <sam@diagrid.io>

* style: appease linter

Signed-off-by: Samantha Coyle <sam@diagrid.io>

* fix: enable configurability + lint fixes

Signed-off-by: Samantha Coyle <sam@diagrid.io>

* fix(build): add tests and fix bug

Signed-off-by: Samantha Coyle <sam@diagrid.io>

* fix(build): add more tests

Signed-off-by: Samantha Coyle <sam@diagrid.io>

* style: appease linter

Signed-off-by: Samantha Coyle <sam@diagrid.io>

* fix(build): add another test

Signed-off-by: Samantha Coyle <sam@diagrid.io>

* test: add even more tests for build to pass lol

Signed-off-by: Samantha Coyle <sam@diagrid.io>

---------

Signed-off-by: Samantha Coyle <sam@diagrid.io>
* feat(convo): add new fields to conversation api

Signed-off-by: Samantha Coyle <sam@diagrid.io>

* fix: update proto/grpc code generator and add more tests

Signed-off-by: Samantha Coyle <sam@diagrid.io>

* style: appease linter

Signed-off-by: Samantha Coyle <sam@diagrid.io>

* style: tox -e type fixes

Signed-off-by: Samantha Coyle <sam@diagrid.io>

---------

Signed-off-by: Samantha Coyle <sam@diagrid.io>
Signed-off-by: Cassandra Coyle <cassie@diagrid.io>
Co-authored-by: Sam <sam@diagrid.io>
Signed-off-by: Samantha Coyle <sam@diagrid.io>
Signed-off-by: Matheus André <92062874+matheusandre1@users.noreply.github.com>
Signed-off-by: Samantha Coyle <sam@diagrid.io>
…ask (dapr#889)

* chore(deps): bump dapr dep to 1.17.0.dev

Signed-off-by: Casper Nielsen <casper@diagrid.io>

* chore(deps): bump durabletask-dapr to 0.2.0a15

Signed-off-by: Casper Nielsen <casper@diagrid.io>

* feat: ensure taskhubgrpcclient expose .close() method for clients to pass down a close call to durabletask

Signed-off-by: Casper Nielsen <casper@diagrid.io>

---------

Signed-off-by: Casper Nielsen <casper@diagrid.io>
Signed-off-by: Samantha Coyle <sam@diagrid.io>
dapr#901)

* fix: signal when dt reader stream is ready within wf client start call

Signed-off-by: Samantha Coyle <sam@diagrid.io>

* style: appease linter

Signed-off-by: Samantha Coyle <sam@diagrid.io>

* fix: enable configurability + lint fixes

Signed-off-by: Samantha Coyle <sam@diagrid.io>

* fix(build): add tests and fix bug

Signed-off-by: Samantha Coyle <sam@diagrid.io>

* fix(build): add more tests

Signed-off-by: Samantha Coyle <sam@diagrid.io>

* style: appease linter

Signed-off-by: Samantha Coyle <sam@diagrid.io>

* fix(build): add another test

Signed-off-by: Samantha Coyle <sam@diagrid.io>

* test: add even more tests for build to pass lol

Signed-off-by: Samantha Coyle <sam@diagrid.io>

---------

Signed-off-by: Samantha Coyle <sam@diagrid.io>
Signed-off-by: Samantha Coyle <sam@diagrid.io>
Copilot AI review requested due to automatic review settings March 5, 2026 20:43
@sicoyle sicoyle requested review from a team as code owners March 5, 2026 20:43
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Updates dependencies and client/runtime behavior to align with the official durabletask-dapr release and newer API surface area.

Changes:

  • Bump durabletask-dapr dependency to >= 0.17.0 in workflow extension and dev requirements.
  • Add worker readiness polling/logging to WorkflowRuntime and expand tests accordingly.
  • Extend Conversation (Alpha2) support for model, token usage details, and request fields like response_format / prompt_cache_retention.

Reviewed changes

Copilot reviewed 18 out of 18 changed files in this pull request and generated 7 comments.

Show a summary per file
File Description
ext/dapr-ext-workflow/setup.cfg Bumps workflow extension dependency to official durabletask-dapr release.
dev-requirements.txt Keeps dev dependencies aligned with new official durabletask-dapr version.
ext/dapr-ext-workflow/dapr/ext/workflow/workflow_runtime.py Adds readiness waiting and improves exception logging around workflow/activity execution.
ext/dapr-ext-workflow/dapr/ext/workflow/logger/logger.py Adds Logger.exception() wrapper used by WorkflowRuntime.
ext/dapr-ext-workflow/tests/test_workflow_runtime.py Adds unit tests for worker readiness behavior and start/shutdown paths.
dapr/clients/grpc/client.py Adds converse_alpha2 request fields (response_format, prompt_cache_retention).
dapr/clients/grpc/conversation.py Adds Alpha2 model/usage dataclasses and populates them from gRPC responses.
tests/clients/test_conversation.py Adds coverage for Alpha2 model/usage, response_format passthrough, and output parsing helper.
tests/clients/fake_dapr_server.py Extends fake server to populate model and usage when supported by proto.
ext/dapr-ext-workflow/dapr/ext/workflow/workflow_context.py Documentation wording change from “cross-app” to “multi-app”.
ext/dapr-ext-workflow/dapr/ext/workflow/dapr_workflow_context.py Documentation/log wording change from “cross-app” to “multi-app”.
examples/workflow/*.py Updates examples to rely less on sleeps and use workflow completion waiting.
examples/workflow/README.md Renames “Cross-app” docs/commands to “Multi-app” terminology.
README.md Improves contributor setup instructions by adding a venv step and renumbering.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +695 to +728
model: Optional[str] = None
usage: Optional[ConversationResultAlpha2CompletionUsage] = None
if hasattr(output, 'model') and getattr(output, 'model', None):
model = output.model
if hasattr(output, 'usage') and output.usage:
u = output.usage
completion_details: Optional[
ConversationResultAlpha2CompletionUsageCompletionTokensDetails
] = None
prompt_details: Optional[ConversationResultAlpha2CompletionUsagePromptTokensDetails] = (
None
)
if hasattr(u, 'completion_tokens_details') and u.completion_tokens_details:
cd = u.completion_tokens_details
completion_details = ConversationResultAlpha2CompletionUsageCompletionTokensDetails(
accepted_prediction_tokens=getattr(cd, 'accepted_prediction_tokens', 0) or 0,
audio_tokens=getattr(cd, 'audio_tokens', 0) or 0,
reasoning_tokens=getattr(cd, 'reasoning_tokens', 0) or 0,
rejected_prediction_tokens=getattr(cd, 'rejected_prediction_tokens', 0) or 0,
)
if hasattr(u, 'prompt_tokens_details') and u.prompt_tokens_details:
pd = u.prompt_tokens_details
prompt_details = ConversationResultAlpha2CompletionUsagePromptTokensDetails(
audio_tokens=getattr(pd, 'audio_tokens', 0) or 0,
cached_tokens=getattr(pd, 'cached_tokens', 0) or 0,
)
usage = ConversationResultAlpha2CompletionUsage(
completion_tokens=getattr(u, 'completion_tokens', 0) or 0,
prompt_tokens=getattr(u, 'prompt_tokens', 0) or 0,
total_tokens=getattr(u, 'total_tokens', 0) or 0,
completion_tokens_details=completion_details,
prompt_tokens_details=prompt_details,
)
outputs.append(ConversationResultAlpha2(choices=choices, model=model, usage=usage))
Copy link

Copilot AI Mar 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

output.usage / u.completion_tokens_details / u.prompt_tokens_details are protobuf message fields; their truthiness is not a reliable indicator of presence (and may evaluate truthy even when unset). This can incorrectly populate usage (and details) with zero-valued objects when the server didn't send usage, changing API semantics from None to 'all zeros'. Prefer presence checks like HasField('usage') when available, or u.ListFields() / u.ByteSize() > 0 to detect an actually-populated submessage before constructing these dataclasses.

Copilot uses AI. Check for mistakes.
self._logger.exception(
f'WorkflowRuntime wait_for_worker_ready() raised exception: {ready_error}'
)
raise ready_error
Copy link

Copilot AI Mar 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re-raising with raise ready_error discards the original traceback context. Use a bare raise here to preserve the original stack trace (you’re already logging with exception()).

Suggested change
raise ready_error
raise

Copilot uses AI. Check for mistakes.
Comment on lines +217 to +224
elapsed = 0.0
poll_interval = 0.1 # 100ms

while elapsed < timeout:
if self.__worker.is_worker_ready():
return True
time.sleep(poll_interval)
elapsed += poll_interval
Copy link

Copilot AI Mar 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The timeout accounting is based on incrementing by poll_interval, which can drift from wall-clock time (sleep delays, scheduling, etc.). Using a monotonic clock (e.g., store deadline = time.monotonic() + timeout and loop until time.monotonic() >= deadline) makes the timeout behavior more accurate and avoids potential overshoot.

Suggested change
elapsed = 0.0
poll_interval = 0.1 # 100ms
while elapsed < timeout:
if self.__worker.is_worker_ready():
return True
time.sleep(poll_interval)
elapsed += poll_interval
poll_interval = 0.1 # 100ms
deadline = time.monotonic() + timeout
while time.monotonic() < deadline:
if self.__worker.is_worker_ready():
return True
time.sleep(poll_interval)

Copilot uses AI. Check for mistakes.
def setUp(self):
listActivities.clear()
listOrchestrators.clear()
mock.patch('durabletask.worker._Registry', return_value=FakeTaskHubGrpcWorker()).start()
Copy link

Copilot AI Mar 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This patcher is started in setUp() but never stopped, which can leak state across tests and make ordering-dependent failures likely. Store the patcher (e.g., self._patcher = mock.patch(...)) and stop it in tearDown() or via self.addCleanup(self._patcher.stop).

Suggested change
mock.patch('durabletask.worker._Registry', return_value=FakeTaskHubGrpcWorker()).start()
self._registry_patcher = mock.patch(
'durabletask.worker._Registry',
return_value=FakeTaskHubGrpcWorker(),
)
self._registry_patcher.start()
self.addCleanup(self._registry_patcher.stop)

Copilot uses AI. Check for mistakes.
Comment on lines +193 to +196
del mock_worker.is_worker_ready
self.runtime._WorkflowRuntime__worker = mock_worker
self.assertFalse(self.runtime.wait_for_worker_ready(timeout=0.1))

Copy link

Copilot AI Mar 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

mock_worker is created with a restrictive spec that does not include is_worker_ready, so del mock_worker.is_worker_ready will raise AttributeError (the attribute doesn't exist). To model 'no is_worker_ready', just avoid creating/deleting it (the spec already achieves that), or use a plain object/MagicMock without setting the attribute at all and rely on hasattr(...) behavior in the implementation.

Suggested change
del mock_worker.is_worker_ready
self.runtime._WorkflowRuntime__worker = mock_worker
self.assertFalse(self.runtime.wait_for_worker_ready(timeout=0.1))
self.runtime._WorkflowRuntime__worker = mock_worker
self.assertFalse(self.runtime.wait_for_worker_ready(timeout=0.1))

Copilot uses AI. Check for mistakes.

def test_start_logs_warning_when_no_is_worker_ready(self):
mock_worker = mock.MagicMock(spec=['start', 'stop', '_registry'])
del mock_worker.is_worker_ready
Copy link

Copilot AI Mar 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same issue as above: deleting is_worker_ready on a MagicMock(spec=[...]) where the attribute never existed will raise AttributeError. Remove the del ... and let the spec enforce the absence, or use a different mock strategy to represent the missing attribute.

Suggested change
del mock_worker.is_worker_ready

Copilot uses AI. Check for mistakes.
total_tokens=15,
)
result.usage.CopyFrom(u)
except Exception:
Copy link

Copilot AI Mar 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The broad except Exception: pass will silently hide real incompatibilities/typos in the fake server and can make tests pass while behavior is broken. Prefer catching the specific expected exceptions (e.g., AttributeError, TypeError) and/or at least fail fast (re-raise) so test failures point to the root cause.

Suggested change
except Exception:
except (AttributeError, TypeError):
# Ignore usage population issues due to minor API/type differences in the fake server

Copilot uses AI. Check for mistakes.
@codecov
Copy link

codecov bot commented Mar 5, 2026

Codecov Report

❌ Patch coverage is 89.75610% with 21 lines in your changes missing coverage. Please review.
⚠️ Please upload report for BASE (release-1.17@f3339f6). Learn more about missing BASE report.

Files with missing lines Patch % Lines
...ext-workflow/dapr/ext/workflow/workflow_runtime.py 64.28% 20 Missing ⚠️
dapr/clients/grpc/client.py 83.33% 1 Missing ⚠️
Additional details and impacted files
@@               Coverage Diff               @@
##             release-1.17     #939   +/-   ##
===============================================
  Coverage                ?   86.89%           
===============================================
  Files                   ?      103           
  Lines                   ?     7305           
  Branches                ?        0           
===============================================
  Hits                    ?     6348           
  Misses                  ?      957           
  Partials                ?        0           

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@sicoyle
Copy link
Contributor Author

sicoyle commented Mar 6, 2026

can close this one since it is covered by #944

@sicoyle sicoyle closed this Mar 6, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants