Skip to content

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

Deploying Azure Functions

  • In vscode, use the Azure Functions extension
  • If you begin the development in vscode, you cannot modify it in azure portal

  • Create new project: create local project

  • Project folder: ./
  • Language: Python
  • Runtime: Python 3.9
  • Trigger method: HTTP, timer, etc
  • Function name: HttpTrigger1
  • Authorization 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 away
  • Runtime 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 key
  • Anonymous: everyone can trigger
  • Admin: 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 evoked
  • Orchestrator function: responsible for maintaining the workflow
  • Activity 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 and container (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 or Message (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