Function App
- Functions are
paid based on requests
. The charge is per request - The functions app is linked to a
Storage account
, where the function is stored in a container - Functions apps support only one runtime stack. To add another language, you must create another function app
- Functions apps perform
stateless
operations! In opposite to durable functions
Plans
Consumption (Serverless)
: Paid for the code that runs (not always running, there is latency to start up)Functions Premium
: Pre-warmed instaced that are always online and ready to run functions. Add more compute when required.App service plan
: Reuse the app service plan that runs the app (optionally enable always on feature). Accept timeout longer than 10 min.
Triggers
-
Invoking your function by means of:
-
HTTP trigger
Timer trigger
-
From other services
(e.g., blob storage, queue storage, event hubs, cosmosdb) -
https://hvitoi-function.azurewebsites.net/api/crazy-function?code={secret-code}
- The code is used for authentication
Deploying Azure Functions
- In
vscode
, use the Azure Functionsextension
-
If you begin the development in vscode, you cannot modify it in azure portal
-
Create new project: create local project
Project folder
: ./Language
: PythonRuntime
: Python 3.9Trigger method
: HTTP, timer, etcFunction name
: HttpTrigger1Authorization level
: function, anonymous, admin- Create function: add a function to an existing project
Trigger method
Function name
Authorization level
- Deploy to function app
Function app
(new or existing): if deploying to an existing project it deploys right awayRuntime stack
(case new)Location
(case new)
Right click on the function (not the function app) and get the function url
Authorization level
Function
: requires an authorization keyAnonymous
: everyone can triggerAdmin
: only admin can trigger
Function
- Select the development environment (visual studio, vscode, portal, any editor)
- Editing functions in portal is not supported for linux function apps
- Select the trigger
- Select name of the function
-
The function itself is composed of 3 parts
-
function.json
: configuration for the function readme.md
-
run
(.csx, .js, .py, etc): code itself -
Dependencies of the functions must be listed in the
requirements.txt
file
azure-functions
pandas=1.2.3
requests
Durable functions
- Stateful operations
- Durable functions can be created by the vscode extension selecting the template functions
Durable functions HTTP starter
Durable function orchestrator
Durable functions activity
- Workflow
Starter function
: function to be evokedOrchestrator function
: responsible for maintaining the workflowActivity function
: workers
Time Trigger
public static class Function
{
[Function("Work")]
public static void Run(
[TimeTrigger("0 */5 * * * *")] TimerInfo myTimer,
ILogger log
)
{
var container = GetCloudBlobContainer();
foreach(var fileItem in ListFiles())
{
var file = new CloudFile(fileItem.StorageUri.PrimaryUri);
var ms = new MemoryStream();
file.DownloadToStreamAsync(ms);
var blob = container.GetBlockBlobReference(fileItem.Uri.ToString());
blob.UploadFromStreamAsync(ms);
}
}
}
HTTP Trigger
public static async Task<IActionResult> Run(
HttpRequest req,
ILogger log
)
{
log.LogInformation("C# function triggered by HTTP request.");
string id = req.Query["id"]; // query parameter
string requestBody = await new StreamReader(req.Body).ReadToEndAsync(); // read entire body
dynamic data = JsonConvert.DeserializeObject(requestBody); // parse JSON
string name = data.name;
string responseMessage = $"Hello, {name}! Your id is {id}.";
return new OkObjectResult(responseMessage);
}
CosmosDB Trigger
- Listens to changes from another source (E.g., cosmosdb)
- Choose template CosmosDBTrigger (Change feed)
- Select cosmosDB
account
,database
andcontainer (collection)
- Whenever an item is inserted or updated in the container, the function will be triggered
- A new collection is created in the cosmosdb that records the changes happened, the name given to this new collection is usually
leases
public static class ReadCosmosChange
{
[Function("ReadCosmosChange")]
public static void Run(
[CosmosDBTrigger(
databaseName: "appdb",
collectionName: "course",
ConnectionStringSetting = "cosmosdbstring", // name of the connection string in local.settings.json
LeaseCollectionName = "leases", // collection that stores the changes from the above collection
CreateLeaseCollectionIfNotExists = true
)] IReadOnlyList<Document> input,
FunctionContext context)
{
var logger = context.GetLogger("ReadCosmosChange");
if (input != null && input.Count > 0) // input is the incoming data
{
foreach (var _course in input) // for each item that has changed
{
logger.LogInformation($"Course ID {_course.Id}");
logger.LogInformation($"Course Name {_course.GetPropertyValue<string>("coursename")}");
}
}
}
}
Blob Trigger
- Trigger
whenever a blob the added/updated
to the container - Example: Take the data from blob storage and insert it into cosmosdb
<ItemGroup>
<PackageReference Include="Microsoft.Azure.WebJobs.Extensions.CosmosDB" Version="3.0.10" />
<PackageReference Include="Microsoft.Azure.WebJobs.Extensions.Storage" Version="3.0.10" />
<PackageReference Include="Microsoft.NET.Sdk.Functions" Version="3.0.11" />
</ItemGroup>
public static class BlobTrigger
{
[Function("BlobTrigger")]
public static void Run(
[BlobTrigger("data/{name}", Connection = "hvitoi_STORAGE")] string myBlob,
[CosmosDB (databaseName: "appdb", collectionName:"blobs", ConnectionStringSetting ="CosmosDBConnection")] out dynamic document, // Get a cosmos db client connection
[Blob("userContent"/{name}, FileAccess,Write)] // Get a blob client connection
string name,
FunctionContext context)
{
var logger = context.GetLogger("BlobTrigger");
logger.LogInformation($"C# Blob trigger function Processed blob\n Name: {name} \n Data: {myBlob}");
StreamReader reader = new StreamReader(myBlob);
logger.LogInformation(reader.ReadToEnd()); // Read all the content of the blob read
Blob blob = new Blob()
{
blobid = Guid.NewGuid().ToString(),
blobname = name,
blobsize = myBlob.Length
};
document = blob; // take the blob and insert as a cosmosdb item
}
}
Queue Trigger
- The connection string must be contained in the
local.settings.json
- The messages that could not be processed after
5 times
(default) are automatically sent to a -poison queue
public static class QueueTriggerCSharp1
{
[Function("GetMessages")]
public static void Run(
[QueueTrigger("appqueue", Connection = "hvitoi_STORAGE")] string myQueueItem,
FunctionContext context
)
{
var logger = context.GetLogger("QueueTriggerCSharp1");
logger.LogInformation($"C# Queue trigger function processed: {myQueueItem}");
}
}
Service Bus Queue Trigger
- Messages can be received as a
string
orMessage
(Microsoft.Azure.ServiceBus)
public static class GetMessages
{
[Function("GetMessages")]
public static void Run(
[ServiceBusTrigger("appqueue", Connection = "hvitoi_SERVICEBUS")] Message myQueueItem,
FunctionContext context
)
{
var logger = context.GetLogger("GetMessages");
logger.LogInformation($"Body of the message: {Encoding.UTF8.GetString(myQueueItem.Body)}");
logger.LogInformation($"Content type: {myQueueItem.ContentType}");
}
}
Service Bus Topic Trigger
public static class GetMessages
{
[Function("GetMessages")]
public static void Run(
[ServiceBusTrigger("apptopic", "subscription-name", Connection = "hvitoi_SERVICEBUS")] string mySbMsg,
FunctionContext context
)
{
var logger = context.GetLogger("GetMessages");
logger.LogInformation($"C# ServiceBus topic trigger function processed message: {mySbMsg}");
}
}
Event Grid Trigger
public static class EventGridTriggerCSharp1
{
[Function("EventGridTriggerCSharp1")]
public static void Run(
[EventGridTrigger] MyEvent input,
FunctionContext context
)
{
var logger = context.GetLogger("EventGridTriggerCSharp1");
logger.LogInformation($"The topic is {input.Topic}"); // /subscriptions/subscription-id/resourceGroups/resource-group-id/providers/Microsoft.Storage/storageAccounts/hvitoi
logger.LogInformation($"The data is {input.EventType}"); // Microsoft.Storage.BlobDeleted
logger.LogInformation($"The data is {input.Id}"); // uuid
logger.LogInformation($"The data is {input.Subject}"); // /blobServices/default/containers/data/blobs/Courses.json
logger.LogInformation($"The data is {input.Data.ToString()}");
}
}
public class MyEvent
{
public string Id { get; set; }
public string Topic { get; set; }
public string Subject { get; set; }
public string EventType { get; set; }
public DateTime EventTime { get; set; }
public object Data { get; set; }
}
Event Hub Trigger
public static class EventHubTriggerCSharp1
{
[Function("EventHubTriggerCSharp1")]
public static void Run(
[EventHubTrigger("apphub", Connection = "hvitoi_Send_EVENTHUB")] string[] input,
FunctionContext context
)
{
var logger = context.GetLogger("EventHubTriggerCSharp1");
logger.LogInformation($"First Event Hubs triggered message: {input[0]}");
}
}
Host file
host.json
file stores settings about the environment- https://docs.microsoft.com/en-us/azure/azure-functions/functions-host-json
- It has configuration about all the trigger methods
- You can configure here the batchSize, to prevent multiple SQL connections to be opened