Thanks to visit codestin.com
Credit goes to github.com

Skip to content

User metadata #701

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 13 commits into from
Dec 16, 2024
Merged

User metadata #701

merged 13 commits into from
Dec 16, 2024

Conversation

Sushisource
Copy link
Member

@Sushisource Sushisource commented Dec 10, 2024

What was changed

  • Added static summary and details to workflow starting/scheduling methods in the client
  • Added summary to activity/child workflow/timer starts from workflows
  • Added ability to get/set dynamic description from within workflows
  • Implement the workflow metadata built-in query

Why?

Checklist

  1. Closes [Feature Request] Support user metadata #670

  2. How was this tested:
    Added & updated tests

  3. Any docs updates needed?

@Sushisource Sushisource marked this pull request as ready for review December 12, 2024 00:34
@Sushisource Sushisource requested a review from a team as a code owner December 12, 2024 00:34
@@ -3400,6 +3461,16 @@ def __init__(
if pair.key.name in self.untyped_search_attributes:
# We know this is mutable here
del self.untyped_search_attributes[pair.key.name] # type: ignore
self.static_summary = (
raw_info.user_metadata.summary
Copy link
Member

Choose a reason for hiding this comment

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

Isn't this a payload? I think you're going to have to change this up a bit to move all of the raw info conversion stuff into _from_proto and make that method async def. May also need a test that confirms schedule describe returns the same workflow summary/details it was created with.

Copy link
Member Author

Choose a reason for hiding this comment

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

This is working exactly the same way memo does when reading from raw info, for example. The tests that compare schedule before/after seem to confirm it works properly but I'll double check

Copy link
Member

Choose a reason for hiding this comment

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

Ah, now I see Optional[Union[str, temporalio.api.common.v1.Payload]], you're good

@@ -1084,6 +1085,29 @@ async def encode_wrapper(
"""
return temporalio.api.common.v1.Payloads(payloads=(await self.encode(values)))

async def _encode_user_metadata(
Copy link
Member

Choose a reason for hiding this comment

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

Since this and the decode equivalent are only called from the client file, can they be made as just underscore-prefixed module-level helpers at the bottom of the client file?

callback: Callable[..., Any],
*args: Any,
context: Optional[contextvars.Context] = None,
options: Optional[_TimerOptions] = None,
Copy link
Member

Choose a reason for hiding this comment

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

Pedantic, but I think it reads better if require this options kwarg and move the _next_timer_options extraction stuff to call_later

Copy link
Member Author

Choose a reason for hiding this comment

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

Works for me


# The current details (as opposed to static details on workflow start), returned in the
# metadata query
self._current_details: str = ""
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
self._current_details: str = ""
self._current_details = ""

(pedantic)

if summary
else None
)
self._timer_impl(
Copy link
Member

Choose a reason for hiding this comment

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

There is nothing awaited here so I don't think this call is going to properly block. Internally I think asyncio invokes that callback on timer complete, so we need to block here waiting on that callback. I'd be ok using an asyncio.Event that is awaited here and set in the callback (or a wait condition, I haven't sat to think about it tbh).

Copy link
Member Author

Choose a reason for hiding this comment

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

Duh, thanks

def _temporal_workflow_metadata(self) -> temporalio.api.sdk.v1.WorkflowMetadata:
query_definitions = [
temporalio.api.sdk.v1.WorkflowInteractionDefinition(
name=qd.name if qd.name is not None else "",
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
name=qd.name if qd.name is not None else "",
name=qd.name or "",

Pedantic, but this is probably good enough and may improve legibility

Comment on lines 254 to 258
@overload
def signal(
*,
description: str,
unfinished_policy: HandlerUnfinishedPolicy = HandlerUnfinishedPolicy.WARN_AND_ABANDON,
Copy link
Member

Choose a reason for hiding this comment

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

I wonder if, instead of this new overload, you can just add description: Optional[str] = None to the one above at line 223. Same for others, ideally you don't need a new overload for signal or update (you do for query because this is the first optional parameter overload)

return _Runtime.current().workflow_get_current_details()


def set_current_details(description: str) -> None:
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
def set_current_details(description: str) -> None:
def set_current_details(current_details: str) -> None:

Pedantic, but this isn't really a "description" per se

@@ -1091,8 +1166,29 @@ def uuid4() -> uuid.UUID:
return uuid.UUID(bytes=random().getrandbits(16 * 8).to_bytes(16, "big"), version=4)


async def sleep(
Copy link
Member

Choose a reason for hiding this comment

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

May want to update README (unsure if that would be just the Timers section or also the Workflow Utilities section), but don't have to

@Sushisource Sushisource changed the title [Draft] User metadata User metadata Dec 12, 2024
@Sushisource Sushisource force-pushed the user-metadata branch 3 times, most recently from 5270251 to b156308 Compare December 12, 2024 19:12
Copy link
Member

@cretz cretz left a comment

Choose a reason for hiding this comment

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

LGTM. @dandavison - unsure if you want to look at this one

@dandavison
Copy link
Contributor

I'm coming cold to this, but maybe that's helpful as a simulation of a user encountering it. My initial reactions to the user-facing API are

  • I wouldn't expect it to be called "summary" -- I think of a summary as something created after an event, whereas this is before. So "description" is more the sort of word I'd expect.

  • The "static_summary" and "static_details" names seem surprising -- is the concept that's being conveyed really so obscure that it needs a name like that?

  • I'm not sure about "timeout_xxx" as a name. There are lots of timeouts in Temporal, and I wonder whether what this really refers to is a "timer", as in the TimerStarted event that it creates.

@cretz
Copy link
Member

cretz commented Dec 13, 2024

This does match a pre-existing spec in the issue and names decided and merged in other SDKs, but we can still discuss...

I wouldn't expect it to be called "summary" -- I think of a summary as something created after an event, whereas this is before. So "description" is more the sort of word I'd expect.

Are you referring to workflow summary, timer summary, or activity summary? In this case we use the word "summary" like a JIRA issue might. There are also "details" which is the longer form ("summary" is the short form), but we didn't feel timers and activities needed details like workflows. It was the best word we could think of to represent this shared data across these (it's actually defined at https://github.com/temporalio/api/blob/38d2ac0af77602baf85c60678f4ab2c09ec47de0/temporal/api/sdk/v1/user_metadata.proto#L39-L43). In this case "summary" is a short-form summarizing what it is and is not related to when created.

The "static_summary" and "static_details" names seem surprising -- is the concept that's being conveyed really so obscure that it needs a name like that?

Unfortunately yes to differentiate "static details" (static, set at start) from "current details" (can be set throughout the workflow), and then we chose "static summary" because it's just a short form of "static details". These are the best terms we could come up with to represent them and still avoid confusion (spec was relayed internally for feedback for many months, but we can still potentially revisit though this is already present in most other SDKs).

I'm not sure about "timeout_xxx" as a name. There are lots of timeouts in Temporal, and I wonder whether what this really refers to is a "timer", as in the TimerStarted event that it creates.

I assume this is for timeout_summary (no other "timeout_xxx" here). This is because there is a timeout field there and this summary only applies to that field and the timer it starts. It could also be called timeout_timer_summary though I think the shorter version makes sense.

@dandavison
Copy link
Contributor

Are you referring to workflow summary, timer summary, or activity summary?

All of those.

Yes these comments should have been made on the spec / design doc. My first thought is description and metadata I think, or user_description and user_metadata.

@cretz
Copy link
Member

cretz commented Dec 13, 2024

We want the concept of a "summary" to be a short form of text and "details" to be the long form. A "summary" isn't a "description" (arguably the "details" are more of a "description" than the "summary"). We decided there was no need for "details" for timer and activity at this time, only "summary". There is no concept of general purpose "user metadata" that a user can set, by intention, but the concept is user metadata and we may add more fields they can set in the future.

@Sushisource Sushisource merged commit 341d949 into main Dec 16, 2024
12 checks passed
@Sushisource Sushisource deleted the user-metadata branch December 16, 2024 17:30
@cretz cretz mentioned this pull request Dec 16, 2024
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.

[Feature Request] Support user metadata
3 participants