Skip to content

Commit 25b86eb

Browse files
author
Hanzhang Zeng (Roger)
committed
Add sample for activity trigger type checks
1 parent 6592177 commit 25b86eb

File tree

35 files changed

+593
-0
lines changed

35 files changed

+593
-0
lines changed
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
.git*
2+
.vscode
3+
local.settings.json
4+
test
5+
.venv
Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
# Byte-compiled / optimized / DLL files
2+
__pycache__/
3+
*.py[cod]
4+
*$py.class
5+
6+
# C extensions
7+
*.so
8+
9+
# Distribution / packaging
10+
.Python
11+
build/
12+
develop-eggs/
13+
dist/
14+
downloads/
15+
eggs/
16+
.eggs/
17+
lib/
18+
lib64/
19+
parts/
20+
sdist/
21+
var/
22+
wheels/
23+
pip-wheel-metadata/
24+
share/python-wheels/
25+
*.egg-info/
26+
.installed.cfg
27+
*.egg
28+
MANIFEST
29+
30+
# PyInstaller
31+
# Usually these files are written by a python script from a template
32+
# before PyInstaller builds the exe, so as to inject date/other infos into it.
33+
*.manifest
34+
*.spec
35+
36+
# Installer logs
37+
pip-log.txt
38+
pip-delete-this-directory.txt
39+
40+
# Unit test / coverage reports
41+
htmlcov/
42+
.tox/
43+
.nox/
44+
.coverage
45+
.coverage.*
46+
.cache
47+
nosetests.xml
48+
coverage.xml
49+
*.cover
50+
.hypothesis/
51+
.pytest_cache/
52+
53+
# Translations
54+
*.mo
55+
*.pot
56+
57+
# Django stuff:
58+
*.log
59+
local_settings.py
60+
db.sqlite3
61+
62+
# Flask stuff:
63+
instance/
64+
.webassets-cache
65+
66+
# Scrapy stuff:
67+
.scrapy
68+
69+
# Sphinx documentation
70+
docs/_build/
71+
72+
# PyBuilder
73+
target/
74+
75+
# Jupyter Notebook
76+
.ipynb_checkpoints
77+
78+
# IPython
79+
profile_default/
80+
ipython_config.py
81+
82+
# pyenv
83+
.python-version
84+
85+
# pipenv
86+
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
87+
# However, in case of collaboration, if having platform-specific dependencies or dependencies
88+
# having no cross-platform support, pipenv may install dependencies that don’t work, or not
89+
# install all needed dependencies.
90+
#Pipfile.lock
91+
92+
# celery beat schedule file
93+
celerybeat-schedule
94+
95+
# SageMath parsed files
96+
*.sage.py
97+
98+
# Environments
99+
.env
100+
.venv
101+
env/
102+
venv/
103+
ENV/
104+
env.bak/
105+
venv.bak/
106+
107+
# Spyder project settings
108+
.spyderproject
109+
.spyproject
110+
111+
# Rope project settings
112+
.ropeproject
113+
114+
# mkdocs documentation
115+
/site
116+
117+
# mypy
118+
.mypy_cache/
119+
.dmypy.json
120+
dmypy.json
121+
122+
# Pyre type checker
123+
.pyre/
124+
125+
# Azure Functions artifacts
126+
bin
127+
obj
128+
appsettings.json
129+
local.settings.json
130+
.python_packages
131+
132+
# pycharm
133+
.idea
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
import json
2+
import os
3+
4+
import azure.functions as func
5+
import azure.durable_functions as df
6+
7+
def orchestrator_function(context: df.DurableOrchestrationContext):
8+
"""This function provides a sample for activity trigger
9+
10+
Parameters
11+
----------
12+
context: DurableOrchestrationContext
13+
This context has the past history and the durable orchestration API
14+
15+
Returns
16+
-------
17+
message
18+
Returns the result of the activity function return values.
19+
20+
Yields
21+
-------
22+
call_activity: str
23+
Yields, depending on the `json_rule`, to wait on either all
24+
tasks to complete, or until one of the tasks completes.
25+
"""
26+
27+
message = []
28+
29+
ret_bool = yield context.call_activity("ReturnBool", "1")
30+
message.append(f"ret_bool: {ret_bool} {type(ret_bool)}")
31+
32+
# Not supported: return value from activity trigger "bytes" is not json serializable!
33+
# ret_bytes = yield context.call_activity("ReturnBytes", "1b2b3b")
34+
# message.append(f"ret_bytes : {ret_bytes} {type(ret_bytes)}")
35+
36+
ret_dict_of_string = yield context.call_activity("ReturnDictOfString", "kv")
37+
message.append(f"ret_dict_of_string : {ret_dict_of_string} {type(ret_dict_of_string)}")
38+
39+
ret_dict_of_string_anno = yield context.call_activity("ReturnDictOfStringWithAnnotation", "kv_anno")
40+
message.append(f"ret_dict_of_string_anno : {ret_dict_of_string_anno} {type(ret_dict_of_string_anno)}")
41+
42+
ret_float = yield context.call_activity("ReturnFloat", "123.0")
43+
message.append(f"ret_float : {ret_float} {type(ret_float)}")
44+
45+
ret_int = yield context.call_activity("ReturnInt", "123")
46+
message.append(f"ret_int : {ret_int} {type(ret_int)}")
47+
48+
ret_int_from_float = yield context.call_activity("ReturnIntFromFloat", 3.14)
49+
message.append(f"ret_int_from_float : {ret_int_from_float} {type(ret_int_from_float)}")
50+
51+
ret_list_of_float = yield context.call_activity("ReturnListOfFloat", "4.5")
52+
message.append(f"ret_list_of_float : {ret_list_of_float} {type(ret_list_of_float)}")
53+
54+
ret_list_of_float_anno = yield context.call_activity("ReturnListOfFloatWithAnnotation", "5.6")
55+
message.append(f"ret_list_of_float_anno : {ret_list_of_float_anno} {type(ret_list_of_float_anno)}")
56+
57+
# Not supported: return value from activity trigger "set" is not json serializable!
58+
# ret_set_of_int = yield context.call_activity("ReturnSetOfInt", 5)
59+
# message.append(f"ret_set_of_int : {ret_set_of_int} {type(ret_set_of_int)}")
60+
61+
ret_string = yield context.call_activity("ReturnString", "simple_string")
62+
message.append(f"ret_string : {ret_string} {type(ret_string)}")
63+
64+
return message
65+
66+
67+
main = df.Orchestrator.create(orchestrator_function)
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
{
2+
"scriptFile": "__init__.py",
3+
"bindings": [
4+
{
5+
"name": "context",
6+
"type": "orchestrationTrigger",
7+
"direction": "in"
8+
}
9+
],
10+
"disabled": false
11+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import logging
2+
3+
from azure.durable_functions import DurableOrchestrationClient
4+
import azure.functions as func
5+
6+
7+
async def main(req: func.HttpRequest, starter: str, message):
8+
"""This function starts up the orchestrator from an HTTP endpoint
9+
10+
Parameters
11+
----------
12+
req: func.HttpRequest
13+
An HTTP Request object, it can be used to parse URL
14+
parameters.
15+
16+
starter: str
17+
A JSON-formatted string describing the orchestration context
18+
19+
message:
20+
An azure functions http output binding, it enables us to establish
21+
an http response.
22+
"""
23+
24+
function_name = req.route_params.get('functionName')
25+
logging.info(starter)
26+
client = DurableOrchestrationClient(starter)
27+
instance_id = await client.start_new(function_name)
28+
response = client.create_check_status_response(req, instance_id)
29+
message.set(response)
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
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+
"direction": "out",
17+
"name": "message",
18+
"type": "http"
19+
},
20+
{
21+
"name": "starter",
22+
"type": "orchestrationClient",
23+
"direction": "in",
24+
"datatype": "string"
25+
}
26+
]
27+
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
# Activity-Trigger-Type - Sample
2+
3+
This sample exemplifies how to return values in primitive Python types from Python Durable Functions Activity Trigger.
4+
5+
## Usage Instructions
6+
7+
### Create a `local.settings.json` file in this directory
8+
This file stores app settings, connection strings, and other settings used by local development tools. Learn more about it [here](https://docs.microsoft.com/en-us/azure/azure-functions/functions-run-local?tabs=windows%2Ccsharp%2Cbash#local-settings-file).
9+
For this sample, you will only need an `AzureWebJobsStorage` connection string, which you can obtain from the Azure portal.
10+
11+
With you connection string, your `local.settings.json` file should look as follows, with `<your connection string>` replaced with the connection string you obtained from the Azure portal:
12+
13+
```json
14+
{
15+
"IsEncrypted": false,
16+
"Values": {
17+
"AzureWebJobsStorage": "<your connection string>",
18+
"FUNCTIONS_WORKER_RUNTIME": "python"
19+
}
20+
}
21+
```
22+
23+
### Run the Sample
24+
To try this sample, run `func host start` in this directory. If all the system requirements have been met, and
25+
after some initialization logs, you should see something like the following:
26+
27+
```bash
28+
Http Functions:
29+
30+
DurableTrigger: [POST,GET] http://localhost:7071/api/orchestrators/{functionName}
31+
```
32+
33+
This indicates that your `DurableTrigger` function can be reached via a `GET` or `POST` request to that URL. `DurableTrigger` starts the function-chaning orchestrator whose name is passed as a parameter to the URL. So, to start the orchestrator, which is named `CheckActivityTypes`, make a GET request to `http://127.0.0.1:7071/api/orchestrators/CheckActivityTypes`.
34+
35+
And that's it! You should see a JSON response with five URLs to monitor the status of the orchestration. To learn more about this, please read [here](TODO)!
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import json
2+
import logging
3+
4+
logger = logging.getLogger('activity')
5+
6+
7+
def main(value: str):
8+
logger.warn(f'ReturnBool is called with {value}')
9+
if value == "1":
10+
return True
11+
else:
12+
return False
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
{
2+
"scriptFile": "__init__.py",
3+
"bindings": [
4+
{
5+
"name": "value",
6+
"type": "activityTrigger",
7+
"direction": "in"
8+
}
9+
],
10+
"disabled": false
11+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import json
2+
import logging
3+
4+
logger = logging.getLogger('activity')
5+
6+
7+
def main(value: str):
8+
logger.warn(f'ReturnBytes is called with {value}')
9+
return value.encode('utf-8')
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
{
2+
"scriptFile": "__init__.py",
3+
"bindings": [
4+
{
5+
"name": "value",
6+
"type": "activityTrigger",
7+
"direction": "in"
8+
}
9+
],
10+
"disabled": false
11+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import json
2+
import logging
3+
4+
logger = logging.getLogger('activity')
5+
6+
7+
def main(value: str):
8+
logger.warn(f'ReturnDictOfString is called with {value}')
9+
result = {}
10+
result[value] = value
11+
return result
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
{
2+
"scriptFile": "__init__.py",
3+
"bindings": [
4+
{
5+
"name": "value",
6+
"type": "activityTrigger",
7+
"direction": "in"
8+
}
9+
],
10+
"disabled": false
11+
}

0 commit comments

Comments
 (0)