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
statelessoperations! 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 methodFunction nameAuthorization 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.txtfile
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 starterDurable function orchestratorDurable 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,databaseandcontainer (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/updatedto 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
stringorMessage(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.jsonfile 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