diff --git a/nodejs-functions/serverless.yml b/nodejs-functions/serverless.yml index bd918ab..87bb58c 100644 --- a/nodejs-functions/serverless.yml +++ b/nodejs-functions/serverless.yml @@ -19,7 +19,7 @@ provider: custom: globalSchedule: cron(0 0 * * *) plugins: - - serverless-azure-functions + - serverless-azure-functions package: exclude: - local.settings.json diff --git a/python-functions/README.md b/python-functions/README.md index e84c026..20d229b 100644 --- a/python-functions/README.md +++ b/python-functions/README.md @@ -1,3 +1,63 @@ # Azure Functions -Refer to [Serverless docs](https://serverless.com/framework/docs/providers/azure/guide/intro/) for more information. + +# CosmosDB bindings with Serverless Framework: + +To use CosmosDB bindings modify the host.json on your main folder to: +``` yaml +{ + "version": "2.0", + "extensionBundle": { + "id": "Microsoft.Azure.Functions.ExtensionBundle", + "version": "[1.*, 2.0.0)" + } +} + ``` + +## There is two types of CosmosDB bindings: +### "cosmosdbtrigger" + +The Azure Cosmos DB Trigger uses the Azure Cosmos DB Change Feed to listen for inserts and updates across partitions. The change feed publishes inserts and updates, not deletions. + +To set-up this binding in the serverless framework, add this event to the serverless.yml + ``` yaml +events: + - cosmosDB: true + x-azure-settings: + name: documents # name of input parameter in function signature + databaseName: + direction: in + leaseCollectionName: leases + connectionStringSetting: + collectionName: + createLeaseCollectionIfNotExists: true + leaseCollectionPrefix: + ``` + +### "cosmosdb" + +The Azure Cosmos DB output binding lets you write a new document to an Azure Cosmos DB database using the SQL API. +To set-up this binding in the serverless framework, add this event to the serverless.yml + ``` yaml + - cosmosDB: true + x-azure-settings: + direction: out + name: events # name the output in function signature + databaseName: + collectionName: + leaseCollectionName: leases + createLeaseCollectionIfNotExists: true + connectionStringSetting: + createIfNotExists: true # A boolean value to indicate whether the collection is created + ``` +Problems with the CosmosDB bindings and the serverless framework: +If there is only one event with the direction set to out, the serverless framework will change the name of this binding to “$return” this will cause problems because this name needs to be the same as the defined in the function signature, to solve this, instead of defining the name in the function signature like this: +``` py +def main(documents: func.DocumentList, events: func.Out[func.Document]): +``` + +Define the return of the function like this: +``` py +def main(documents: func.DocumentList) -> func.Document: +``` +And return directly the document that you want to add to the database. diff --git a/python-functions/host.json b/python-functions/host.json index d2059a4..d342a8e 100644 --- a/python-functions/host.json +++ b/python-functions/host.json @@ -1,3 +1,7 @@ { - "version": "2.0" + "version": "2.0", + "extensionBundle": { + "id": "Microsoft.Azure.Functions.ExtensionBundle", + "version": "[1.*, 2.0.0)" + } } diff --git a/python-functions/serverless.yml b/python-functions/serverless.yml index 9959d12..7b30628 100644 --- a/python-functions/serverless.yml +++ b/python-functions/serverless.yml @@ -1,4 +1,4 @@ -service: python-functions-test1 +service: python-functions-test1-len frameworkVersion: '2' provider: @@ -6,7 +6,7 @@ provider: region: West US 2 runtime: python3.8 # python3.7 or python3.8 also available os: linux # linux is the only operating system available for python - prefix: time-tracker + prefix: time-tracker-test-lenin environment: # these will be created as application settings COSMOS_DATABASE_URI: ${file(keys.yml):COSMOS_DATABASE_URI} @@ -35,7 +35,7 @@ package: functions: handle_activity_events_trigger: - handler: src/handlers/handle_activity_events_trigger/__init__.py + handler: src/handlers/handle_activity_events_trigger/handle_events_trigger.main events: - cosmosDB: true x-azure-settings: @@ -46,19 +46,19 @@ functions: databaseName: time-tracker-db collectionName: activity createLeaseCollectionIfNotExists: true - leaseCollectionPrefix: activity_ + leaseCollectionPrefix: activity - cosmosDB: true x-azure-settings: connectionStringSetting: COSMOS_DATABASE_URI direction: out - name: events # name of input parameter in function signature + name: $return # name of input parameter in function signature databaseName: time-tracker-db collectionName: event createIfNotExists: true # A boolean value to indicate whether the collection is created createLeaseCollectionIfNotExists: true handle_customer_trigger: - handler: src/handlers/handle_customer_trigger/__init__.py + handler: src/handlers/handle_customer_trigger/handle_events_trigger.main events: - cosmosDB: true x-azure-settings: @@ -68,11 +68,11 @@ functions: databaseName: time-tracker-db collectionName: customer createLeaseCollectionIfNotExists: true - leaseCollectionPrefix: customer_ + leaseCollectionPrefix: customer - cosmosDB: true x-azure-settings: direction: out - name: events # name of input parameter in function signature + name: $return # name of input parameter in function signature databaseName: time-tracker-db collectionName: event leaseCollectionName: leases @@ -81,7 +81,7 @@ functions: createIfNotExists: true # A boolean value to indicate whether the collection is created handle_project_events_trigger: - handler: src/handlers/handle_project_events_trigger/__init__.py + handler: src/handlers/handle_project_events_trigger/handle_events_trigger.main events: - cosmosDB: true x-azure-settings: @@ -92,11 +92,11 @@ functions: databaseName: time-tracker-db collectionName: project createLeaseCollectionIfNotExists: true - leaseCollectionPrefix: project_ + leaseCollectionPrefix: project - cosmosDB: true x-azure-settings: direction: out - name: events # name of input parameter in function signature + name: $return # name of input parameter in function signature databaseName: time-tracker-db collectionName: event leaseCollectionName: leases @@ -105,22 +105,23 @@ functions: createIfNotExists: true # A boolean value to indicate whether the collection is created handle_project_type_events_trigger: - handler: src/handlers/handle_project_type_events_trigger/__init__.py + handler: src/handlers/handle_project_type_events_trigger/handle_events_trigger.main events: - cosmosDB: true - x-azure-settings: - name: documents # name of input parameter in function signature + x-azure-settings: + name: document # name of input parameter in function signature direction: in leaseCollectionName: leases connectionStringSetting: COSMOS_DATABASE_URI databaseName: time-tracker-db collectionName: project_type createLeaseCollectionIfNotExists: true - leaseCollectionPrefix: project_type_ + leaseCollectionPrefix: project_type + - cosmosDB: true x-azure-settings: direction: out - name: events # name of input parameter in function signature + name: $return # name of input parameter in function signature databaseName: time-tracker-db collectionName: event leaseCollectionName: leases @@ -129,25 +130,26 @@ functions: createIfNotExists: true # A boolean value to indicate whether the collection is created handle_time_entry_events_trigger: - handler: src/handlers/handle_time_entry_events_trigger/__init__.py + handler: src/handlers/handle_time_entry_events_trigger/handle_events_trigger.main events: - cosmosDB: true x-azure-settings: name: documents # name of input parameter in function signature + databaseName: time-tracker-db direction: in leaseCollectionName: leases + leaseCollectionPrefix: time_entry connectionStringSetting: COSMOS_DATABASE_URI - databaseName: time-tracker-db collectionName: time_entry createLeaseCollectionIfNotExists: true - leaseCollectionPrefix: time_entry_ + - cosmosDB: true x-azure-settings: direction: out - name: events # name of input parameter in function signature + name: $return # name of input parameter in function signature databaseName: time-tracker-db collectionName: event leaseCollectionName: leases createLeaseCollectionIfNotExists: true connectionStringSetting: COSMOS_DATABASE_URI - createIfNotExists: true # A boolean value to indicate whether the collection is created \ No newline at end of file + createIfNotExists: true # A boolean value to indicate whether the collection is created diff --git a/python-functions/src/handlers/goodbye.py b/python-functions/src/handlers/goodbye.py deleted file mode 100644 index 1fe195c..0000000 --- a/python-functions/src/handlers/goodbye.py +++ /dev/null @@ -1,24 +0,0 @@ -import logging - -import azure.functions as func - - -def main(req: func.HttpRequest) -> func.HttpResponse: - logging.info('Python HTTP trigger function processed a request.') - - name = req.params.get('name') - if not name: - try: - req_body = req.get_json() - except ValueError: - pass - else: - name = req_body.get('name') - - if name: - return func.HttpResponse(f'Goodbye {name}!') - else: - return func.HttpResponse( - "Please pass a name on the query string or in the request body", - status_code=400 - ) diff --git a/python-functions/src/handlers/handle_activity_events_trigger/__init__.py b/python-functions/src/handlers/handle_activity_events_trigger/__init__.py deleted file mode 100644 index d1c6560..0000000 --- a/python-functions/src/handlers/handle_activity_events_trigger/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -import handle_events_trigger - -main = handle_events_trigger.main \ No newline at end of file diff --git a/python-functions/src/handlers/handle_activity_events_trigger/handle_events_trigger.py b/python-functions/src/handlers/handle_activity_events_trigger/handle_events_trigger.py index 63501bf..25ba9c3 100644 --- a/python-functions/src/handlers/handle_activity_events_trigger/handle_events_trigger.py +++ b/python-functions/src/handlers/handle_activity_events_trigger/handle_events_trigger.py @@ -5,7 +5,7 @@ import azure.functions as func -def main(documents: func.DocumentList, events: func.Out[func.Document]): +def main(documents: func.DocumentList) -> func.Document: if documents: new_events = func.DocumentList() @@ -29,6 +29,7 @@ def main(documents: func.DocumentList, events: func.Out[func.Document]): logging.warning("- Not saved!") if len(new_events): - events.set(new_events) + return new_events + else: logging.warning("No valid events were found!") \ No newline at end of file diff --git a/python-functions/src/handlers/handle_customer_trigger/__init__.py b/python-functions/src/handlers/handle_customer_trigger/__init__.py deleted file mode 100644 index d62d6bb..0000000 --- a/python-functions/src/handlers/handle_customer_trigger/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -from handle_events_trigger import main as handler - -main = handler \ No newline at end of file diff --git a/python-functions/src/handlers/handle_customer_trigger/handle_events_trigger.py b/python-functions/src/handlers/handle_customer_trigger/handle_events_trigger.py index 63501bf..25ba9c3 100644 --- a/python-functions/src/handlers/handle_customer_trigger/handle_events_trigger.py +++ b/python-functions/src/handlers/handle_customer_trigger/handle_events_trigger.py @@ -5,7 +5,7 @@ import azure.functions as func -def main(documents: func.DocumentList, events: func.Out[func.Document]): +def main(documents: func.DocumentList) -> func.Document: if documents: new_events = func.DocumentList() @@ -29,6 +29,7 @@ def main(documents: func.DocumentList, events: func.Out[func.Document]): logging.warning("- Not saved!") if len(new_events): - events.set(new_events) + return new_events + else: logging.warning("No valid events were found!") \ No newline at end of file diff --git a/python-functions/src/handlers/handle_project_events_trigger/__init__.py b/python-functions/src/handlers/handle_project_events_trigger/__init__.py deleted file mode 100644 index 55ad97e..0000000 --- a/python-functions/src/handlers/handle_project_events_trigger/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -from handle_events_trigger import main as handler - -main = handler diff --git a/python-functions/src/handlers/handle_project_events_trigger/handle_events_trigger.py b/python-functions/src/handlers/handle_project_events_trigger/handle_events_trigger.py index 63501bf..25ba9c3 100644 --- a/python-functions/src/handlers/handle_project_events_trigger/handle_events_trigger.py +++ b/python-functions/src/handlers/handle_project_events_trigger/handle_events_trigger.py @@ -5,7 +5,7 @@ import azure.functions as func -def main(documents: func.DocumentList, events: func.Out[func.Document]): +def main(documents: func.DocumentList) -> func.Document: if documents: new_events = func.DocumentList() @@ -29,6 +29,7 @@ def main(documents: func.DocumentList, events: func.Out[func.Document]): logging.warning("- Not saved!") if len(new_events): - events.set(new_events) + return new_events + else: logging.warning("No valid events were found!") \ No newline at end of file diff --git a/python-functions/src/handlers/handle_project_type_events_trigger/__init__.py b/python-functions/src/handlers/handle_project_type_events_trigger/__init__.py deleted file mode 100644 index d62d6bb..0000000 --- a/python-functions/src/handlers/handle_project_type_events_trigger/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -from handle_events_trigger import main as handler - -main = handler \ No newline at end of file diff --git a/python-functions/src/handlers/handle_project_type_events_trigger/handle_events_trigger.py b/python-functions/src/handlers/handle_project_type_events_trigger/handle_events_trigger.py index 63501bf..25ba9c3 100644 --- a/python-functions/src/handlers/handle_project_type_events_trigger/handle_events_trigger.py +++ b/python-functions/src/handlers/handle_project_type_events_trigger/handle_events_trigger.py @@ -5,7 +5,7 @@ import azure.functions as func -def main(documents: func.DocumentList, events: func.Out[func.Document]): +def main(documents: func.DocumentList) -> func.Document: if documents: new_events = func.DocumentList() @@ -29,6 +29,7 @@ def main(documents: func.DocumentList, events: func.Out[func.Document]): logging.warning("- Not saved!") if len(new_events): - events.set(new_events) + return new_events + else: logging.warning("No valid events were found!") \ No newline at end of file diff --git a/python-functions/src/handlers/handle_time_entry_events_trigger/__init__.py b/python-functions/src/handlers/handle_time_entry_events_trigger/__init__.py deleted file mode 100644 index 55ad97e..0000000 --- a/python-functions/src/handlers/handle_time_entry_events_trigger/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -from handle_events_trigger import main as handler - -main = handler diff --git a/python-functions/src/handlers/handle_time_entry_events_trigger/handle_events_trigger.py b/python-functions/src/handlers/handle_time_entry_events_trigger/handle_events_trigger.py index 63501bf..64cae6c 100644 --- a/python-functions/src/handlers/handle_time_entry_events_trigger/handle_events_trigger.py +++ b/python-functions/src/handlers/handle_time_entry_events_trigger/handle_events_trigger.py @@ -5,7 +5,7 @@ import azure.functions as func -def main(documents: func.DocumentList, events: func.Out[func.Document]): +def main(documents: func.DocumentList) -> func.Document: if documents: new_events = func.DocumentList() @@ -18,7 +18,7 @@ def main(documents: func.DocumentList, events: func.Out[func.Document]): "id": str(uuid.uuid4()), "date": datetime.utcnow().isoformat(), "user_id": event_context.get("user_id"), - "action": event_context.get("action"), + "action": event_context.get("action") + 'delete_me', "description": event_context.get("description"), "item_id": doc.get("id"), "container_id": event_context.get("container_id"), @@ -29,6 +29,7 @@ def main(documents: func.DocumentList, events: func.Out[func.Document]): logging.warning("- Not saved!") if len(new_events): - events.set(new_events) + return new_events + else: logging.warning("No valid events were found!") \ No newline at end of file diff --git a/python-functions/src/handlers/hello.py b/python-functions/src/handlers/hello.py deleted file mode 100644 index 9d479d9..0000000 --- a/python-functions/src/handlers/hello.py +++ /dev/null @@ -1,24 +0,0 @@ -import logging - -import azure.functions as func - - -def main(req: func.HttpRequest) -> func.HttpResponse: - logging.info('Python HTTP trigger function processed a request.') - - name = req.params.get('name') - if not name: - try: - req_body = req.get_json() - except ValueError: - pass - else: - name = req_body.get('name') - - if name: - return func.HttpResponse(f"Hello {name}!") - else: - return func.HttpResponse( - "Please pass a name on the query string or in the request body", - status_code=400 - ) diff --git a/python-functions/src/handlers/shared_code/handle_events_trigger.py b/python-functions/src/handlers/shared_code/handle_events_trigger.py deleted file mode 100644 index 63501bf..0000000 --- a/python-functions/src/handlers/shared_code/handle_events_trigger.py +++ /dev/null @@ -1,34 +0,0 @@ -import logging -import uuid -from datetime import datetime - -import azure.functions as func - - -def main(documents: func.DocumentList, events: func.Out[func.Document]): - if documents: - new_events = func.DocumentList() - - for doc in documents: - logging.info(doc.to_json()) - - event_context = doc.get("_last_event_ctx") - if event_context is not None: - new_events.append(func.Document.from_dict({ - "id": str(uuid.uuid4()), - "date": datetime.utcnow().isoformat(), - "user_id": event_context.get("user_id"), - "action": event_context.get("action"), - "description": event_context.get("description"), - "item_id": doc.get("id"), - "container_id": event_context.get("container_id"), - "session_id": event_context.get("session_id"), - "tenant_id": event_context.get("tenant_id"), - })) - else: - logging.warning("- Not saved!") - - if len(new_events): - events.set(new_events) - else: - logging.warning("No valid events were found!") \ No newline at end of file