Skip to content

Add activity trigger return type sample #105

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

Merged
merged 3 commits into from
Apr 10, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions samples/activity_trigger_types/.funcignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
.git*
.vscode
local.settings.json
test
.venv
133 changes: 133 additions & 0 deletions samples/activity_trigger_types/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class

# C extensions
*.so

# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
pip-wheel-metadata/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST

# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec

# Installer logs
pip-log.txt
pip-delete-this-directory.txt

# Unit test / coverage reports
htmlcov/
.tox/
.nox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
.hypothesis/
.pytest_cache/

# Translations
*.mo
*.pot

# Django stuff:
*.log
local_settings.py
db.sqlite3

# Flask stuff:
instance/
.webassets-cache

# Scrapy stuff:
.scrapy

# Sphinx documentation
docs/_build/

# PyBuilder
target/

# Jupyter Notebook
.ipynb_checkpoints

# IPython
profile_default/
ipython_config.py

# pyenv
.python-version

# pipenv
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
# However, in case of collaboration, if having platform-specific dependencies or dependencies
# having no cross-platform support, pipenv may install dependencies that don’t work, or not
# install all needed dependencies.
#Pipfile.lock

# celery beat schedule file
celerybeat-schedule

# SageMath parsed files
*.sage.py

# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/

# Spyder project settings
.spyderproject
.spyproject

# Rope project settings
.ropeproject

# mkdocs documentation
/site

# mypy
.mypy_cache/
.dmypy.json
dmypy.json

# Pyre type checker
.pyre/

# Azure Functions artifacts
bin
obj
appsettings.json
local.settings.json
.python_packages

# pycharm
.idea
67 changes: 67 additions & 0 deletions samples/activity_trigger_types/CheckActivityTypes/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import json
import os

import azure.functions as func
import azure.durable_functions as df

def orchestrator_function(context: df.DurableOrchestrationContext):
"""This function provides a sample for activity trigger

Parameters
----------
context: DurableOrchestrationContext
This context has the past history and the durable orchestration API

Returns
-------
message
Returns the result of the activity function return values.

Yields
-------
call_activity: str
Yields, depending on the `json_rule`, to wait on either all
tasks to complete, or until one of the tasks completes.
"""

message = []

ret_bool = yield context.call_activity("ReturnBool", "1")
message.append(f"ret_bool: {ret_bool} {type(ret_bool)}")

# Not supported: return value from activity trigger "bytes" is not json serializable!
# ret_bytes = yield context.call_activity("ReturnBytes", "1b2b3b")
# message.append(f"ret_bytes : {ret_bytes} {type(ret_bytes)}")

ret_dict_of_string = yield context.call_activity("ReturnDictOfString", "kv")
message.append(f"ret_dict_of_string : {ret_dict_of_string} {type(ret_dict_of_string)}")

ret_dict_of_string_anno = yield context.call_activity("ReturnDictOfStringWithAnnotation", "kv_anno")
message.append(f"ret_dict_of_string_anno : {ret_dict_of_string_anno} {type(ret_dict_of_string_anno)}")

ret_float = yield context.call_activity("ReturnFloat", "123.0")
message.append(f"ret_float : {ret_float} {type(ret_float)}")

ret_int = yield context.call_activity("ReturnInt", "123")
message.append(f"ret_int : {ret_int} {type(ret_int)}")

ret_int_from_float = yield context.call_activity("ReturnIntFromFloat", 3.14)
message.append(f"ret_int_from_float : {ret_int_from_float} {type(ret_int_from_float)}")

ret_list_of_float = yield context.call_activity("ReturnListOfFloat", "4.5")
message.append(f"ret_list_of_float : {ret_list_of_float} {type(ret_list_of_float)}")

ret_list_of_float_anno = yield context.call_activity("ReturnListOfFloatWithAnnotation", "5.6")
message.append(f"ret_list_of_float_anno : {ret_list_of_float_anno} {type(ret_list_of_float_anno)}")

# Not supported: return value from activity trigger "set" is not json serializable!
# ret_set_of_int = yield context.call_activity("ReturnSetOfInt", 5)
# message.append(f"ret_set_of_int : {ret_set_of_int} {type(ret_set_of_int)}")

ret_string = yield context.call_activity("ReturnString", "simple_string")
message.append(f"ret_string : {ret_string} {type(ret_string)}")

return message


main = df.Orchestrator.create(orchestrator_function)
11 changes: 11 additions & 0 deletions samples/activity_trigger_types/CheckActivityTypes/function.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"scriptFile": "__init__.py",
"bindings": [
{
"name": "context",
"type": "orchestrationTrigger",
"direction": "in"
}
],
"disabled": false
}
29 changes: 29 additions & 0 deletions samples/activity_trigger_types/DurableTrigger/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import logging

from azure.durable_functions import DurableOrchestrationClient
import azure.functions as func


async def main(req: func.HttpRequest, starter: str, message):
"""This function starts up the orchestrator from an HTTP endpoint

Parameters
----------
req: func.HttpRequest
An HTTP Request object, it can be used to parse URL
parameters.

starter: str
A JSON-formatted string describing the orchestration context

message:
An azure functions http output binding, it enables us to establish
an http response.
"""

function_name = req.route_params.get('functionName')
logging.info(starter)
client = DurableOrchestrationClient(starter)
instance_id = await client.start_new(function_name)
response = client.create_check_status_response(req, instance_id)
message.set(response)
27 changes: 27 additions & 0 deletions samples/activity_trigger_types/DurableTrigger/function.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
{
"scriptFile": "__init__.py",
"bindings": [
{
"authLevel": "anonymous",
"name": "req",
"type": "httpTrigger",
"direction": "in",
"route": "orchestrators/{functionName}",
"methods": [
"post",
"get"
]
},
{
"direction": "out",
"name": "message",
"type": "http"
},
{
"name": "starter",
"type": "orchestrationClient",
"direction": "in",
"datatype": "string"
}
]
}
35 changes: 35 additions & 0 deletions samples/activity_trigger_types/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# Activity-Trigger-Type - Sample

This sample exemplifies how to return values in primitive Python types from Python Durable Functions Activity Trigger.

## Usage Instructions

### Create a `local.settings.json` file in this directory
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).
For this sample, you will only need an `AzureWebJobsStorage` connection string, which you can obtain from the Azure portal.

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:

```json
{
"IsEncrypted": false,
"Values": {
"AzureWebJobsStorage": "<your connection string>",
"FUNCTIONS_WORKER_RUNTIME": "python"
}
}
```

### Run the Sample
To try this sample, run `func host start` in this directory. If all the system requirements have been met, and
after some initialization logs, you should see something like the following:

```bash
Http Functions:

DurableTrigger: [POST,GET] http://localhost:7071/api/orchestrators/{functionName}
```

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`.

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)!
12 changes: 12 additions & 0 deletions samples/activity_trigger_types/ReturnBool/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import json
import logging

logger = logging.getLogger('activity')


def main(value: str):
logger.warn(f'ReturnBool is called with {value}')
if value == "1":
return True
else:
return False
11 changes: 11 additions & 0 deletions samples/activity_trigger_types/ReturnBool/function.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"scriptFile": "__init__.py",
"bindings": [
{
"name": "value",
"type": "activityTrigger",
"direction": "in"
}
],
"disabled": false
}
9 changes: 9 additions & 0 deletions samples/activity_trigger_types/ReturnBytes/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import json
import logging

logger = logging.getLogger('activity')


def main(value: str):
logger.warn(f'ReturnBytes is called with {value}')
return value.encode('utf-8')
11 changes: 11 additions & 0 deletions samples/activity_trigger_types/ReturnBytes/function.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"scriptFile": "__init__.py",
"bindings": [
{
"name": "value",
"type": "activityTrigger",
"direction": "in"
}
],
"disabled": false
}
11 changes: 11 additions & 0 deletions samples/activity_trigger_types/ReturnDictOfString/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import json
import logging

logger = logging.getLogger('activity')


def main(value: str):
logger.warn(f'ReturnDictOfString is called with {value}')
result = {}
result[value] = value
return result
11 changes: 11 additions & 0 deletions samples/activity_trigger_types/ReturnDictOfString/function.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"scriptFile": "__init__.py",
"bindings": [
{
"name": "value",
"type": "activityTrigger",
"direction": "in"
}
],
"disabled": false
}
Loading