Skip to content

Conversation

@mfateev
Copy link
Member

@mfateev mfateev commented Mar 29, 2025

What was changed

Added updatable_timer sample based on the Java one.

Why?

It demonstrates how to use workflow.wait_condition with a timeout. How to update the sleep interval is a FAQ.

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.

May also want a simple test on this one

Copy link
Member

Choose a reason for hiding this comment

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

Like our other samples w/ no special install instructions, may want to link to top-level README for "prerequisites"

Comment on lines 9 to 27
@workflow.defn
class Workflow:
def __init__(self):
self.timer: Optional[UpdatableTimer] = None

@workflow.run
async def run(self, wake_up_time: float):
self.timer = UpdatableTimer(
datetime.fromtimestamp(wake_up_time, tz=timezone.utc)
)
await self.timer.sleep()

@workflow.signal
async def update_wake_up_time(self, wake_up_time: float):
# Deals with situation when the signal method is called before the run method.
# This happens when a workflow task is executed after a signal is received
# or when a workflow is started using the signal-with-start.
await workflow.wait_condition(lambda: self.timer is not None)
assert self.timer is not None # for mypy
Copy link
Member

Choose a reason for hiding this comment

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

We have a neat, fairly new feature for @workflow.init that lets you operate on workflow input on the constructor, so can change this to:

Suggested change
@workflow.defn
class Workflow:
def __init__(self):
self.timer: Optional[UpdatableTimer] = None
@workflow.run
async def run(self, wake_up_time: float):
self.timer = UpdatableTimer(
datetime.fromtimestamp(wake_up_time, tz=timezone.utc)
)
await self.timer.sleep()
@workflow.signal
async def update_wake_up_time(self, wake_up_time: float):
# Deals with situation when the signal method is called before the run method.
# This happens when a workflow task is executed after a signal is received
# or when a workflow is started using the signal-with-start.
await workflow.wait_condition(lambda: self.timer is not None)
assert self.timer is not None # for mypy
@workflow.defn
class Workflow:
@workflow.init
def __init__(self, wake_up_time: float) -> None:
self.timer = UpdatableTimer(
datetime.fromtimestamp(wake_up_time, tz=timezone.utc)
)
@workflow.run
async def run(self, wake_up_time: float) -> None:
await self.timer.sleep()
@workflow.signal
async def update_wake_up_time(self, wake_up_time: float):

(also can remove the assert self.timer is not None # for mypy in the query)

Copy link
Member Author

Choose a reason for hiding this comment

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

Nice! So much clearer!


@workflow.defn
class Workflow:
def __init__(self):
Copy link
Member

Choose a reason for hiding this comment

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

Recommend return type annotations everywhere

Copy link
Member Author

Choose a reason for hiding this comment

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

My Java brain protested this for a constructor :).

Refactored workflow to use workflow.init.
Added unit test.
@cretz cretz merged commit 7577bd6 into temporalio:main Apr 1, 2025
10 checks passed
@mfateev mfateev deleted the updatable-timer branch April 1, 2025 20:21
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.

2 participants