Skip to content

Commit 625eb7f

Browse files
authored
Bugfix for checking durable functions implicit output (#1099)
* Durable functions fix * Added durable to extra requires * Updated webhooks * removed webhooks * Test fixes * Fixed flake8 errors * Added storage account to unit test pipeline * Update macos image for build pipeline
1 parent bcdb5cf commit 625eb7f

File tree

12 files changed

+128
-2
lines changed

12 files changed

+128
-2
lines changed

.github/workflows/ut_ci_workflow.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,8 @@ jobs:
6767
retry 5 python setup.py webhost --branch-name=dev
6868
retry 5 python setup.py extension
6969
- name: Test with pytest
70+
env:
71+
AzureWebJobsStorage: ${{ secrets.LinuxStorageConnectionString310 }}
7072
run: |
7173
python -m pytest --instafail --cov=./azure_functions_worker --cov-report xml --cov-branch tests/unittests
7274
- name: Codecov

azure-pipelines.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ jobs:
8989
artifactName: '$(pythonVersion)_LINUX_X64'
9090
- job: Build_OSX_X64
9191
pool:
92-
vmImage: 'macOS-10.15'
92+
vmImage: 'macOS-12'
9393
strategy:
9494
matrix:
9595
Python37V4:

azure_functions_worker/functions.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -340,7 +340,7 @@ def add_function(self, function_id: str,
340340
has_explicit_return, has_implicit_return = \
341341
self.get_explicit_and_implicit_return(
342342
binding_name, binding_info, has_explicit_return,
343-
has_explicit_return, bound_params)
343+
has_implicit_return, bound_params)
344344

345345
return_binding_name = self.get_return_binding(binding_name,
346346
binding_info.type,

azure_functions_worker/testutils.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -782,6 +782,9 @@ def popen_webhost(*, stdout, stderr, script_root=FUNCS_PATH, port=None):
782782
hostexe_args = []
783783
os.environ['AzureWebJobsFeatureFlags'] = 'EnableWorkerIndexing'
784784

785+
# webhook for durable tests
786+
os.environ['WEBSITE_HOSTNAME'] = f'http://*:{port}'
787+
785788
# If we want to use core-tools
786789
coretools_exe = os.environ.get('CORE_TOOLS_EXE_PATH')
787790
if coretools_exe:

setup.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,8 @@
5555
<PackageReference
5656
Include="Microsoft.Azure.WebJobs.Script.ExtensionsMetadataGenerator"
5757
Version="1.1.3" />
58+
<PackageReference Include="Microsoft.Azure.WebJobs.Extensions.DurableTask"
59+
Version="2.7.2" />
5860
</ItemGroup>
5961
</Project>
6062
"""
@@ -114,6 +116,7 @@
114116
EXTRA_REQUIRES = {
115117
"dev": [
116118
"azure-eventhub~=5.7.0", # Used for EventHub E2E tests
119+
"azure-functions-durable", # Used for Durable E2E tests
117120
"flask",
118121
"fastapi",
119122
"pydantic",
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# This function an HTTP starter function for Durable Functions.
2+
# Before running this sample, please:
3+
# - create a Durable orchestration function
4+
# - create a Durable activity function (default name is "Hello")
5+
# - add azure-functions-durable to requirements.txt
6+
# - run pip install -r requirements.txt
7+
import logging
8+
9+
import azure.functions as func
10+
import azure.durable_functions as df
11+
12+
13+
async def main(req: func.HttpRequest, starter: str) -> func.HttpResponse:
14+
client = df.DurableOrchestrationClient(starter)
15+
instance_id = await client.start_new(req.route_params["functionName"], None,
16+
None)
17+
18+
logging.info(f"Started orchestration with ID = '{instance_id}'.")
19+
20+
return client.create_check_status_response(req, instance_id)
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
{
2+
"scriptFile": "__init__.py",
3+
"bindings": [
4+
{
5+
"authLevel": "anonymous",
6+
"name": "req",
7+
"type": "httpTrigger",
8+
"direction": "in",
9+
"route": "orchestrators/{functionName}",
10+
"methods": [
11+
"post",
12+
"get"
13+
]
14+
},
15+
{
16+
"name": "$return",
17+
"type": "http",
18+
"direction": "out"
19+
},
20+
{
21+
"name": "starter",
22+
"type": "durableClient",
23+
"direction": "in"
24+
}
25+
]
26+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# This function is not intended to be invoked directly. Instead it will be
2+
# triggered by an HTTP starter function.
3+
# Before running this sample, please:
4+
# - create a Durable activity function (default name is "Hello")
5+
# - create a Durable HTTP starter function
6+
# - add azure-functions-durable to requirements.txt
7+
# - run pip install -r requirements.txt
8+
import azure.durable_functions as df
9+
10+
11+
def orchestrator_function(context: df.DurableOrchestrationContext):
12+
result1 = yield context.call_activity('Hello', "Tokyo")
13+
result2 = yield context.call_activity('Hello', "Seattle")
14+
result3 = yield context.call_activity('Hello', "London")
15+
return [result1, result2, result3]
16+
17+
18+
main = df.Orchestrator.create(orchestrator_function)
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{
2+
"scriptFile": "__init__.py",
3+
"bindings": [
4+
{
5+
"name": "context",
6+
"type": "orchestrationTrigger",
7+
"direction": "in"
8+
}
9+
]
10+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# This function is not intended to be invoked directly. Instead it will be
2+
# triggered by an orchestrator function.
3+
# Before running this sample, please:
4+
# - create a Durable orchestration function
5+
# - create a Durable HTTP starter function
6+
# - add azure-functions-durable to requirements.txt
7+
# - run pip install -r requirements.txt
8+
9+
def main(name: str, blob) -> str:
10+
blob.set("test-durable")
11+
return f"Hello {name}!"
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
{
2+
"scriptFile": "__init__.py",
3+
"bindings": [
4+
{
5+
"name": "name",
6+
"type": "activityTrigger",
7+
"direction": "in"
8+
},
9+
{
10+
"type": "blob",
11+
"direction": "out",
12+
"name": "blob",
13+
"path": "python-worker-tests/test-return1.txt",
14+
"connection": "AzureWebJobsStorage"
15+
}
16+
17+
]
18+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# Copyright (c) Microsoft Corporation. All rights reserved.
2+
# Licensed under the MIT License.
3+
from azure_functions_worker import testutils
4+
5+
6+
class TestDurableFunctions(testutils.WebHostTestCase):
7+
8+
@classmethod
9+
def get_script_dir(cls):
10+
return testutils.E2E_TESTS_FOLDER / 'durable_functions'
11+
12+
def test_durable(self):
13+
r = self.webhost.request('GET',
14+
'orchestrators/DurableFunctionsOrchestrator')
15+
self.assertEqual(r.status_code, 202)

0 commit comments

Comments
 (0)