Skip to content

Commit f92dd38

Browse files
authored
Merge pull request #269 from Azure/dev
2 parents 3c1ecad + d9dc0a8 commit f92dd38

File tree

8 files changed

+113
-11
lines changed

8 files changed

+113
-11
lines changed
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
---
2+
name: "\U0001F4A1 Feature request"
3+
about: Suggest an idea for this project!
4+
title: ''
5+
labels: ''
6+
assignees: ''
7+
8+
---
9+
10+
💡 **Feature description**
11+
> What would you like to see, and why?
12+
> What kinds of usage do you expect to see in this feature?
13+
14+
💭 **Describe alternatives you've considered**
15+
> What are other ways to achieve this? Have you thought of alternative designs or solutions?
16+
> Any existing workarounds? Why are they not sufficient? We'd like to know!
17+
18+
**Additional context**
19+
> Add any other context or screenshots about the feature request here.
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
---
2+
name: "\U0001F41B Bug report"
3+
about: Did something not work out as expected? Let us know!
4+
title: ''
5+
labels: ''
6+
assignees: ''
7+
8+
---
9+
10+
🐛 **Describe the bug**
11+
> A clear and concise description of what the bug is.
12+
13+
🤔 **Expected behavior**
14+
> What should have happened?
15+
16+
**Steps to reproduce**
17+
> What Durable Functions patterns are you using, if any?
18+
> Any minimal reproducer we can use?
19+
> Are you running this locally or on Azure?
20+
21+
**If deployed to Azure**
22+
> We have access to a lot of telemetry that can help with investigations. Please provide as much of the following information as you can to help us investigate!
23+
24+
- **Timeframe issue observed**:
25+
- **Function App name**:
26+
- **Function name(s)**:
27+
- **Azure region**:
28+
- **Orchestration instance ID(s)**:
29+
- **Azure storage account name**:
30+
31+
> If you don't want to share your Function App or storage account name GitHub, please at least share the orchestration instance ID. Otherwise it's extremely difficult to look up information.

README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
|Branch|Status|
22
|---|---|
3-
|main|[![Build Status](https://azfunc.visualstudio.com/Azure%20Functions%20Python/_apis/build/status/Azure%20Functions%20Durable%20Python?branchName=main)](https://azfunc.visualstudio.com/Azure%20Functions%20Python/_build/latest?definitionId=44&branchName=main)|
4-
|dev|[![Build Status](https://azfunc.visualstudio.com/Azure%20Functions%20Python/_apis/build/status/Azure%20Functions%20Durable%20Python?branchName=dev)](https://azfunc.visualstudio.com/Azure%20Functions%20Python/_build/latest?definitionId=44&branchName=dev)|
3+
|main|[![Build Status](https://azfunc.visualstudio.com/Azure%20Functions/_apis/build/status/Azure.azure-functions-durable-python?branchName=main)](https://azfunc.visualstudio.com/Azure%20Functions/_build/latest?definitionId=58&branchName=main)|
4+
|dev|[![Build Status](https://azfunc.visualstudio.com/Azure%20Functions/_apis/build/status/Azure.azure-functions-durable-python?branchName=dev)](https://azfunc.visualstudio.com/Azure%20Functions/_build/latest?definitionId=58&branchName=dev)|
55

66
# Durable Functions for Python
77

@@ -27,4 +27,4 @@ Follow these instructions to get started with Durable Functions in Python:
2727

2828
## Tooling
2929

30-
* Python Durable Functions requires [Azure Functions Core Tools](https://docs.microsoft.com/en-us/azure/azure-functions/functions-run-local) version 3.0.2630 or higher.
30+
* Python Durable Functions requires [Azure Functions Core Tools](https://docs.microsoft.com/en-us/azure/azure-functions/functions-run-local) version 3.0.2630 or higher.

azure/__init__.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
11
"""Base module for the Python Durable functions."""
22
from pkgutil import extend_path
3-
import typing
4-
__path__: typing.Iterable[str] = extend_path(__path__, __name__)
3+
__path__ = extend_path(__path__, __name__)

azure/durable_functions/__init__.py

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,21 +6,23 @@
66
from .entity import Entity
77
from .models.utils.entity_utils import EntityId
88
from .models.DurableOrchestrationClient import DurableOrchestrationClient
9+
from .models.OrchestrationRuntimeStatus import OrchestrationRuntimeStatus
910
from .models.DurableOrchestrationContext import DurableOrchestrationContext
1011
from .models.DurableEntityContext import DurableEntityContext
1112
from .models.RetryOptions import RetryOptions
1213
from .models.TokenSource import ManagedIdentityTokenSource
1314
import json
1415
from pathlib import Path
1516
import sys
17+
import warnings
1618

1719

1820
def validate_extension_bundles():
19-
"""Throw an exception if host.json contains bundle-range V1.
21+
"""Raise a warning if host.json contains bundle-range V1.
2022
21-
Raises
23+
Effects
2224
------
23-
Exception: Exception prompting the user to update to bundles V2
25+
Warning: Warning prompting the user to update to bundles V2
2426
"""
2527
# No need to validate if we're running tests
2628
if "pytest" in sys.modules:
@@ -46,10 +48,13 @@ def validate_extension_bundles():
4648
# We do a best-effort attempt to detect bundles V1
4749
# This is the string hard-coded into the bundles V1 template in VSCode
4850
if version_range == "[1.*, 2.0.0)":
49-
message = "Durable Functions for Python does not support Bundles V1."\
51+
message = "Your application is currently configured to use Extension Bundles V1."\
52+
" Durable Functions for Python works best with Bundles V2,"\
53+
" which provides additional features like Durable Entities, better performance,"\
54+
" and is actively being developed."\
5055
" Please update to Bundles V2 in your `host.json`."\
5156
" You can set extensionBundles version to be: [2.*, 3.0.0)"
52-
raise Exception(message)
57+
warnings.warn(message)
5358

5459

5560
# Validate that users are not in extension bundles V1
@@ -63,5 +68,6 @@ def validate_extension_bundles():
6368
'DurableEntityContext',
6469
'DurableOrchestrationContext',
6570
'ManagedIdentityTokenSource',
71+
'OrchestrationRuntimeStatus',
6672
'RetryOptions'
6773
]

azure/durable_functions/models/DurableOrchestrationContext.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import json
22
import datetime
33
from typing import List, Any, Dict, Optional
4+
from uuid import UUID, uuid5, NAMESPACE_URL
45

56
from .RetryOptions import RetryOptions
67
from .TaskSet import TaskSet
@@ -444,3 +445,17 @@ def continue_as_new(self, input_: Any):
444445
The new starting input to the orchestrator.
445446
"""
446447
return continue_as_new(context=self, input_=input_)
448+
449+
def new_guid(self) -> UUID:
450+
"""Generate a replay-safe GUID.
451+
452+
Returns
453+
-------
454+
UUID
455+
A new globally-unique ID
456+
"""
457+
guid_name = f"{self.instance_id}_{self.current_utc_datetime}"\
458+
f"_{self._new_uuid_counter}"
459+
self._new_uuid_counter += 1
460+
guid = uuid5(NAMESPACE_URL, guid_name)
461+
return guid

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ def run(self, *args, **kwargs):
4040
'Operating System :: POSIX',
4141
'Operating System :: MacOS :: MacOS X',
4242
'Environment :: Web Environment',
43-
'Development Status :: 4 - Beta',
43+
'Development Status :: 5 - Production/Stable',
4444
],
4545
license='MIT',
4646
python_requires='>=3.6,<4',

tests/orchestrator/test_sequential_orchestrator.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,19 @@ def generator_function_with_serialization(context):
9191

9292
return outputs
9393

94+
def generator_function_new_guid(context):
95+
"""Simple orchestrator that generates 3 GUIDs"""
96+
outputs = []
97+
98+
output1 = context.new_guid()
99+
output2 = context.new_guid()
100+
output3 = context.new_guid()
101+
102+
outputs.append(str(output1))
103+
outputs.append(str(output2))
104+
outputs.append(str(output3))
105+
return outputs
106+
94107

95108
def base_expected_state(output=None) -> OrchestratorState:
96109
return OrchestratorState(is_done=False, actions=[], output=output)
@@ -353,3 +366,22 @@ def test_utc_time_updates_correctly():
353366
assert_valid_schema(result)
354367
assert_orchestration_state_equals(expected, result)
355368

369+
def test_new_guid_orchestrator():
370+
"""Tests that the new_guid API is replay-safe and produces new GUIDs every time"""
371+
context_builder = ContextBuilder('test_guid_orchestrator')
372+
373+
# To test that the API is replay-safe, we generate two orchestrators
374+
# with the same starting context
375+
result1 = get_orchestration_state_result(
376+
context_builder, generator_function_new_guid)
377+
outputs1 = result1["output"]
378+
379+
result2 = get_orchestration_state_result(
380+
context_builder, generator_function_new_guid)
381+
outputs2 = result2["output"]
382+
383+
# All GUIDs should be unique
384+
assert len(outputs1) == len(set(outputs1))
385+
# The two GUID lists should be the same
386+
assert outputs1 == outputs2
387+

0 commit comments

Comments
 (0)