-
Notifications
You must be signed in to change notification settings - Fork 103
Patch support and random/UUID helpers #35
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,11 +5,13 @@ | |
import asyncio | ||
import inspect | ||
import logging | ||
import uuid | ||
from abc import ABC, abstractmethod | ||
from dataclasses import dataclass | ||
from datetime import datetime, timedelta | ||
from enum import IntEnum | ||
from functools import partial | ||
from random import Random | ||
from typing import ( | ||
TYPE_CHECKING, | ||
Any, | ||
|
@@ -365,6 +367,14 @@ def workflow_is_replaying(self) -> bool: | |
def workflow_now(self) -> datetime: | ||
... | ||
|
||
@abstractmethod | ||
def workflow_patch(self, id: str, *, deprecated: bool) -> bool: | ||
... | ||
|
||
@abstractmethod | ||
def workflow_random(self) -> Random: | ||
... | ||
|
||
@abstractmethod | ||
def workflow_set_query_handler( | ||
self, name: Optional[str], handler: Optional[Callable] | ||
|
@@ -436,6 +446,20 @@ async def workflow_wait_condition( | |
... | ||
|
||
|
||
def deprecate_patch(id: str) -> None: | ||
"""Mark a patch as deprecated. | ||
|
||
This marks a workflow that had :py:func:`patched` in a previous version of | ||
the code as no longer applicable because all workflows that use the old code | ||
path are done and will never be queried again. Therefore the old code path | ||
is removed as well. | ||
|
||
Args: | ||
id: The identifier originally used with :py:func:`patched`. | ||
""" | ||
_Runtime.current().workflow_patch(id, deprecated=True) | ||
|
||
|
||
def info() -> Info: | ||
"""Current workflow's info. | ||
|
||
|
@@ -454,6 +478,51 @@ def now() -> datetime: | |
return _Runtime.current().workflow_now() | ||
|
||
|
||
def patched(id: str) -> bool: | ||
"""Patch a workflow. | ||
|
||
When called, this will only return true if code should take the newer path | ||
which means this is either not replaying or is replaying and has seen this | ||
patch before. | ||
|
||
Use :py:func:`deprecate_patch` when all workflows are done and will never be | ||
queried again. The old code path can be used at that time too. | ||
|
||
Args: | ||
id: The identifier for this patch. This identifier may be used | ||
repeatedly in the same workflow to represent the same patch | ||
|
||
Returns: | ||
True if this should take the newer path, false if it should take the | ||
older path. | ||
""" | ||
return _Runtime.current().workflow_patch(id, deprecated=False) | ||
|
||
|
||
def random() -> Random: | ||
"""Get a deterministic pseudo-random number generator. | ||
|
||
Note, this random number generator is not cryptographically safe and should | ||
not be used for security purposes. | ||
|
||
Returns: | ||
The deterministically-seeded pseudo-random number generator. | ||
""" | ||
return _Runtime.current().workflow_random() | ||
|
||
|
||
def uuid4() -> uuid.UUID: | ||
"""Get a new, determinism-safe v4 UUID based on :py:func:`random`. | ||
|
||
Note, this UUID is not cryptographically safe and should not be used for | ||
security purposes. | ||
|
||
Returns: | ||
A deterministically-seeded v4 UUID. | ||
""" | ||
return uuid.UUID(bytes=random().getrandbits(16 * 8).to_bytes(16, "big"), version=4) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is so much better than what I had to do in TS to get random and uuid. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Saw that. This could be even better if I was able to use I hesitated adding these APIs at all because I was hoping a sandbox could provide the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If we do have sandbox in the future we'll probably reuse these random and uuid implementations |
||
|
||
|
||
async def wait_condition( | ||
fn: Callable[[], bool], *, timeout: Optional[float] = None | ||
) -> None: | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not necessary for this PR, but probably makes sense to link to docs page explaining the patch lifecycle
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unfortunately that doesn't exist for Python yet. https://docs.temporal.io/typescript/patching will be perfect in Python form if/when it exists. I have opened #37 to track this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It should probably be part of the app dev guide