├── azure-functions
├── HttpIngressFunc
│ ├── host.json
│ ├── HttpIngressFunc.cs
│ ├── HttpIngressFunc.csproj
│ └── .gitignore
├── ConsumerReceiveFunc
│ ├── host.json
│ ├── ConsumerReceiveFunc.csproj
│ ├── ConsumerReceiveFunc.cs
│ └── .gitignore
├── ConsumerEgressFuncs
│ ├── host.json
│ ├── ConsumerEgressFuncs.csproj
│ ├── ChangeFeedFunc.cs
│ ├── ConsumerEgressFuncs.cs
│ └── .gitignore
├── CosmosDbIngressFunc
│ ├── host.json
│ ├── CosmosDbIngressFunc.csproj
│ ├── CosmosDbIngressFunc.cs
│ └── .gitignore
└── Functions.sln
├── docs
├── Architecture.pptx
├── images
│ └── architecture.png
└── Stockholm Azure Meetup.pdf
├── azure-pipelines.yml
├── load-test
├── indexing-policy.json
├── products.lua
└── generate-load.sh
├── LICENSE
├── nested-arm-templates
├── shared-resources.json
├── consumer-receive.json
├── http-ingress.json
├── consumer-egress.json
└── cosmosdb-ingress.json
├── README.md
├── .gitignore
└── azuredeploy.json
/azure-functions/HttpIngressFunc/host.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "2.0"
3 | }
--------------------------------------------------------------------------------
/azure-functions/ConsumerReceiveFunc/host.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "2.0"
3 | }
--------------------------------------------------------------------------------
/docs/Architecture.pptx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/syedhassaanahmed/azure-event-driven-data-pipeline/HEAD/docs/Architecture.pptx
--------------------------------------------------------------------------------
/docs/images/architecture.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/syedhassaanahmed/azure-event-driven-data-pipeline/HEAD/docs/images/architecture.png
--------------------------------------------------------------------------------
/docs/Stockholm Azure Meetup.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/syedhassaanahmed/azure-event-driven-data-pipeline/HEAD/docs/Stockholm Azure Meetup.pdf
--------------------------------------------------------------------------------
/azure-pipelines.yml:
--------------------------------------------------------------------------------
1 | pool:
2 | vmImage: 'VS2017-Win2016'
3 |
4 | variables:
5 | buildConfiguration: 'Release'
6 |
7 | steps:
8 | - script: dotnet build azure-functions --configuration $(buildConfiguration)
--------------------------------------------------------------------------------
/azure-functions/ConsumerEgressFuncs/host.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "2.0",
3 | "extensions": {
4 | "cosmosDB": {
5 | "connectionMode": "Direct",
6 | "protocol": "Tcp"
7 | }
8 | }
9 | }
--------------------------------------------------------------------------------
/azure-functions/CosmosDbIngressFunc/host.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "2.0",
3 | "logging": {
4 | "applicationInsights": {
5 | "samplingSettings": {
6 | "isEnabled": true,
7 | "maxTelemetryItemsPerSecond": 5
8 | }
9 | }
10 | },
11 | "extensions": {
12 | "cosmosDB": {
13 | "connectionMode": "Direct",
14 | "protocol": "Tcp"
15 | }
16 | }
17 | }
--------------------------------------------------------------------------------
/load-test/indexing-policy.json:
--------------------------------------------------------------------------------
1 | {
2 | "indexingMode": "consistent",
3 | "automatic": true,
4 | "excludedPaths": [
5 | {
6 | "path": "/"
7 | }
8 | ],
9 | "includedPaths": [
10 | {
11 | "path": "/productText/?",
12 | "indexes": [
13 | {
14 | "kind": "Hash",
15 | "dataType": "String",
16 | "precision": -1
17 | }
18 | ]
19 | }
20 | ]
21 | }
--------------------------------------------------------------------------------
/azure-functions/HttpIngressFunc/HttpIngressFunc.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Azure.WebJobs;
2 | using Microsoft.Azure.WebJobs.Extensions.Http;
3 | using Microsoft.Extensions.Logging;
4 |
5 | namespace Functions
6 | {
7 | public static class HttpIngressFunc
8 | {
9 | [FunctionName(nameof(HttpIngressFunc))]
10 | [return: ServiceBus("productsQueue", Connection = "SERVICEBUS_CONNECTION")]
11 | public static string Run([HttpTrigger(AuthorizationLevel.Function, "post")]
12 | dynamic product, ILogger log)
13 | {
14 | return product.ToString();
15 | }
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/azure-functions/ConsumerReceiveFunc/ConsumerReceiveFunc.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 | netcoreapp2.1
4 | v2
5 |
6 |
7 |
8 |
9 |
10 |
11 | PreserveNewest
12 |
13 |
14 | PreserveNewest
15 | Never
16 |
17 |
18 |
--------------------------------------------------------------------------------
/azure-functions/HttpIngressFunc/HttpIngressFunc.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 | netcoreapp2.1
4 | v2
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 | PreserveNewest
13 |
14 |
15 | PreserveNewest
16 | Never
17 |
18 |
19 |
--------------------------------------------------------------------------------
/azure-functions/CosmosDbIngressFunc/CosmosDbIngressFunc.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 | netcoreapp2.1
4 | v2
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 | PreserveNewest
14 |
15 |
16 | PreserveNewest
17 | Never
18 |
19 |
20 |
--------------------------------------------------------------------------------
/azure-functions/ConsumerEgressFuncs/ConsumerEgressFuncs.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 | netcoreapp2.1
4 | v2
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 | PreserveNewest
14 |
15 |
16 | PreserveNewest
17 | Never
18 |
19 |
20 |
--------------------------------------------------------------------------------
/azure-functions/ConsumerReceiveFunc/ConsumerReceiveFunc.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Threading.Tasks;
3 | using Microsoft.AspNetCore.Mvc;
4 | using Microsoft.Azure.WebJobs;
5 | using Microsoft.Azure.WebJobs.Extensions.Http;
6 | using Microsoft.AspNetCore.Http;
7 | using Microsoft.Extensions.Logging;
8 |
9 | namespace ConsumerReceiveFunc
10 | {
11 | public static class ConsumerReceiveFunc
12 | {
13 | [FunctionName(nameof(ConsumerReceiveFunc))]
14 | public static async Task Run(
15 | [HttpTrigger(AuthorizationLevel.Function, "post")] HttpRequest req,
16 | ILogger log)
17 | {
18 | var product = await req.ReadAsStringAsync();
19 |
20 | log.LogInformation(product);
21 |
22 | return new Random().Next(0, 10) < 6
23 | ? (ActionResult)new OkObjectResult("Product received")
24 | : new BadRequestObjectResult("Random error");
25 | }
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2018 Syed Hassaan Ahmed
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/azure-functions/ConsumerEgressFuncs/ChangeFeedFunc.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.Linq;
3 | using System.Threading.Tasks;
4 | using Microsoft.Azure.Documents;
5 | using Microsoft.Azure.WebJobs;
6 | using Microsoft.Extensions.Logging;
7 |
8 | namespace ConsumerEgressFuncs
9 | {
10 | public static class ChangeFeedFunc
11 | {
12 | [FunctionName(nameof(ChangeFeedFunc))]
13 | public static Task Run([CosmosDBTrigger(
14 | databaseName: "masterdata",
15 | collectionName: "product",
16 | ConnectionStringSetting = "COSMOSDB_CONNECTION",
17 | LeaseCollectionName = "leases",
18 | CreateLeaseCollectionIfNotExists = true)]
19 | IReadOnlyList input,
20 | [OrchestrationClient] DurableOrchestrationClient starter,
21 | ILogger log)
22 | {
23 | if (input == null || input.Count <= 0)
24 | return Task.CompletedTask;
25 |
26 | var products = input.Select(x => x.ToString());
27 | return starter.StartNewAsync(nameof(ConsumerEgressFuncs.OrchestrateConsumersFunc), products);
28 | }
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/load-test/products.lua:
--------------------------------------------------------------------------------
1 | wrk.method = "POST"
2 |
3 | -- define random string generator
4 | local charset = {}
5 | -- qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM1234567890
6 | for i = 48, 57 do table.insert(charset, string.char(i)) end
7 | for i = 65, 90 do table.insert(charset, string.char(i)) end
8 | for i = 97, 122 do table.insert(charset, string.char(i)) end
9 | function string.random(length)
10 | math.randomseed(os.time())
11 | if length > 0 then
12 | return string.random(length - 1) .. charset[math.random(1, #charset)]
13 | else
14 | return ""
15 | end
16 | end
17 |
18 | local productCount = 0
19 |
20 | request = function()
21 | local productGroupId = productCount % 2000 -- there are 2k product groups
22 | local productText = string.random(5) .. " Ä Ö Å ä ö å" -- test Swedish chars
23 | local longText = "This is a very very long text intentionally added to exceed One Kilobyte boundary."
24 |
25 | body = string.format([[
26 | {
27 | "id": "product_%s",
28 | "productGroupId": "productGroup_%s",
29 | "productText": "%s",
30 | "productStatusId": 11,
31 | "temperatureMax": -18,
32 | "temperatureMin": -23,
33 | "expiryDate": "19.02.2018 03:56:29",
34 | "VERY_LONG_ATTRIBUTE_1": "%s",
35 | "VERY_LONG_ATTRIBUTE_2": "%s",
36 | "VERY_LONG_ATTRIBUTE_3": "%s",
37 | "VERY_LONG_ATTRIBUTE_4": "%s",
38 | "VERY_LONG_ATTRIBUTE_5": "%s",
39 | "VERY_LONG_ATTRIBUTE_6": "%s",
40 | "VERY_LONG_ATTRIBUTE_7": "%s",
41 | "VERY_LONG_ATTRIBUTE_8": "%s",
42 | "VERY_LONG_ATTRIBUTE_9": "%s",
43 | "VERY_LONG_ATTRIBUTE_10": "%s"
44 | }
45 | ]], productCount, productGroupId, productText,
46 | longText, longText, longText, longText, longText, longText, longText, longText, longText, longText)
47 |
48 | productCount = (productCount + 1) % 100000 -- there are 100k products
49 |
50 | return wrk.format(wrk.method, wrk.path, wrk.headers, body)
51 | end
--------------------------------------------------------------------------------
/azure-functions/CosmosDbIngressFunc/CosmosDbIngressFunc.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Azure.Documents;
2 | using Microsoft.Azure.Documents.Client;
3 | using Microsoft.Azure.WebJobs;
4 | using Microsoft.Extensions.Logging;
5 | using Newtonsoft.Json;
6 | using System;
7 | using System.Threading.Tasks;
8 |
9 | namespace CosmosDbIngressFunc
10 | {
11 | public static class CosmosDbIngressFunc
12 | {
13 | private static readonly DocumentClient DocumentClient = CreateDocumentClient();
14 |
15 | [FunctionName(nameof(CosmosDbIngressFunc))]
16 | public static async Task Run([ServiceBusTrigger("productsQueue", Connection = "SERVICEBUS_CONNECTION")]
17 | string productJson, ILogger log)
18 | {
19 | var product = JsonConvert.DeserializeObject(productJson);
20 | await UpsertProductAsync(product, log);
21 | }
22 |
23 | private static async Task UpsertProductAsync(Document product, ILogger log)
24 | {
25 | var collectionLink = UriFactory.CreateDocumentCollectionUri("masterdata", "product");
26 |
27 | // Explicitly adding partitionKey to the data, gives us the flexibility of modifying it later
28 | product.SetPropertyValue("partitionKey", product.GetPropertyValue("productGroupId"));
29 |
30 | var response = await DocumentClient.UpsertDocumentAsync(collectionLink, product);
31 | log.LogMetric("product_RU", response.RequestCharge);
32 | }
33 |
34 | private static DocumentClient CreateDocumentClient()
35 | {
36 | var endpoint = Environment.GetEnvironmentVariable("COSMOSDB_ENDPOINT", EnvironmentVariableTarget.Process);
37 | var authKey = Environment.GetEnvironmentVariable("COSMOSDB_KEY", EnvironmentVariableTarget.Process);
38 |
39 | return new DocumentClient(new Uri(endpoint), authKey, null, ConsistencyLevel.ConsistentPrefix);
40 | }
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/nested-arm-templates/shared-resources.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://schema.management.azure.com/schemas/2018-05-01/deploymentTemplate.json#",
3 | "contentVersion": "1.0.0.0",
4 | "parameters": {
5 | "cosmosDbAccountName": {
6 | "type": "string"
7 | },
8 | "serviceBusNamespaceName": {
9 | "type": "string"
10 | }
11 | },
12 | "variables": {
13 | "serviceBusQueueName": "productsQueue"
14 | },
15 | "resources": [
16 | {
17 | "name": "[parameters('cosmosDbAccountName')]",
18 | "type": "Microsoft.DocumentDb/databaseAccounts",
19 | "apiVersion": "2016-03-31",
20 | "kind": "GlobalDocumentDB",
21 | "location": "[resourceGroup().location]",
22 | "properties": {
23 | "name": "[parameters('cosmosDbAccountName')]",
24 | "databaseAccountOfferType": "Standard"
25 | }
26 | },
27 | {
28 | "apiVersion": "2017-04-01",
29 | "name": "[parameters('serviceBusNamespaceName')]",
30 | "type": "Microsoft.ServiceBus/Namespaces",
31 | "location": "[resourceGroup().location]",
32 | "sku": {
33 | "name": "Standard"
34 | },
35 | "properties": {},
36 | "resources": [
37 | {
38 | "apiVersion": "2017-04-01",
39 | "name": "[variables('serviceBusQueueName')]",
40 | "type": "Queues",
41 | "dependsOn": [
42 | "[concat('Microsoft.ServiceBus/namespaces/', parameters('serviceBusNamespaceName'))]"
43 | ],
44 | "properties": {
45 | "requiresDuplicateDetection": "false",
46 | "requiresSession": "false",
47 | "enablePartitioning": "true",
48 | "enableExpress": "true"
49 | }
50 | }
51 | ]
52 | }
53 | ]
54 | }
--------------------------------------------------------------------------------
/azure-functions/ConsumerEgressFuncs/ConsumerEgressFuncs.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Azure.WebJobs;
2 | using Microsoft.Extensions.Logging;
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Linq;
6 | using System.Net.Http;
7 | using System.Text;
8 | using System.Threading.Tasks;
9 |
10 | namespace ConsumerEgressFuncs
11 | {
12 | public static class ConsumerEgressFuncs
13 | {
14 | private static readonly HttpClient HttpClient = new HttpClient();
15 |
16 | [FunctionName(nameof(OrchestrateConsumersFunc))]
17 | public static async Task OrchestrateConsumersFunc([OrchestrationTrigger] DurableOrchestrationContext ctx)
18 | {
19 | var changedProducts = ctx.GetInput>();
20 |
21 | var retryOptions = new RetryOptions(firstRetryInterval: TimeSpan.FromSeconds(5),
22 | maxNumberOfAttempts: 3);
23 |
24 | var consumers = Environment.GetEnvironmentVariable("CONSUMERS", EnvironmentVariableTarget.Process)
25 | ?.Split('|');
26 |
27 | var parallelTasks = consumers.Select(x => CallSendToConsumerActivityAsync(ctx, retryOptions, x, changedProducts));
28 |
29 | await Task.WhenAll(parallelTasks);
30 | }
31 |
32 | public static async Task CallSendToConsumerActivityAsync(DurableOrchestrationContext ctx,
33 | RetryOptions retryOptions, string consumerUrl, IEnumerable changedProducts)
34 | {
35 | try
36 | {
37 | await ctx.CallActivityWithRetryAsync(nameof(SendToConsumerFunc), retryOptions, (consumerUrl, changedProducts));
38 | }
39 | catch
40 | {
41 | //TODO: TEMPORARILY MARK THE CONSUMER AS BANNED IN CONSUMER_DB
42 | }
43 | }
44 |
45 | [FunctionName(nameof(SendToConsumerFunc))]
46 | public static async Task SendToConsumerFunc([ActivityTrigger] (string consumerUrl, IEnumerable changedProducts) consumerData,
47 | ILogger log)
48 | {
49 | foreach (var product in consumerData.changedProducts)
50 | {
51 | var content = new StringContent(product, Encoding.UTF8, "application/json");
52 | await HttpClient.PostAsync(consumerData.consumerUrl, content);
53 | }
54 | }
55 | }
56 | }
--------------------------------------------------------------------------------
/load-test/generate-load.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | if [ -z "$1" ]; then echo "RESOURCE_GROUP was not supplied"; exit 1; fi && RESOURCE_GROUP=$1
4 | if [ -z "$2" ]; then echo "CONTAINER_NAME was not supplied"; exit 1; fi && CONTAINER_NAME=$2
5 | if [ -z "$3" ]; then echo "TARGET_URL was not supplied"; exit 1; fi && TARGET_URL=$3
6 |
7 | CONTAINER_EXISTS=$(az container list -g $RESOURCE_GROUP --query "[].contains(name, '$CONTAINER_NAME')" -o tsv)
8 | if [[ "$CONTAINER_EXISTS" = true ]]; then
9 | az container stop -g $RESOURCE_GROUP -n $CONTAINER_NAME
10 | fi
11 |
12 | DATABASE=masterdata
13 | COLLECTION=product
14 | LEASES=leases
15 | COSMOS_DB=$(az cosmosdb list -g $RESOURCE_GROUP --query "[0].name" -o tsv)
16 |
17 | DATABASE_EXISTS=$(az cosmosdb database exists -g $RESOURCE_GROUP -n $COSMOS_DB -d $DATABASE -o tsv)
18 | if [[ "$DATABASE_EXISTS" != true ]]; then
19 | az cosmosdb database create -g $RESOURCE_GROUP -n $COSMOS_DB -d $DATABASE
20 | fi
21 |
22 | # Recreate Cosmos DB leases and products collection with partition key
23 | LEASES_EXISTS=$(az cosmosdb collection exists -g $RESOURCE_GROUP -n $COSMOS_DB -d $DATABASE -c $LEASES -o tsv)
24 | if [[ "$LEASES_EXISTS" = true ]]; then
25 | az cosmosdb collection delete -g $RESOURCE_GROUP -n $COSMOS_DB -d $DATABASE -c $LEASES
26 | fi
27 | az cosmosdb collection create -g $RESOURCE_GROUP -n $COSMOS_DB -d $DATABASE -c $LEASES
28 |
29 | COLLECTION_EXISTS=$(az cosmosdb collection exists -g $RESOURCE_GROUP -n $COSMOS_DB -d $DATABASE -c $COLLECTION -o tsv)
30 | if [[ "$COLLECTION_EXISTS" = true ]]; then
31 | az cosmosdb collection delete -g $RESOURCE_GROUP -n $COSMOS_DB -d $DATABASE -c $COLLECTION
32 | fi
33 | az cosmosdb collection create -g $RESOURCE_GROUP -n $COSMOS_DB -d $DATABASE -c $COLLECTION \
34 | --throughput 25000 --partition-key-path "/partitionKey" --indexing-policy @indexing-policy.json
35 |
36 | SCRIPT_URL=https://raw.githubusercontent.com/syedhassaanahmed/azure-event-driven-data-pipeline/master/load-test/products.lua
37 | WRK_OPTIONS="-t1 -c100 -d2m -R1500 --latency"
38 | WRK_IMAGE=syedhassaanahmed/wrk2-with-online-script
39 |
40 | # Timestamp environment variable is used to trigger an ACI update, otherwise container will remain stopped
41 | az container create -g $RESOURCE_GROUP -n $CONTAINER_NAME --image $WRK_IMAGE \
42 | -l westeurope --restart-policy Never -e \
43 | SCRIPT_URL="$SCRIPT_URL" \
44 | TARGET_URL="$TARGET_URL" \
45 | WRK_OPTIONS="$WRK_OPTIONS" \
46 | WRK_HEADER="content-type: application/json" \
47 | TIMESTAMP="$(date +%s)"
--------------------------------------------------------------------------------
/azure-functions/Functions.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 15
4 | VisualStudioVersion = 15.0.28307.136
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "HttpIngressFunc", "HttpIngressFunc\HttpIngressFunc.csproj", "{68B9D0D7-8A3E-4AAB-B088-F41FCD7CD89E}"
7 | EndProject
8 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CosmosDbIngressFunc", "CosmosDbIngressFunc\CosmosDbIngressFunc.csproj", "{67734AD8-6347-4C50-83E0-A62A965306C8}"
9 | EndProject
10 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ConsumerEgressFuncs", "ConsumerEgressFuncs\ConsumerEgressFuncs.csproj", "{ECE3C9BA-1A26-46EC-B232-BD8AB95CCFBC}"
11 | EndProject
12 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ConsumerReceiveFunc", "ConsumerReceiveFunc\ConsumerReceiveFunc.csproj", "{4C918E19-5F86-4C2F-B621-A96FCECFC5A5}"
13 | EndProject
14 | Global
15 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
16 | Debug|Any CPU = Debug|Any CPU
17 | Release|Any CPU = Release|Any CPU
18 | EndGlobalSection
19 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
20 | {68B9D0D7-8A3E-4AAB-B088-F41FCD7CD89E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
21 | {68B9D0D7-8A3E-4AAB-B088-F41FCD7CD89E}.Debug|Any CPU.Build.0 = Debug|Any CPU
22 | {68B9D0D7-8A3E-4AAB-B088-F41FCD7CD89E}.Release|Any CPU.ActiveCfg = Release|Any CPU
23 | {68B9D0D7-8A3E-4AAB-B088-F41FCD7CD89E}.Release|Any CPU.Build.0 = Release|Any CPU
24 | {67734AD8-6347-4C50-83E0-A62A965306C8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
25 | {67734AD8-6347-4C50-83E0-A62A965306C8}.Debug|Any CPU.Build.0 = Debug|Any CPU
26 | {67734AD8-6347-4C50-83E0-A62A965306C8}.Release|Any CPU.ActiveCfg = Release|Any CPU
27 | {67734AD8-6347-4C50-83E0-A62A965306C8}.Release|Any CPU.Build.0 = Release|Any CPU
28 | {ECE3C9BA-1A26-46EC-B232-BD8AB95CCFBC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
29 | {ECE3C9BA-1A26-46EC-B232-BD8AB95CCFBC}.Debug|Any CPU.Build.0 = Debug|Any CPU
30 | {ECE3C9BA-1A26-46EC-B232-BD8AB95CCFBC}.Release|Any CPU.ActiveCfg = Release|Any CPU
31 | {ECE3C9BA-1A26-46EC-B232-BD8AB95CCFBC}.Release|Any CPU.Build.0 = Release|Any CPU
32 | {4C918E19-5F86-4C2F-B621-A96FCECFC5A5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
33 | {4C918E19-5F86-4C2F-B621-A96FCECFC5A5}.Debug|Any CPU.Build.0 = Debug|Any CPU
34 | {4C918E19-5F86-4C2F-B621-A96FCECFC5A5}.Release|Any CPU.ActiveCfg = Release|Any CPU
35 | {4C918E19-5F86-4C2F-B621-A96FCECFC5A5}.Release|Any CPU.Build.0 = Release|Any CPU
36 | EndGlobalSection
37 | GlobalSection(SolutionProperties) = preSolution
38 | HideSolutionNode = FALSE
39 | EndGlobalSection
40 | GlobalSection(ExtensibilityGlobals) = postSolution
41 | SolutionGuid = {A159435B-CF1A-41E4-9596-8FA491D420CC}
42 | EndGlobalSection
43 | EndGlobal
44 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # azure-event-driven-data-pipeline
2 | [](https://dev.azure.com/syedhassaanahmed/azure-event-driven-data-pipeline/_build/latest?definitionId=9)
3 |
4 | ## Problem
5 | A large retailer with many source systems, wants a single source of truth of their data and be able to send updates to their consumers whenever this data is changed. They want to support an unpredictable load, with a max spike of 1500 req/sec.
6 |
7 | ## Architecture
8 | 
9 |
10 | ## Deployment
11 | [](https://portal.azure.com/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2Fsyedhassaanahmed%2Fazure-event-driven-data-pipeline%2Fmaster%2Fazuredeploy.json)
12 |
13 | The entire deployment can be orchestrated using [ARM template](https://docs.microsoft.com/en-us/azure/azure-resource-manager/resource-manager-create-first-template) `azuredeploy.json`.
14 |
15 | To deploy using [Azure CLI](https://docs.microsoft.com/en-us/cli/azure/install-azure-cli?view=azure-cli-latest);
16 | ```
17 | az group deployment create -g --template-file azuredeploy.json
18 | ```
19 |
20 | Once the deployment is complete, the only **manual step** is to copy `ConsumerReceiveFunc` URL from the Azure portal and paste it multiple times (pipe `|` delimited) in `ConsumerEgressFunc` -> App Settings -> `CONSUMERS`.
21 |
22 | ## Running load tests
23 | We perform the load tests using [Azure Container Instances](https://docs.microsoft.com/en-us/azure/container-instances/container-instances-overview). After creating resources using the above ARM template, run the following load testing script;
24 | ```
25 | ./generate-load.sh https://http-ingress-func.azurewebsites.net/api/HttpIngressFunc?code=
26 | ```
27 |
28 | Here is how to stream logs from the container;
29 | ```
30 | az container attach -g -n
31 | ```
32 |
33 | ## Measuring Cosmos DB RUs using Application Insights
34 | When we upsert into Cosmos DB, we log the [Request Units](https://docs.microsoft.com/en-us/azure/cosmos-db/request-units) consumed in [Application Insights](https://docs.microsoft.com/en-us/azure/application-insights/app-insights-overview). The following [Kusto](https://docs.microsoft.com/en-us/azure/kusto/query/) query renders a timechart of RUs consumed in the last 10 minutes, aggregated on 10 seconds.
35 | ```sql
36 | customMetrics
37 | | where timestamp > ago(10m)
38 | and name == "product_RU"
39 | | summarize avg(value) by bin(timestamp, 10s)
40 | | render timechart
41 | ```
42 |
43 | ## Resources
44 | [Choose between Azure services that deliver messages](https://docs.microsoft.com/en-us/azure/event-grid/compare-messaging-services)
45 |
46 | [Choose between Flow, Logic Apps, Functions, and WebJobs](https://docs.microsoft.com/en-us/azure/azure-functions/functions-compare-logic-apps-ms-flow-webjobs)
47 |
48 | [Durable Functions overview](https://docs.microsoft.com/en-us/azure/azure-functions/durable-functions-overview)
49 |
50 | [Understanding Serverless Cold Start](https://blogs.msdn.microsoft.com/appserviceteam/2018/02/07/understanding-serverless-cold-start/)
51 |
52 | [Azure Function Apps: Performance Considerations](https://blogs.msdn.microsoft.com/amitagarwal/2018/04/03/azure-function-apps-performance-considerations/)
53 |
54 | [Processing 100,000 Events Per Second on Azure Functions](https://blogs.msdn.microsoft.com/appserviceteam/2017/09/19/processing-100000-events-per-second-on-azure-functions/)
55 |
56 | [Choose the right data store](https://docs.microsoft.com/en-us/azure/architecture/guide/technology-choices/data-store-overview)
57 |
58 | [Modeling document data for NoSQL databases](https://docs.microsoft.com/en-us/azure/cosmos-db/modeling-data)
59 |
60 | [A fast, serverless, big data pipeline powered by a single Azure Function](https://azure.microsoft.com/en-us/blog/a-fast-serverless-big-data-pipeline-powered-by-a-single-azure-function/)
61 |
62 | [Load testing with Azure Container Instances and wrk](https://blog.vjrantal.net/2017/08/10/load-testing-with-azure-container-instances-and-wrk/)
63 |
--------------------------------------------------------------------------------
/nested-arm-templates/consumer-receive.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://schema.management.azure.com/schemas/2018-05-01/deploymentTemplate.json#",
3 | "contentVersion": "1.0.0.0",
4 | "parameters": {
5 | "consumerReceiveFunctionName": {
6 | "type": "string"
7 | },
8 | "repoURL": {
9 | "type": "string"
10 | }
11 | },
12 | "variables": {
13 | "consumerReceiveStorageAccountName": "[concat('receiver', uniqueString(resourceGroup().id))]",
14 | "consumerReceiveStorageAccountId": "[resourceId('Microsoft.Storage/storageAccounts', variables('consumerReceiveStorageAccountName'))]",
15 | "consumerReceiveServerFarmId": "[resourceId('Microsoft.Web/serverFarms', parameters('consumerReceiveFunctionName'))]"
16 | },
17 | "resources": [
18 | {
19 | "name": "[variables('consumerReceiveStorageAccountName')]",
20 | "type": "Microsoft.Storage/storageAccounts",
21 | "apiVersion": "2018-07-01",
22 | "location": "[resourceGroup().location]",
23 | "kind": "Storage",
24 | "sku": {
25 | "name": "Standard_LRS"
26 | }
27 | },
28 | {
29 | "name": "[parameters('consumerReceiveFunctionName')]",
30 | "type": "Microsoft.Web/serverFarms",
31 | "apiVersion": "2015-04-01",
32 | "location": "[resourceGroup().location]",
33 | "properties": {
34 | "name": "[parameters('consumerReceiveFunctionName')]",
35 | "computeMode": "Dynamic",
36 | "sku": "Dynamic"
37 | }
38 | },
39 | {
40 | "name": "[parameters('consumerReceiveFunctionName')]",
41 | "type": "Microsoft.Web/sites",
42 | "apiVersion": "2018-02-01",
43 | "location": "[resourceGroup().location]",
44 | "kind": "functionapp",
45 | "dependsOn": [
46 | "[variables('consumerReceiveServerFarmId')]",
47 | "[variables('consumerReceiveStorageAccountId')]"
48 | ],
49 | "resources": [
50 | {
51 | "name": "web",
52 | "type": "sourceControls",
53 | "apiVersion": "2018-02-01",
54 | "dependsOn": [
55 | "[resourceId('Microsoft.Web/Sites', parameters('consumerReceiveFunctionName'))]"
56 | ],
57 | "properties": {
58 | "RepoUrl": "[parameters('repoURL')]",
59 | "branch": "master",
60 | "IsManualIntegration": true
61 | }
62 | }
63 | ],
64 | "properties": {
65 | "serverFarmId": "[variables('consumerReceiveServerFarmId')]",
66 | "siteConfig": {
67 | "appSettings": [
68 | {
69 | "name": "AzureWebJobsDashboard",
70 | "value": "[concat('DefaultEndpointsProtocol=https;AccountName=', variables('consumerReceiveStorageAccountName'), ';AccountKey=', listKeys(variables('consumerReceiveStorageAccountId'),'2018-07-01').keys[0].value)]"
71 | },
72 | {
73 | "name": "AzureWebJobsStorage",
74 | "value": "[concat('DefaultEndpointsProtocol=https;AccountName=', variables('consumerReceiveStorageAccountName'), ';AccountKey=', listKeys(variables('consumerReceiveStorageAccountId'),'2018-07-01').keys[0].value)]"
75 | },
76 | {
77 | "name": "WEBSITE_CONTENTAZUREFILECONNECTIONSTRING",
78 | "value": "[concat('DefaultEndpointsProtocol=https;AccountName=', variables('consumerReceiveStorageAccountName'), ';AccountKey=', listKeys(variables('consumerReceiveStorageAccountId'),'2018-07-01').keys[0].value)]"
79 | },
80 | {
81 | "name": "FUNCTIONS_EXTENSION_VERSION",
82 | "value": "~2"
83 | },
84 | {
85 | "name": "PROJECT",
86 | "value": "azure-functions/ConsumerReceiveFunc/ConsumerReceiveFunc.csproj"
87 | },
88 | {
89 | "name": "WEBSITE_CONTENTSHARE",
90 | "value": "[parameters('consumerReceiveFunctionName')]"
91 | },
92 | {
93 | "name": "SCM_COMMAND_IDLE_TIMEOUT",
94 | "value": "1200"
95 | }
96 | ]
97 | }
98 | }
99 | }
100 | ]
101 | }
--------------------------------------------------------------------------------
/nested-arm-templates/http-ingress.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://schema.management.azure.com/schemas/2018-05-01/deploymentTemplate.json#",
3 | "contentVersion": "1.0.0.0",
4 | "parameters": {
5 | "httpIngressFunctionName": {
6 | "type": "string"
7 | },
8 | "httpIngressSkuName": {
9 | "type": "string"
10 | },
11 | "httpIngressSkuTier": {
12 | "type": "string"
13 | },
14 | "httpIngressSkuCapacity": {
15 | "type": "int"
16 | },
17 | "serviceBusAuth": {
18 | "type": "string"
19 | },
20 | "repoURL": {
21 | "type": "string"
22 | }
23 | },
24 | "variables": {
25 | "httpIngressStorageAccountName": "[concat('http', uniqueString(resourceGroup().id))]",
26 | "httpIngressStorageAccountId": "[resourceId('Microsoft.Storage/storageAccounts', variables('httpIngressStorageAccountName'))]",
27 | "httpIngressServerFarmId": "[resourceId('Microsoft.Web/serverFarms', parameters('httpIngressFunctionName'))]"
28 | },
29 | "resources": [
30 | {
31 | "name": "[variables('httpIngressStorageAccountName')]",
32 | "type": "Microsoft.Storage/storageAccounts",
33 | "apiVersion": "2018-07-01",
34 | "location": "[resourceGroup().location]",
35 | "kind": "Storage",
36 | "sku": {
37 | "name": "Standard_LRS"
38 | }
39 | },
40 | {
41 | "name": "[parameters('httpIngressFunctionName')]",
42 | "type": "Microsoft.Insights/components",
43 | "apiVersion": "2015-05-01",
44 | "kind": "other",
45 | "location": "[resourceGroup().location]",
46 | "properties": {
47 | "ApplicationId": "[parameters('httpIngressFunctionName')]"
48 | }
49 | },
50 | {
51 | "name": "[parameters('httpIngressFunctionName')]",
52 | "type": "Microsoft.Web/serverFarms",
53 | "apiVersion": "2018-02-01",
54 | "location": "[resourceGroup().location]",
55 | "sku": {
56 | "name": "[parameters('httpIngressSkuName')]",
57 | "tier": "[parameters('httpIngressSkuTier')]",
58 | "capacity": "[parameters('httpIngressSkuCapacity')]"
59 | }
60 | },
61 | {
62 | "name": "[parameters('httpIngressFunctionName')]",
63 | "type": "Microsoft.Web/sites",
64 | "apiVersion": "2018-02-01",
65 | "location": "[resourceGroup().location]",
66 | "kind": "functionapp",
67 | "dependsOn": [
68 | "[variables('httpIngressServerFarmId')]",
69 | "[variables('httpIngressStorageAccountId')]",
70 | "[resourceId('microsoft.insights/components', parameters('httpIngressFunctionName'))]"
71 | ],
72 | "resources": [
73 | {
74 | "name": "web",
75 | "type": "sourcecontrols",
76 | "apiVersion": "2018-02-01",
77 | "dependsOn": [
78 | "[resourceId('Microsoft.Web/Sites', parameters('httpIngressFunctionName'))]"
79 | ],
80 | "properties": {
81 | "RepoUrl": "[parameters('repoURL')]",
82 | "branch": "master",
83 | "IsManualIntegration": true
84 | }
85 | }
86 | ],
87 | "properties": {
88 | "name": "[parameters('httpIngressFunctionName')]",
89 | "serverFarmId": "[variables('httpIngressServerFarmId')]",
90 | "hostingEnvironment": "",
91 | "clientAffinityEnabled": false,
92 | "siteConfig": {
93 | "alwaysOn": true,
94 | "appSettings": [
95 | {
96 | "name": "AzureWebJobsStorage",
97 | "value": "[concat('DefaultEndpointsProtocol=https;AccountName=', variables('httpIngressStorageAccountName'), ';AccountKey=', listKeys(variables('httpIngressStorageAccountId'),'2018-07-01').keys[0].value)]"
98 | },
99 | {
100 | "name": "FUNCTIONS_EXTENSION_VERSION",
101 | "value": "~2"
102 | },
103 | {
104 | "name": "AppInsights_InstrumentationKey",
105 | "value": "[reference(concat('microsoft.insights/components/', parameters('httpIngressFunctionName'))).InstrumentationKey]"
106 | },
107 | {
108 | "name": "PROJECT",
109 | "value": "azure-functions/HttpIngressFunc/HttpIngressFunc.csproj"
110 | },
111 | {
112 | "name": "SERVICEBUS_CONNECTION",
113 | "value": "[listkeys(parameters('serviceBusAuth'), '2017-04-01').primaryConnectionString]"
114 | },
115 | {
116 | "name": "SCM_COMMAND_IDLE_TIMEOUT",
117 | "value": "1200"
118 | }
119 | ]
120 | }
121 | }
122 | }
123 | ]
124 | }
--------------------------------------------------------------------------------
/azure-functions/HttpIngressFunc/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 |
4 | # Azure Functions localsettings file
5 | local.settings.json
6 |
7 | # User-specific files
8 | *.suo
9 | *.user
10 | *.userosscache
11 | *.sln.docstates
12 |
13 | # User-specific files (MonoDevelop/Xamarin Studio)
14 | *.userprefs
15 |
16 | # Build results
17 | [Dd]ebug/
18 | [Dd]ebugPublic/
19 | [Rr]elease/
20 | [Rr]eleases/
21 | x64/
22 | x86/
23 | bld/
24 | [Bb]in/
25 | [Oo]bj/
26 | [Ll]og/
27 |
28 | # Visual Studio 2015 cache/options directory
29 | .vs/
30 | # Uncomment if you have tasks that create the project's static files in wwwroot
31 | #wwwroot/
32 |
33 | # MSTest test Results
34 | [Tt]est[Rr]esult*/
35 | [Bb]uild[Ll]og.*
36 |
37 | # NUNIT
38 | *.VisualState.xml
39 | TestResult.xml
40 |
41 | # Build Results of an ATL Project
42 | [Dd]ebugPS/
43 | [Rr]eleasePS/
44 | dlldata.c
45 |
46 | # DNX
47 | project.lock.json
48 | project.fragment.lock.json
49 | artifacts/
50 |
51 | *_i.c
52 | *_p.c
53 | *_i.h
54 | *.ilk
55 | *.meta
56 | *.obj
57 | *.pch
58 | *.pdb
59 | *.pgc
60 | *.pgd
61 | *.rsp
62 | *.sbr
63 | *.tlb
64 | *.tli
65 | *.tlh
66 | *.tmp
67 | *.tmp_proj
68 | *.log
69 | *.vspscc
70 | *.vssscc
71 | .builds
72 | *.pidb
73 | *.svclog
74 | *.scc
75 |
76 | # Chutzpah Test files
77 | _Chutzpah*
78 |
79 | # Visual C++ cache files
80 | ipch/
81 | *.aps
82 | *.ncb
83 | *.opendb
84 | *.opensdf
85 | *.sdf
86 | *.cachefile
87 | *.VC.db
88 | *.VC.VC.opendb
89 |
90 | # Visual Studio profiler
91 | *.psess
92 | *.vsp
93 | *.vspx
94 | *.sap
95 |
96 | # TFS 2012 Local Workspace
97 | $tf/
98 |
99 | # Guidance Automation Toolkit
100 | *.gpState
101 |
102 | # ReSharper is a .NET coding add-in
103 | _ReSharper*/
104 | *.[Rr]e[Ss]harper
105 | *.DotSettings.user
106 |
107 | # JustCode is a .NET coding add-in
108 | .JustCode
109 |
110 | # TeamCity is a build add-in
111 | _TeamCity*
112 |
113 | # DotCover is a Code Coverage Tool
114 | *.dotCover
115 |
116 | # NCrunch
117 | _NCrunch_*
118 | .*crunch*.local.xml
119 | nCrunchTemp_*
120 |
121 | # MightyMoose
122 | *.mm.*
123 | AutoTest.Net/
124 |
125 | # Web workbench (sass)
126 | .sass-cache/
127 |
128 | # Installshield output folder
129 | [Ee]xpress/
130 |
131 | # DocProject is a documentation generator add-in
132 | DocProject/buildhelp/
133 | DocProject/Help/*.HxT
134 | DocProject/Help/*.HxC
135 | DocProject/Help/*.hhc
136 | DocProject/Help/*.hhk
137 | DocProject/Help/*.hhp
138 | DocProject/Help/Html2
139 | DocProject/Help/html
140 |
141 | # Click-Once directory
142 | publish/
143 |
144 | # Publish Web Output
145 | *.[Pp]ublish.xml
146 | *.azurePubxml
147 | # TODO: Comment the next line if you want to checkin your web deploy settings
148 | # but database connection strings (with potential passwords) will be unencrypted
149 | #*.pubxml
150 | *.publishproj
151 |
152 | # Microsoft Azure Web App publish settings. Comment the next line if you want to
153 | # checkin your Azure Web App publish settings, but sensitive information contained
154 | # in these scripts will be unencrypted
155 | PublishScripts/
156 |
157 | # NuGet Packages
158 | *.nupkg
159 | # The packages folder can be ignored because of Package Restore
160 | **/packages/*
161 | # except build/, which is used as an MSBuild target.
162 | !**/packages/build/
163 | # Uncomment if necessary however generally it will be regenerated when needed
164 | #!**/packages/repositories.config
165 | # NuGet v3's project.json files produces more ignoreable files
166 | *.nuget.props
167 | *.nuget.targets
168 |
169 | # Microsoft Azure Build Output
170 | csx/
171 | *.build.csdef
172 |
173 | # Microsoft Azure Emulator
174 | ecf/
175 | rcf/
176 |
177 | # Windows Store app package directories and files
178 | AppPackages/
179 | BundleArtifacts/
180 | Package.StoreAssociation.xml
181 | _pkginfo.txt
182 |
183 | # Visual Studio cache files
184 | # files ending in .cache can be ignored
185 | *.[Cc]ache
186 | # but keep track of directories ending in .cache
187 | !*.[Cc]ache/
188 |
189 | # Others
190 | ClientBin/
191 | ~$*
192 | *~
193 | *.dbmdl
194 | *.dbproj.schemaview
195 | *.jfm
196 | *.pfx
197 | *.publishsettings
198 | node_modules/
199 | orleans.codegen.cs
200 |
201 | # Since there are multiple workflows, uncomment next line to ignore bower_components
202 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
203 | #bower_components/
204 |
205 | # RIA/Silverlight projects
206 | Generated_Code/
207 |
208 | # Backup & report files from converting an old project file
209 | # to a newer Visual Studio version. Backup files are not needed,
210 | # because we have git ;-)
211 | _UpgradeReport_Files/
212 | Backup*/
213 | UpgradeLog*.XML
214 | UpgradeLog*.htm
215 |
216 | # SQL Server files
217 | *.mdf
218 | *.ldf
219 |
220 | # Business Intelligence projects
221 | *.rdl.data
222 | *.bim.layout
223 | *.bim_*.settings
224 |
225 | # Microsoft Fakes
226 | FakesAssemblies/
227 |
228 | # GhostDoc plugin setting file
229 | *.GhostDoc.xml
230 |
231 | # Node.js Tools for Visual Studio
232 | .ntvs_analysis.dat
233 |
234 | # Visual Studio 6 build log
235 | *.plg
236 |
237 | # Visual Studio 6 workspace options file
238 | *.opt
239 |
240 | # Visual Studio LightSwitch build output
241 | **/*.HTMLClient/GeneratedArtifacts
242 | **/*.DesktopClient/GeneratedArtifacts
243 | **/*.DesktopClient/ModelManifest.xml
244 | **/*.Server/GeneratedArtifacts
245 | **/*.Server/ModelManifest.xml
246 | _Pvt_Extensions
247 |
248 | # Paket dependency manager
249 | .paket/paket.exe
250 | paket-files/
251 |
252 | # FAKE - F# Make
253 | .fake/
254 |
255 | # JetBrains Rider
256 | .idea/
257 | *.sln.iml
258 |
259 | # CodeRush
260 | .cr/
261 |
262 | # Python Tools for Visual Studio (PTVS)
263 | __pycache__/
264 | *.pyc
--------------------------------------------------------------------------------
/azure-functions/ConsumerEgressFuncs/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 |
4 | # Azure Functions localsettings file
5 | local.settings.json
6 |
7 | # User-specific files
8 | *.suo
9 | *.user
10 | *.userosscache
11 | *.sln.docstates
12 |
13 | # User-specific files (MonoDevelop/Xamarin Studio)
14 | *.userprefs
15 |
16 | # Build results
17 | [Dd]ebug/
18 | [Dd]ebugPublic/
19 | [Rr]elease/
20 | [Rr]eleases/
21 | x64/
22 | x86/
23 | bld/
24 | [Bb]in/
25 | [Oo]bj/
26 | [Ll]og/
27 |
28 | # Visual Studio 2015 cache/options directory
29 | .vs/
30 | # Uncomment if you have tasks that create the project's static files in wwwroot
31 | #wwwroot/
32 |
33 | # MSTest test Results
34 | [Tt]est[Rr]esult*/
35 | [Bb]uild[Ll]og.*
36 |
37 | # NUNIT
38 | *.VisualState.xml
39 | TestResult.xml
40 |
41 | # Build Results of an ATL Project
42 | [Dd]ebugPS/
43 | [Rr]eleasePS/
44 | dlldata.c
45 |
46 | # DNX
47 | project.lock.json
48 | project.fragment.lock.json
49 | artifacts/
50 |
51 | *_i.c
52 | *_p.c
53 | *_i.h
54 | *.ilk
55 | *.meta
56 | *.obj
57 | *.pch
58 | *.pdb
59 | *.pgc
60 | *.pgd
61 | *.rsp
62 | *.sbr
63 | *.tlb
64 | *.tli
65 | *.tlh
66 | *.tmp
67 | *.tmp_proj
68 | *.log
69 | *.vspscc
70 | *.vssscc
71 | .builds
72 | *.pidb
73 | *.svclog
74 | *.scc
75 |
76 | # Chutzpah Test files
77 | _Chutzpah*
78 |
79 | # Visual C++ cache files
80 | ipch/
81 | *.aps
82 | *.ncb
83 | *.opendb
84 | *.opensdf
85 | *.sdf
86 | *.cachefile
87 | *.VC.db
88 | *.VC.VC.opendb
89 |
90 | # Visual Studio profiler
91 | *.psess
92 | *.vsp
93 | *.vspx
94 | *.sap
95 |
96 | # TFS 2012 Local Workspace
97 | $tf/
98 |
99 | # Guidance Automation Toolkit
100 | *.gpState
101 |
102 | # ReSharper is a .NET coding add-in
103 | _ReSharper*/
104 | *.[Rr]e[Ss]harper
105 | *.DotSettings.user
106 |
107 | # JustCode is a .NET coding add-in
108 | .JustCode
109 |
110 | # TeamCity is a build add-in
111 | _TeamCity*
112 |
113 | # DotCover is a Code Coverage Tool
114 | *.dotCover
115 |
116 | # NCrunch
117 | _NCrunch_*
118 | .*crunch*.local.xml
119 | nCrunchTemp_*
120 |
121 | # MightyMoose
122 | *.mm.*
123 | AutoTest.Net/
124 |
125 | # Web workbench (sass)
126 | .sass-cache/
127 |
128 | # Installshield output folder
129 | [Ee]xpress/
130 |
131 | # DocProject is a documentation generator add-in
132 | DocProject/buildhelp/
133 | DocProject/Help/*.HxT
134 | DocProject/Help/*.HxC
135 | DocProject/Help/*.hhc
136 | DocProject/Help/*.hhk
137 | DocProject/Help/*.hhp
138 | DocProject/Help/Html2
139 | DocProject/Help/html
140 |
141 | # Click-Once directory
142 | publish/
143 |
144 | # Publish Web Output
145 | *.[Pp]ublish.xml
146 | *.azurePubxml
147 | # TODO: Comment the next line if you want to checkin your web deploy settings
148 | # but database connection strings (with potential passwords) will be unencrypted
149 | #*.pubxml
150 | *.publishproj
151 |
152 | # Microsoft Azure Web App publish settings. Comment the next line if you want to
153 | # checkin your Azure Web App publish settings, but sensitive information contained
154 | # in these scripts will be unencrypted
155 | PublishScripts/
156 |
157 | # NuGet Packages
158 | *.nupkg
159 | # The packages folder can be ignored because of Package Restore
160 | **/packages/*
161 | # except build/, which is used as an MSBuild target.
162 | !**/packages/build/
163 | # Uncomment if necessary however generally it will be regenerated when needed
164 | #!**/packages/repositories.config
165 | # NuGet v3's project.json files produces more ignoreable files
166 | *.nuget.props
167 | *.nuget.targets
168 |
169 | # Microsoft Azure Build Output
170 | csx/
171 | *.build.csdef
172 |
173 | # Microsoft Azure Emulator
174 | ecf/
175 | rcf/
176 |
177 | # Windows Store app package directories and files
178 | AppPackages/
179 | BundleArtifacts/
180 | Package.StoreAssociation.xml
181 | _pkginfo.txt
182 |
183 | # Visual Studio cache files
184 | # files ending in .cache can be ignored
185 | *.[Cc]ache
186 | # but keep track of directories ending in .cache
187 | !*.[Cc]ache/
188 |
189 | # Others
190 | ClientBin/
191 | ~$*
192 | *~
193 | *.dbmdl
194 | *.dbproj.schemaview
195 | *.jfm
196 | *.pfx
197 | *.publishsettings
198 | node_modules/
199 | orleans.codegen.cs
200 |
201 | # Since there are multiple workflows, uncomment next line to ignore bower_components
202 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
203 | #bower_components/
204 |
205 | # RIA/Silverlight projects
206 | Generated_Code/
207 |
208 | # Backup & report files from converting an old project file
209 | # to a newer Visual Studio version. Backup files are not needed,
210 | # because we have git ;-)
211 | _UpgradeReport_Files/
212 | Backup*/
213 | UpgradeLog*.XML
214 | UpgradeLog*.htm
215 |
216 | # SQL Server files
217 | *.mdf
218 | *.ldf
219 |
220 | # Business Intelligence projects
221 | *.rdl.data
222 | *.bim.layout
223 | *.bim_*.settings
224 |
225 | # Microsoft Fakes
226 | FakesAssemblies/
227 |
228 | # GhostDoc plugin setting file
229 | *.GhostDoc.xml
230 |
231 | # Node.js Tools for Visual Studio
232 | .ntvs_analysis.dat
233 |
234 | # Visual Studio 6 build log
235 | *.plg
236 |
237 | # Visual Studio 6 workspace options file
238 | *.opt
239 |
240 | # Visual Studio LightSwitch build output
241 | **/*.HTMLClient/GeneratedArtifacts
242 | **/*.DesktopClient/GeneratedArtifacts
243 | **/*.DesktopClient/ModelManifest.xml
244 | **/*.Server/GeneratedArtifacts
245 | **/*.Server/ModelManifest.xml
246 | _Pvt_Extensions
247 |
248 | # Paket dependency manager
249 | .paket/paket.exe
250 | paket-files/
251 |
252 | # FAKE - F# Make
253 | .fake/
254 |
255 | # JetBrains Rider
256 | .idea/
257 | *.sln.iml
258 |
259 | # CodeRush
260 | .cr/
261 |
262 | # Python Tools for Visual Studio (PTVS)
263 | __pycache__/
264 | *.pyc
--------------------------------------------------------------------------------
/azure-functions/ConsumerReceiveFunc/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 |
4 | # Azure Functions localsettings file
5 | local.settings.json
6 |
7 | # User-specific files
8 | *.suo
9 | *.user
10 | *.userosscache
11 | *.sln.docstates
12 |
13 | # User-specific files (MonoDevelop/Xamarin Studio)
14 | *.userprefs
15 |
16 | # Build results
17 | [Dd]ebug/
18 | [Dd]ebugPublic/
19 | [Rr]elease/
20 | [Rr]eleases/
21 | x64/
22 | x86/
23 | bld/
24 | [Bb]in/
25 | [Oo]bj/
26 | [Ll]og/
27 |
28 | # Visual Studio 2015 cache/options directory
29 | .vs/
30 | # Uncomment if you have tasks that create the project's static files in wwwroot
31 | #wwwroot/
32 |
33 | # MSTest test Results
34 | [Tt]est[Rr]esult*/
35 | [Bb]uild[Ll]og.*
36 |
37 | # NUNIT
38 | *.VisualState.xml
39 | TestResult.xml
40 |
41 | # Build Results of an ATL Project
42 | [Dd]ebugPS/
43 | [Rr]eleasePS/
44 | dlldata.c
45 |
46 | # DNX
47 | project.lock.json
48 | project.fragment.lock.json
49 | artifacts/
50 |
51 | *_i.c
52 | *_p.c
53 | *_i.h
54 | *.ilk
55 | *.meta
56 | *.obj
57 | *.pch
58 | *.pdb
59 | *.pgc
60 | *.pgd
61 | *.rsp
62 | *.sbr
63 | *.tlb
64 | *.tli
65 | *.tlh
66 | *.tmp
67 | *.tmp_proj
68 | *.log
69 | *.vspscc
70 | *.vssscc
71 | .builds
72 | *.pidb
73 | *.svclog
74 | *.scc
75 |
76 | # Chutzpah Test files
77 | _Chutzpah*
78 |
79 | # Visual C++ cache files
80 | ipch/
81 | *.aps
82 | *.ncb
83 | *.opendb
84 | *.opensdf
85 | *.sdf
86 | *.cachefile
87 | *.VC.db
88 | *.VC.VC.opendb
89 |
90 | # Visual Studio profiler
91 | *.psess
92 | *.vsp
93 | *.vspx
94 | *.sap
95 |
96 | # TFS 2012 Local Workspace
97 | $tf/
98 |
99 | # Guidance Automation Toolkit
100 | *.gpState
101 |
102 | # ReSharper is a .NET coding add-in
103 | _ReSharper*/
104 | *.[Rr]e[Ss]harper
105 | *.DotSettings.user
106 |
107 | # JustCode is a .NET coding add-in
108 | .JustCode
109 |
110 | # TeamCity is a build add-in
111 | _TeamCity*
112 |
113 | # DotCover is a Code Coverage Tool
114 | *.dotCover
115 |
116 | # NCrunch
117 | _NCrunch_*
118 | .*crunch*.local.xml
119 | nCrunchTemp_*
120 |
121 | # MightyMoose
122 | *.mm.*
123 | AutoTest.Net/
124 |
125 | # Web workbench (sass)
126 | .sass-cache/
127 |
128 | # Installshield output folder
129 | [Ee]xpress/
130 |
131 | # DocProject is a documentation generator add-in
132 | DocProject/buildhelp/
133 | DocProject/Help/*.HxT
134 | DocProject/Help/*.HxC
135 | DocProject/Help/*.hhc
136 | DocProject/Help/*.hhk
137 | DocProject/Help/*.hhp
138 | DocProject/Help/Html2
139 | DocProject/Help/html
140 |
141 | # Click-Once directory
142 | publish/
143 |
144 | # Publish Web Output
145 | *.[Pp]ublish.xml
146 | *.azurePubxml
147 | # TODO: Comment the next line if you want to checkin your web deploy settings
148 | # but database connection strings (with potential passwords) will be unencrypted
149 | #*.pubxml
150 | *.publishproj
151 |
152 | # Microsoft Azure Web App publish settings. Comment the next line if you want to
153 | # checkin your Azure Web App publish settings, but sensitive information contained
154 | # in these scripts will be unencrypted
155 | PublishScripts/
156 |
157 | # NuGet Packages
158 | *.nupkg
159 | # The packages folder can be ignored because of Package Restore
160 | **/packages/*
161 | # except build/, which is used as an MSBuild target.
162 | !**/packages/build/
163 | # Uncomment if necessary however generally it will be regenerated when needed
164 | #!**/packages/repositories.config
165 | # NuGet v3's project.json files produces more ignoreable files
166 | *.nuget.props
167 | *.nuget.targets
168 |
169 | # Microsoft Azure Build Output
170 | csx/
171 | *.build.csdef
172 |
173 | # Microsoft Azure Emulator
174 | ecf/
175 | rcf/
176 |
177 | # Windows Store app package directories and files
178 | AppPackages/
179 | BundleArtifacts/
180 | Package.StoreAssociation.xml
181 | _pkginfo.txt
182 |
183 | # Visual Studio cache files
184 | # files ending in .cache can be ignored
185 | *.[Cc]ache
186 | # but keep track of directories ending in .cache
187 | !*.[Cc]ache/
188 |
189 | # Others
190 | ClientBin/
191 | ~$*
192 | *~
193 | *.dbmdl
194 | *.dbproj.schemaview
195 | *.jfm
196 | *.pfx
197 | *.publishsettings
198 | node_modules/
199 | orleans.codegen.cs
200 |
201 | # Since there are multiple workflows, uncomment next line to ignore bower_components
202 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
203 | #bower_components/
204 |
205 | # RIA/Silverlight projects
206 | Generated_Code/
207 |
208 | # Backup & report files from converting an old project file
209 | # to a newer Visual Studio version. Backup files are not needed,
210 | # because we have git ;-)
211 | _UpgradeReport_Files/
212 | Backup*/
213 | UpgradeLog*.XML
214 | UpgradeLog*.htm
215 |
216 | # SQL Server files
217 | *.mdf
218 | *.ldf
219 |
220 | # Business Intelligence projects
221 | *.rdl.data
222 | *.bim.layout
223 | *.bim_*.settings
224 |
225 | # Microsoft Fakes
226 | FakesAssemblies/
227 |
228 | # GhostDoc plugin setting file
229 | *.GhostDoc.xml
230 |
231 | # Node.js Tools for Visual Studio
232 | .ntvs_analysis.dat
233 |
234 | # Visual Studio 6 build log
235 | *.plg
236 |
237 | # Visual Studio 6 workspace options file
238 | *.opt
239 |
240 | # Visual Studio LightSwitch build output
241 | **/*.HTMLClient/GeneratedArtifacts
242 | **/*.DesktopClient/GeneratedArtifacts
243 | **/*.DesktopClient/ModelManifest.xml
244 | **/*.Server/GeneratedArtifacts
245 | **/*.Server/ModelManifest.xml
246 | _Pvt_Extensions
247 |
248 | # Paket dependency manager
249 | .paket/paket.exe
250 | paket-files/
251 |
252 | # FAKE - F# Make
253 | .fake/
254 |
255 | # JetBrains Rider
256 | .idea/
257 | *.sln.iml
258 |
259 | # CodeRush
260 | .cr/
261 |
262 | # Python Tools for Visual Studio (PTVS)
263 | __pycache__/
264 | *.pyc
--------------------------------------------------------------------------------
/azure-functions/CosmosDbIngressFunc/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 |
4 | # Azure Functions localsettings file
5 | local.settings.json
6 |
7 | # User-specific files
8 | *.suo
9 | *.user
10 | *.userosscache
11 | *.sln.docstates
12 |
13 | # User-specific files (MonoDevelop/Xamarin Studio)
14 | *.userprefs
15 |
16 | # Build results
17 | [Dd]ebug/
18 | [Dd]ebugPublic/
19 | [Rr]elease/
20 | [Rr]eleases/
21 | x64/
22 | x86/
23 | bld/
24 | [Bb]in/
25 | [Oo]bj/
26 | [Ll]og/
27 |
28 | # Visual Studio 2015 cache/options directory
29 | .vs/
30 | # Uncomment if you have tasks that create the project's static files in wwwroot
31 | #wwwroot/
32 |
33 | # MSTest test Results
34 | [Tt]est[Rr]esult*/
35 | [Bb]uild[Ll]og.*
36 |
37 | # NUNIT
38 | *.VisualState.xml
39 | TestResult.xml
40 |
41 | # Build Results of an ATL Project
42 | [Dd]ebugPS/
43 | [Rr]eleasePS/
44 | dlldata.c
45 |
46 | # DNX
47 | project.lock.json
48 | project.fragment.lock.json
49 | artifacts/
50 |
51 | *_i.c
52 | *_p.c
53 | *_i.h
54 | *.ilk
55 | *.meta
56 | *.obj
57 | *.pch
58 | *.pdb
59 | *.pgc
60 | *.pgd
61 | *.rsp
62 | *.sbr
63 | *.tlb
64 | *.tli
65 | *.tlh
66 | *.tmp
67 | *.tmp_proj
68 | *.log
69 | *.vspscc
70 | *.vssscc
71 | .builds
72 | *.pidb
73 | *.svclog
74 | *.scc
75 |
76 | # Chutzpah Test files
77 | _Chutzpah*
78 |
79 | # Visual C++ cache files
80 | ipch/
81 | *.aps
82 | *.ncb
83 | *.opendb
84 | *.opensdf
85 | *.sdf
86 | *.cachefile
87 | *.VC.db
88 | *.VC.VC.opendb
89 |
90 | # Visual Studio profiler
91 | *.psess
92 | *.vsp
93 | *.vspx
94 | *.sap
95 |
96 | # TFS 2012 Local Workspace
97 | $tf/
98 |
99 | # Guidance Automation Toolkit
100 | *.gpState
101 |
102 | # ReSharper is a .NET coding add-in
103 | _ReSharper*/
104 | *.[Rr]e[Ss]harper
105 | *.DotSettings.user
106 |
107 | # JustCode is a .NET coding add-in
108 | .JustCode
109 |
110 | # TeamCity is a build add-in
111 | _TeamCity*
112 |
113 | # DotCover is a Code Coverage Tool
114 | *.dotCover
115 |
116 | # NCrunch
117 | _NCrunch_*
118 | .*crunch*.local.xml
119 | nCrunchTemp_*
120 |
121 | # MightyMoose
122 | *.mm.*
123 | AutoTest.Net/
124 |
125 | # Web workbench (sass)
126 | .sass-cache/
127 |
128 | # Installshield output folder
129 | [Ee]xpress/
130 |
131 | # DocProject is a documentation generator add-in
132 | DocProject/buildhelp/
133 | DocProject/Help/*.HxT
134 | DocProject/Help/*.HxC
135 | DocProject/Help/*.hhc
136 | DocProject/Help/*.hhk
137 | DocProject/Help/*.hhp
138 | DocProject/Help/Html2
139 | DocProject/Help/html
140 |
141 | # Click-Once directory
142 | publish/
143 |
144 | # Publish Web Output
145 | *.[Pp]ublish.xml
146 | *.azurePubxml
147 | # TODO: Comment the next line if you want to checkin your web deploy settings
148 | # but database connection strings (with potential passwords) will be unencrypted
149 | #*.pubxml
150 | *.publishproj
151 |
152 | # Microsoft Azure Web App publish settings. Comment the next line if you want to
153 | # checkin your Azure Web App publish settings, but sensitive information contained
154 | # in these scripts will be unencrypted
155 | PublishScripts/
156 |
157 | # NuGet Packages
158 | *.nupkg
159 | # The packages folder can be ignored because of Package Restore
160 | **/packages/*
161 | # except build/, which is used as an MSBuild target.
162 | !**/packages/build/
163 | # Uncomment if necessary however generally it will be regenerated when needed
164 | #!**/packages/repositories.config
165 | # NuGet v3's project.json files produces more ignoreable files
166 | *.nuget.props
167 | *.nuget.targets
168 |
169 | # Microsoft Azure Build Output
170 | csx/
171 | *.build.csdef
172 |
173 | # Microsoft Azure Emulator
174 | ecf/
175 | rcf/
176 |
177 | # Windows Store app package directories and files
178 | AppPackages/
179 | BundleArtifacts/
180 | Package.StoreAssociation.xml
181 | _pkginfo.txt
182 |
183 | # Visual Studio cache files
184 | # files ending in .cache can be ignored
185 | *.[Cc]ache
186 | # but keep track of directories ending in .cache
187 | !*.[Cc]ache/
188 |
189 | # Others
190 | ClientBin/
191 | ~$*
192 | *~
193 | *.dbmdl
194 | *.dbproj.schemaview
195 | *.jfm
196 | *.pfx
197 | *.publishsettings
198 | node_modules/
199 | orleans.codegen.cs
200 |
201 | # Since there are multiple workflows, uncomment next line to ignore bower_components
202 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
203 | #bower_components/
204 |
205 | # RIA/Silverlight projects
206 | Generated_Code/
207 |
208 | # Backup & report files from converting an old project file
209 | # to a newer Visual Studio version. Backup files are not needed,
210 | # because we have git ;-)
211 | _UpgradeReport_Files/
212 | Backup*/
213 | UpgradeLog*.XML
214 | UpgradeLog*.htm
215 |
216 | # SQL Server files
217 | *.mdf
218 | *.ldf
219 |
220 | # Business Intelligence projects
221 | *.rdl.data
222 | *.bim.layout
223 | *.bim_*.settings
224 |
225 | # Microsoft Fakes
226 | FakesAssemblies/
227 |
228 | # GhostDoc plugin setting file
229 | *.GhostDoc.xml
230 |
231 | # Node.js Tools for Visual Studio
232 | .ntvs_analysis.dat
233 |
234 | # Visual Studio 6 build log
235 | *.plg
236 |
237 | # Visual Studio 6 workspace options file
238 | *.opt
239 |
240 | # Visual Studio LightSwitch build output
241 | **/*.HTMLClient/GeneratedArtifacts
242 | **/*.DesktopClient/GeneratedArtifacts
243 | **/*.DesktopClient/ModelManifest.xml
244 | **/*.Server/GeneratedArtifacts
245 | **/*.Server/ModelManifest.xml
246 | _Pvt_Extensions
247 |
248 | # Paket dependency manager
249 | .paket/paket.exe
250 | paket-files/
251 |
252 | # FAKE - F# Make
253 | .fake/
254 |
255 | # JetBrains Rider
256 | .idea/
257 | *.sln.iml
258 |
259 | # CodeRush
260 | .cr/
261 |
262 | # Python Tools for Visual Studio (PTVS)
263 | __pycache__/
264 | *.pyc
--------------------------------------------------------------------------------
/nested-arm-templates/consumer-egress.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://schema.management.azure.com/schemas/2018-05-01/deploymentTemplate.json#",
3 | "contentVersion": "1.0.0.0",
4 | "parameters": {
5 | "consumerEgressFunctionName": {
6 | "type": "string"
7 | },
8 | "cosmosDbEndpoint": {
9 | "type": "string"
10 | },
11 | "cosmosDbId": {
12 | "type": "string"
13 | },
14 | "repoURL": {
15 | "type": "string"
16 | }
17 | },
18 | "variables": {
19 | "consumerEgressStorageAccountName": "[concat('consumer', uniqueString(resourceGroup().id))]",
20 | "consumerEgressStorageAccountId": "[resourceId('Microsoft.Storage/storageAccounts', variables('consumerEgressStorageAccountName'))]",
21 | "consumerEgressServerFarmId": "[resourceId('Microsoft.Web/serverFarms', parameters('consumerEgressFunctionName'))]"
22 | },
23 | "resources": [
24 | {
25 | "name": "[variables('consumerEgressStorageAccountName')]",
26 | "type": "Microsoft.Storage/storageAccounts",
27 | "apiVersion": "2018-07-01",
28 | "location": "[resourceGroup().location]",
29 | "kind": "Storage",
30 | "sku": {
31 | "name": "Standard_LRS"
32 | }
33 | },
34 | {
35 | "name": "[parameters('consumerEgressFunctionName')]",
36 | "type": "Microsoft.Insights/components",
37 | "apiVersion": "2015-05-01",
38 | "kind": "other",
39 | "location": "[resourceGroup().location]",
40 | "properties": {
41 | "ApplicationId": "[parameters('consumerEgressFunctionName')]"
42 | }
43 | },
44 | {
45 | "name": "[parameters('consumerEgressFunctionName')]",
46 | "type": "Microsoft.Web/serverFarms",
47 | "apiVersion": "2015-04-01",
48 | "location": "[resourceGroup().location]",
49 | "properties": {
50 | "name": "[parameters('consumerEgressFunctionName')]",
51 | "computeMode": "Dynamic",
52 | "sku": "Dynamic"
53 | }
54 | },
55 | {
56 | "name": "[parameters('consumerEgressFunctionName')]",
57 | "type": "Microsoft.Web/sites",
58 | "apiVersion": "2018-02-01",
59 | "location": "[resourceGroup().location]",
60 | "kind": "functionapp",
61 | "dependsOn": [
62 | "[variables('consumerEgressServerFarmId')]",
63 | "[variables('consumerEgressStorageAccountId')]",
64 | "[resourceId('microsoft.insights/components', parameters('consumerEgressFunctionName'))]"
65 | ],
66 | "resources": [
67 | {
68 | "name": "web",
69 | "type": "sourceControls",
70 | "apiVersion": "2018-02-01",
71 | "dependsOn": [
72 | "[resourceId('Microsoft.Web/Sites', parameters('consumerEgressFunctionName'))]"
73 | ],
74 | "properties": {
75 | "RepoUrl": "[parameters('repoURL')]",
76 | "branch": "master",
77 | "IsManualIntegration": true
78 | }
79 | }
80 | ],
81 | "properties": {
82 | "serverFarmId": "[variables('consumerEgressServerFarmId')]",
83 | "siteConfig": {
84 | "appSettings": [
85 | {
86 | "name": "AzureWebJobsStorage",
87 | "value": "[concat('DefaultEndpointsProtocol=https;AccountName=', variables('consumerEgressStorageAccountName'), ';AccountKey=', listKeys(variables('consumerEgressStorageAccountId'),'2018-07-01').keys[0].value)]"
88 | },
89 | {
90 | "name": "WEBSITE_CONTENTAZUREFILECONNECTIONSTRING",
91 | "value": "[concat('DefaultEndpointsProtocol=https;AccountName=', variables('consumerEgressStorageAccountName'), ';AccountKey=', listKeys(variables('consumerEgressStorageAccountId'),'2018-07-01').keys[0].value)]"
92 | },
93 | {
94 | "name": "FUNCTIONS_EXTENSION_VERSION",
95 | "value": "~2"
96 | },
97 | {
98 | "name": "AppInsights_InstrumentationKey",
99 | "value": "[reference(concat('microsoft.insights/components/', parameters('consumerEgressFunctionName'))).InstrumentationKey]"
100 | },
101 | {
102 | "name": "PROJECT",
103 | "value": "azure-functions/ConsumerEgressFuncs/ConsumerEgressFuncs.csproj"
104 | },
105 | {
106 | "name": "COSMOSDB_CONNECTION",
107 | "value": "[concat('AccountEndpoint=', parameters('cosmosDbEndpoint'), ';AccountKey=', listKeys(parameters('cosmosDbId'), '2016-03-31').primaryMasterKey, ';')]"
108 | },
109 | {
110 | "name": "WEBSITE_CONTENTSHARE",
111 | "value": "[parameters('consumerEgressFunctionName')]"
112 | },
113 | {
114 | "name": "SCM_COMMAND_IDLE_TIMEOUT",
115 | "value": "1200"
116 | },
117 | {
118 | "name": "CONSUMERS",
119 | "value": ""
120 | }
121 | ]
122 | }
123 | }
124 | }
125 | ]
126 | }
--------------------------------------------------------------------------------
/nested-arm-templates/cosmosdb-ingress.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://schema.management.azure.com/schemas/2018-05-01/deploymentTemplate.json#",
3 | "contentVersion": "1.0.0.0",
4 | "parameters": {
5 | "cosmosDbIngressFunctionName": {
6 | "type": "string"
7 | },
8 | "cosmosDbEndpoint": {
9 | "type": "string"
10 | },
11 | "cosmosDbId": {
12 | "type": "string"
13 | },
14 | "serviceBusAuth": {
15 | "type": "string"
16 | },
17 | "repoURL": {
18 | "type": "string"
19 | }
20 | },
21 | "variables": {
22 | "cosmosDbIngressStorageAccountName": "[concat('cosmosdb', uniqueString(resourceGroup().id))]",
23 | "cosmosDbIngressStorageAccountId": "[resourceId('Microsoft.Storage/storageAccounts', variables('cosmosDbIngressStorageAccountName'))]",
24 | "cosmosDbIngressServerFarmId": "[resourceId('Microsoft.Web/serverFarms', parameters('cosmosDbIngressFunctionName'))]"
25 | },
26 | "resources": [
27 | {
28 | "name": "[variables('cosmosDbIngressStorageAccountName')]",
29 | "type": "Microsoft.Storage/storageAccounts",
30 | "apiVersion": "2018-07-01",
31 | "location": "[resourceGroup().location]",
32 | "kind": "Storage",
33 | "sku": {
34 | "name": "Standard_LRS"
35 | }
36 | },
37 | {
38 | "name": "[parameters('cosmosDbIngressFunctionName')]",
39 | "type": "Microsoft.Insights/components",
40 | "apiVersion": "2015-05-01",
41 | "kind": "other",
42 | "location": "[resourceGroup().location]",
43 | "properties": {
44 | "ApplicationId": "[parameters('cosmosDbIngressFunctionName')]"
45 | }
46 | },
47 | {
48 | "name": "[parameters('cosmosDbIngressFunctionName')]",
49 | "type": "Microsoft.Web/serverFarms",
50 | "apiVersion": "2015-04-01",
51 | "location": "[resourceGroup().location]",
52 | "properties": {
53 | "name": "[parameters('cosmosDbIngressFunctionName')]",
54 | "computeMode": "Dynamic",
55 | "sku": "Dynamic"
56 | }
57 | },
58 | {
59 | "name": "[parameters('cosmosDbIngressFunctionName')]",
60 | "type": "Microsoft.Web/sites",
61 | "apiVersion": "2018-02-01",
62 | "location": "[resourceGroup().location]",
63 | "kind": "functionapp",
64 | "dependsOn": [
65 | "[variables('cosmosDbIngressServerFarmId')]",
66 | "[variables('cosmosDbIngressStorageAccountId')]",
67 | "[resourceId('microsoft.insights/components', parameters('cosmosDbIngressFunctionName'))]"
68 | ],
69 | "resources": [
70 | {
71 | "name": "web",
72 | "type": "sourceControls",
73 | "apiVersion": "2018-02-01",
74 | "dependsOn": [
75 | "[resourceId('Microsoft.Web/Sites', parameters('cosmosDbIngressFunctionName'))]"
76 | ],
77 | "properties": {
78 | "RepoUrl": "[parameters('repoURL')]",
79 | "branch": "master",
80 | "IsManualIntegration": true
81 | }
82 | }
83 | ],
84 | "properties": {
85 | "serverFarmId": "[variables('cosmosDbIngressServerFarmId')]",
86 | "siteConfig": {
87 | "appSettings": [
88 | {
89 | "name": "AzureWebJobsStorage",
90 | "value": "[concat('DefaultEndpointsProtocol=https;AccountName=', variables('cosmosDbIngressStorageAccountName'), ';AccountKey=', listKeys(variables('cosmosDbIngressStorageAccountId'),'2018-07-01').keys[0].value)]"
91 | },
92 | {
93 | "name": "WEBSITE_CONTENTAZUREFILECONNECTIONSTRING",
94 | "value": "[concat('DefaultEndpointsProtocol=https;AccountName=', variables('cosmosDbIngressStorageAccountName'), ';AccountKey=', listKeys(variables('cosmosDbIngressStorageAccountId'),'2018-07-01').keys[0].value)]"
95 | },
96 | {
97 | "name": "FUNCTIONS_EXTENSION_VERSION",
98 | "value": "~2"
99 | },
100 | {
101 | "name": "AppInsights_InstrumentationKey",
102 | "value": "[reference(concat('microsoft.insights/components/', parameters('cosmosDbIngressFunctionName'))).InstrumentationKey]"
103 | },
104 | {
105 | "name": "PROJECT",
106 | "value": "azure-functions/CosmosDbIngressFunc/CosmosDbIngressFunc.csproj"
107 | },
108 | {
109 | "name": "SERVICEBUS_CONNECTION",
110 | "value": "[listkeys(parameters('serviceBusAuth'), '2017-04-01').primaryConnectionString]"
111 | },
112 | {
113 | "name": "COSMOSDB_ENDPOINT",
114 | "value": "[parameters('cosmosDbEndpoint')]"
115 | },
116 | {
117 | "name": "COSMOSDB_KEY",
118 | "value": "[listKeys(parameters('cosmosDbId'), '2016-03-31').primaryMasterKey]"
119 | },
120 | {
121 | "name": "WEBSITE_CONTENTSHARE",
122 | "value": "[parameters('cosmosDbIngressFunctionName')]"
123 | },
124 | {
125 | "name": "SCM_COMMAND_IDLE_TIMEOUT",
126 | "value": "1200"
127 | }
128 | ]
129 | }
130 | }
131 | }
132 | ]
133 | }
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 | ##
4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
5 |
6 | # User-specific files
7 | *.suo
8 | *.user
9 | *.userosscache
10 | *.sln.docstates
11 |
12 | # User-specific files (MonoDevelop/Xamarin Studio)
13 | *.userprefs
14 |
15 | # Build results
16 | [Dd]ebug/
17 | [Dd]ebugPublic/
18 | [Rr]elease/
19 | [Rr]eleases/
20 | x64/
21 | x86/
22 | bld/
23 | [Bb]in/
24 | [Oo]bj/
25 | [Ll]og/
26 |
27 | # Visual Studio 2015 cache/options directory
28 | .vs/
29 | # Uncomment if you have tasks that create the project's static files in wwwroot
30 | #wwwroot/
31 |
32 | # MSTest test Results
33 | [Tt]est[Rr]esult*/
34 | [Bb]uild[Ll]og.*
35 |
36 | # NUNIT
37 | *.VisualState.xml
38 | TestResult.xml
39 |
40 | # Build Results of an ATL Project
41 | [Dd]ebugPS/
42 | [Rr]eleasePS/
43 | dlldata.c
44 |
45 | # .NET Core
46 | project.lock.json
47 | project.fragment.lock.json
48 | artifacts/
49 | **/Properties/launchSettings.json
50 |
51 | *_i.c
52 | *_p.c
53 | *_i.h
54 | *.ilk
55 | *.meta
56 | *.obj
57 | *.pch
58 | *.pdb
59 | *.pgc
60 | *.pgd
61 | *.rsp
62 | *.sbr
63 | *.tlb
64 | *.tli
65 | *.tlh
66 | *.tmp
67 | *.tmp_proj
68 | *.log
69 | *.vspscc
70 | *.vssscc
71 | .builds
72 | *.pidb
73 | *.svclog
74 | *.scc
75 |
76 | # Chutzpah Test files
77 | _Chutzpah*
78 |
79 | # Visual C++ cache files
80 | ipch/
81 | *.aps
82 | *.ncb
83 | *.opendb
84 | *.opensdf
85 | *.sdf
86 | *.cachefile
87 | *.VC.db
88 | *.VC.VC.opendb
89 |
90 | # Visual Studio profiler
91 | *.psess
92 | *.vsp
93 | *.vspx
94 | *.sap
95 |
96 | # TFS 2012 Local Workspace
97 | $tf/
98 |
99 | # Guidance Automation Toolkit
100 | *.gpState
101 |
102 | # ReSharper is a .NET coding add-in
103 | _ReSharper*/
104 | *.[Rr]e[Ss]harper
105 | *.DotSettings.user
106 |
107 | # JustCode is a .NET coding add-in
108 | .JustCode
109 |
110 | # TeamCity is a build add-in
111 | _TeamCity*
112 |
113 | # DotCover is a Code Coverage Tool
114 | *.dotCover
115 |
116 | # Visual Studio code coverage results
117 | *.coverage
118 | *.coveragexml
119 |
120 | # NCrunch
121 | _NCrunch_*
122 | .*crunch*.local.xml
123 | nCrunchTemp_*
124 |
125 | # MightyMoose
126 | *.mm.*
127 | AutoTest.Net/
128 |
129 | # Web workbench (sass)
130 | .sass-cache/
131 |
132 | # Installshield output folder
133 | [Ee]xpress/
134 |
135 | # DocProject is a documentation generator add-in
136 | DocProject/buildhelp/
137 | DocProject/Help/*.HxT
138 | DocProject/Help/*.HxC
139 | DocProject/Help/*.hhc
140 | DocProject/Help/*.hhk
141 | DocProject/Help/*.hhp
142 | DocProject/Help/Html2
143 | DocProject/Help/html
144 |
145 | # Click-Once directory
146 | publish/
147 |
148 | # Publish Web Output
149 | *.[Pp]ublish.xml
150 | *.azurePubxml
151 | # TODO: Comment the next line if you want to checkin your web deploy settings
152 | # but database connection strings (with potential passwords) will be unencrypted
153 | *.pubxml
154 | *.publishproj
155 |
156 | # Microsoft Azure Web App publish settings. Comment the next line if you want to
157 | # checkin your Azure Web App publish settings, but sensitive information contained
158 | # in these scripts will be unencrypted
159 | PublishScripts/
160 |
161 | # NuGet Packages
162 | *.nupkg
163 | # The packages folder can be ignored because of Package Restore
164 | **/packages/*
165 | # except build/, which is used as an MSBuild target.
166 | !**/packages/build/
167 | # Uncomment if necessary however generally it will be regenerated when needed
168 | #!**/packages/repositories.config
169 | # NuGet v3's project.json files produces more ignorable files
170 | *.nuget.props
171 | *.nuget.targets
172 |
173 | # Microsoft Azure Build Output
174 | csx/
175 | *.build.csdef
176 |
177 | # Microsoft Azure Emulator
178 | ecf/
179 | rcf/
180 |
181 | # Windows Store app package directories and files
182 | AppPackages/
183 | BundleArtifacts/
184 | Package.StoreAssociation.xml
185 | _pkginfo.txt
186 |
187 | # Visual Studio cache files
188 | # files ending in .cache can be ignored
189 | *.[Cc]ache
190 | # but keep track of directories ending in .cache
191 | !*.[Cc]ache/
192 |
193 | # Others
194 | ClientBin/
195 | ~$*
196 | *~
197 | *.dbmdl
198 | *.dbproj.schemaview
199 | *.jfm
200 | *.pfx
201 | *.publishsettings
202 | orleans.codegen.cs
203 |
204 | # Since there are multiple workflows, uncomment next line to ignore bower_components
205 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
206 | #bower_components/
207 |
208 | # RIA/Silverlight projects
209 | Generated_Code/
210 |
211 | # Backup & report files from converting an old project file
212 | # to a newer Visual Studio version. Backup files are not needed,
213 | # because we have git ;-)
214 | _UpgradeReport_Files/
215 | Backup*/
216 | UpgradeLog*.XML
217 | UpgradeLog*.htm
218 |
219 | # SQL Server files
220 | *.mdf
221 | *.ldf
222 | *.ndf
223 |
224 | # Business Intelligence projects
225 | *.rdl.data
226 | *.bim.layout
227 | *.bim_*.settings
228 |
229 | # Microsoft Fakes
230 | FakesAssemblies/
231 |
232 | # GhostDoc plugin setting file
233 | *.GhostDoc.xml
234 |
235 | # Node.js Tools for Visual Studio
236 | .ntvs_analysis.dat
237 | node_modules/
238 |
239 | # Typescript v1 declaration files
240 | typings/
241 |
242 | # Visual Studio 6 build log
243 | *.plg
244 |
245 | # Visual Studio 6 workspace options file
246 | *.opt
247 |
248 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
249 | *.vbw
250 |
251 | # Visual Studio LightSwitch build output
252 | **/*.HTMLClient/GeneratedArtifacts
253 | **/*.DesktopClient/GeneratedArtifacts
254 | **/*.DesktopClient/ModelManifest.xml
255 | **/*.Server/GeneratedArtifacts
256 | **/*.Server/ModelManifest.xml
257 | _Pvt_Extensions
258 |
259 | # Paket dependency manager
260 | .paket/paket.exe
261 | paket-files/
262 |
263 | # FAKE - F# Make
264 | .fake/
265 |
266 | # JetBrains Rider
267 | .idea/
268 | *.sln.iml
269 |
270 | # CodeRush
271 | .cr/
272 |
273 | # Python Tools for Visual Studio (PTVS)
274 | __pycache__/
275 | *.pyc
276 |
277 | # Cake - Uncomment if you are using it
278 | # tools/**
279 | # !tools/packages.config
280 |
281 | # Telerik's JustMock configuration file
282 | *.jmconfig
283 |
284 | # BizTalk build output
285 | *.btp.cs
286 | *.btm.cs
287 | *.odx.cs
288 | *.xsd.cs
289 |
290 | # Ignore ARM template parameters.json file
291 | parameters.json
--------------------------------------------------------------------------------
/azuredeploy.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://schema.management.azure.com/schemas/2018-05-01/deploymentTemplate.json#",
3 | "contentVersion": "1.0.0.0",
4 | "parameters": {
5 | "httpIngressFunctionName": {
6 | "type": "string",
7 | "defaultValue": "http-ingress-func",
8 | "metadata": {
9 | "description": "Name of the Http ingress function app."
10 | }
11 | },
12 | "httpIngressSkuName": {
13 | "type": "string",
14 | "defaultValue": "S3",
15 | "allowedValues": [
16 | "F1",
17 | "D1",
18 | "B1",
19 | "B2",
20 | "B3",
21 | "S1",
22 | "S2",
23 | "S3",
24 | "P1",
25 | "P2",
26 | "P3",
27 | "P4"
28 | ],
29 | "metadata": {
30 | "description": "Pricing SKU of dedicated plan. Check details at https://azure.microsoft.com/en-us/pricing/details/app-service/"
31 | }
32 | },
33 | "httpIngressSkuTier": {
34 | "type": "string",
35 | "allowedValues": [
36 | "Free",
37 | "Shared",
38 | "Basic",
39 | "Standard"
40 | ],
41 | "defaultValue": "Standard",
42 | "metadata": {
43 | "description": "Pricing tier for dedicated plan."
44 | }
45 | },
46 | "httpIngressSkuCapacity": {
47 | "type": "int",
48 | "minValue": 1,
49 | "maxValue": 20,
50 | "defaultValue": 4
51 | },
52 | "cosmosDbIngressFunctionName": {
53 | "type": "string",
54 | "defaultValue": "cosmosdb-ingress-func",
55 | "metadata": {
56 | "description": "Name of the Function App which inserts data in Cosmos DB"
57 | }
58 | },
59 | "consumerEgressFunctionName": {
60 | "type": "string",
61 | "defaultValue": "consumer-egress-func",
62 | "metadata": {
63 | "description": "Name of the Function App which orchestrates send to consumer"
64 | }
65 | },
66 | "consumerReceiveFunctionName": {
67 | "type": "string",
68 | "defaultValue": "consumer-receive-func",
69 | "metadata": {
70 | "description": "Name of the consumer-hosted Function App which receives final product"
71 | }
72 | },
73 | "cosmosDbAccountName": {
74 | "type": "string",
75 | "defaultValue": "azure-meetup-cosmosdb",
76 | "metadata": {
77 | "description": "Name of the Cosmos DB account"
78 | }
79 | },
80 | "serviceBusNamespaceName": {
81 | "type": "string",
82 | "defaultValue": "azure-meetup-products",
83 | "metadata": {
84 | "description": "Name of the Service Bus namespace"
85 | }
86 | }
87 | },
88 | "variables": {
89 | "repoURL": "https://github.com/syedhassaanahmed/azure-event-driven-data-pipeline.git",
90 | "cosmosDbEndpoint": "[concat('https://', parameters('cosmosDbAccountName'), '.documents.azure.com:443/')]",
91 | "cosmosDbId": "[resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('cosmosDbAccountName'))]",
92 | "serviceBusAuth": "[resourceId('Microsoft.ServiceBus/namespaces/authorizationRules', parameters('serviceBusNamespaceName'), 'RootManageSharedAccessKey')]",
93 | "templatesBaseUri": "https://raw.githubusercontent.com/syedhassaanahmed/azure-event-driven-data-pipeline/master/nested-arm-templates/"
94 | },
95 | "resources": [
96 | {
97 | "apiVersion": "2018-09-01",
98 | "name": "sharedResources",
99 | "type": "Microsoft.Resources/deployments",
100 | "properties": {
101 | "mode": "incremental",
102 | "templateLink": {
103 | "uri": "[concat(variables('templatesBaseUri'), 'shared-resources.json')]",
104 | "contentVersion": "1.0.0.0"
105 | },
106 | "parameters": {
107 | "cosmosDbAccountName": {
108 | "value": "[parameters('cosmosDbAccountName')]"
109 | },
110 | "serviceBusNamespaceName": {
111 | "value": "[parameters('serviceBusNamespaceName')]"
112 | }
113 | }
114 | }
115 | },
116 | {
117 | "apiVersion": "2018-09-01",
118 | "name": "httpIngress",
119 | "type": "Microsoft.Resources/deployments",
120 | "dependsOn": [
121 | "[resourceId('Microsoft.Resources/deployments', 'sharedResources')]"
122 | ],
123 | "properties": {
124 | "mode": "incremental",
125 | "templateLink": {
126 | "uri": "[concat(variables('templatesBaseUri'), 'http-ingress.json')]",
127 | "contentVersion": "1.0.0.0"
128 | },
129 | "parameters": {
130 | "httpIngressFunctionName": {
131 | "value": "[parameters('httpIngressFunctionName')]"
132 | },
133 | "httpIngressSkuName": {
134 | "value": "[parameters('httpIngressSkuName')]"
135 | },
136 | "httpIngressSkuTier": {
137 | "value": "[parameters('httpIngressSkuTier')]"
138 | },
139 | "httpIngressSkuCapacity": {
140 | "value": "[parameters('httpIngressSkuCapacity')]"
141 | },
142 | "serviceBusAuth": {
143 | "value": "[variables('serviceBusAuth')]"
144 | },
145 | "repoURL": {
146 | "value": "[variables('repoURL')]"
147 | }
148 | }
149 | }
150 | },
151 | {
152 | "apiVersion": "2018-09-01",
153 | "name": "cosmosDbIngress",
154 | "type": "Microsoft.Resources/deployments",
155 | "dependsOn": [
156 | "[resourceId('Microsoft.Resources/deployments', 'sharedResources')]"
157 | ],
158 | "properties": {
159 | "mode": "incremental",
160 | "templateLink": {
161 | "uri": "[concat(variables('templatesBaseUri'), 'cosmosdb-ingress.json')]",
162 | "contentVersion": "1.0.0.0"
163 | },
164 | "parameters": {
165 | "cosmosDbIngressFunctionName": {
166 | "value": "[parameters('cosmosDbIngressFunctionName')]"
167 | },
168 | "cosmosDbEndpoint": {
169 | "value": "[variables('cosmosDbEndpoint')]"
170 | },
171 | "cosmosDbId": {
172 | "value": "[variables('cosmosDbId')]"
173 | },
174 | "serviceBusAuth": {
175 | "value": "[variables('serviceBusAuth')]"
176 | },
177 | "repoURL": {
178 | "value": "[variables('repoURL')]"
179 | }
180 | }
181 | }
182 | },
183 | {
184 | "apiVersion": "2018-09-01",
185 | "name": "consumerEgress",
186 | "type": "Microsoft.Resources/deployments",
187 | "dependsOn": [
188 | "[resourceId('Microsoft.Resources/deployments', 'sharedResources')]"
189 | ],
190 | "properties": {
191 | "mode": "incremental",
192 | "templateLink": {
193 | "uri": "[concat(variables('templatesBaseUri'), 'consumer-egress.json')]",
194 | "contentVersion": "1.0.0.0"
195 | },
196 | "parameters": {
197 | "consumerEgressFunctionName": {
198 | "value": "[parameters('consumerEgressFunctionName')]"
199 | },
200 | "cosmosDbEndpoint": {
201 | "value": "[variables('cosmosDbEndpoint')]"
202 | },
203 | "cosmosDbId": {
204 | "value": "[variables('cosmosDbId')]"
205 | },
206 | "repoURL": {
207 | "value": "[variables('repoURL')]"
208 | }
209 | }
210 | }
211 | },
212 | {
213 | "apiVersion": "2018-09-01",
214 | "name": "consumerReceive",
215 | "type": "Microsoft.Resources/deployments",
216 | "properties": {
217 | "mode": "incremental",
218 | "templateLink": {
219 | "uri": "[concat(variables('templatesBaseUri'), 'consumer-receive.json')]",
220 | "contentVersion": "1.0.0.0"
221 | },
222 | "parameters": {
223 | "consumerReceiveFunctionName": {
224 | "value": "[parameters('consumerReceiveFunctionName')]"
225 | },
226 | "repoURL": {
227 | "value": "[variables('repoURL')]"
228 | }
229 | }
230 | }
231 | }
232 | ]
233 | }
--------------------------------------------------------------------------------