Tutorial: Trigger Azure Functions on blob containers using an event subscription

Previous versions of the Azure Functions Blob Storage trigger poll your storage container for changes. More recent version of the Blob Storage extension (5.x+) instead use an Event Grid event subscription on the container. This event subscription reduces latency by triggering your function instantly as changes occur in the subscribed container.

This article shows how to create a function that runs based on events raised when a blob is added to a container. You use Visual Studio Code for local development and to validate your code before deploying your project to Azure.

  • Create an event-based Blob Storage triggered function in a new project.
  • Validate locally within Visual Studio Code using the Azurite emulator.
  • Create a blob storage container in a new storage account in Azure.
  • Create a function app in the Flex Consumption plan (preview).
  • Create an event subscription to the new blob container.
  • Deploy and validate your function code in Azure.

This article supports version 4 of the Node.js programming model for Azure Functions.

This article supports version 2 of the Python programming model for Azure Functions.

This article creates a C# app that runs in isolated worker mode, which supports .NET 8.0.

Important

This tutorial has you use the Flex Consumption plan, which is currently in preview. The Flex Consumption plan only supports the event-based version of the Blob Storage trigger.

Prerequisites

Note

The Azure Storage extension for Visual Studio Code is currently in preview.

Create a Blob triggered function

When you create a Blob Storage trigger function using Visual Studio Code, you also create a new project. You need to edit the function to consume an event subscription as the source, rather than use the regular polled container.

  1. In Visual Studio Code, press F1 to open the command palette, enter Azure Functions: Create Function..., and select Create new project.

  2. For your project workspace, select a directory location. Make sure that you either create a new folder or choose an empty folder for the project workspace.

    Don't choose a project folder that's already part of a workspace.

    1. At the prompts, provide the following information:
    Prompt Action
    Select a language Select C#.
    Select a .NET runtime Select .NET 8.0 Isolated LTS.
    Select a template for your project's first function Select Azure Blob Storage trigger (using Event Grid).
    Provide a function name Enter EventGridBlobTrigger.
    Provide a namespace Enter My.Functions.
    Select setting from "local.settings.json" Select Create new local app setting.
    Select subscription Select your subscription, if needed.
    Select a storage account Use Azurite emulator for local storage.
    The path within your storage account that the trigger will monitor Accept the default value samples-workitems.
    Select how you would like to open your project Select Open in current window.
    Prompt Action
    Select a language Select Python.
    Select a Python programming model Select Model V2
    Select a Python interpreter to create a virtual environment Select your preferred Python interpreter. If an option isn't shown, enter the full path to your Python binary.
    Select a template for your project's first function Select Blob trigger. (The event-based template isn't yet available.)
    Provide a function name Enter EventGridBlobTrigger.
    The path within your storage account that the trigger will monitor Accept the default value samples-workitems.
    Select setting from "local.settings.json" Select Create new local app setting.
    Select subscription Select your subscription, if needed.
    Select a storage account Use Azurite emulator for local storage.
    Select how you would like to open your project Select Open in current window.
    Prompt Action
    Select a language Select Java.
    Select a version of Java Select Java 11 or Java 8, the Java version on which your functions run in Azure and that you've locally verified.
    Provide a group ID Select com.function.
    Provide an artifact ID Select EventGridBlobTrigger (or the default).
    Provide a version Select 1.0-SNAPSHOT.
    Provide a package name Select com.function.
    Provide an app name Accept the generated name starting with EventGridBlobTrigger.
    Select the build tool for Java project Select Maven.
    Select how you would like to open your project Select Open in current window.

    An HTTP triggered function (HttpExample) is created for you. You won't use this function and must instead create a new function.

    Prompt Action
    Select a language for your function project Select TypeScript.
    Select a TypeScript programming model Select Model V4.
    Select a template for your project's first function Select Azure Blob Storage trigger (using Event Grid).
    Provide a function name Enter EventGridBlobTrigger.
    Select setting from "local.settings.json" Select Create new local app setting.
    Select subscription Select your subscription, if needed.
    Select a storage account Use Azurite emulator for local storage.
    The path within your storage account that the trigger will monitor Accept the default value samples-workitems.
    Select how you would like to open your project Select Open in current window.
    Prompt Action
    Select a language for your function project Select JavaScript.
    Select a JavaScript programming model Select Model V4.
    Select a template for your project's first function Select Azure Blob Storage trigger (using Event Grid).
    Provide a function name Enter eventGridBlobTrigger.
    Select setting from "local.settings.json" Select Create new local app setting.
    Select subscription Select your subscription, if needed.
    Select a storage account Use Azurite emulator for local storage.
    The path within your storage account that the trigger will monitor Accept the default value samples-workitems.
    Select how you would like to open your project Select Open in current window.
    Prompt Action
    Select a language for your function project Select PowerShell.
    Select a template for your project's first function Select Azure Blob Storage trigger (using Event Grid).
    Provide a function name Enter EventGridBlobTrigger.
    Select setting from "local.settings.json" Select Create new local app setting.
    Select subscription Select your subscription, if needed.
    Select a storage account Use Azurite emulator for local storage.
    The path within your storage account that the trigger will monitor Accept the default value samples-workitems.
    Select how you would like to open your project Select Open in current window.
  1. In the command palette, enter Azure Functions: Create Function... and select EventGridBlobTrigger. If you don't see this template, first select Change template filter > All.

  2. At the prompts, provide the following information:

    Prompt Action
    Provide a package name Select com.function.
    Provide a function name Enter EventGridBlobTrigger.
    Select setting from "local.settings.json" Select Create new local app setting.
    Select subscription Select your subscription.
    Select a storage account Use Azurite emulator for local storage.
    The path within your storage account that the trigger will monitor Accept the default value samples-workitems.

You now have a function that can be triggered by events in a Blob Storage container.

Update the trigger source

You first need to switch the trigger source from the default Blob trigger source (container polling) to an event subscription source.

  1. Open the function_app.py project file and you see a definition for the EventGridBlobTrigger function with the blob_trigger decorator applied.

  2. Update the decorator by adding source = "EventGrid". Your function should now look something like this:

    @app.blob_trigger(arg_name="myblob", source="EventGrid", path="samples-workitems",
                               connection="<STORAGE_ACCOUNT>") 
    def EventGridBlobTrigger(myblob: func.InputStream):
    logging.info(f"Python blob trigger function processed blob"
                f"Name: {myblob.name}"
                f"Blob Size: {myblob.length} bytes")
    

    In this definition source = "EventGrid" indicates that an event subscription to the samples-workitems blob container is used as the source of the event that starts the trigger.

(Optional) Review the code

Open the generated EventGridBlobTrigger.cs file and you see a definition for an EventGridBlobTrigger function that looks something like this:

[Function(nameof(EventGridBlobTriggerCSharp))]
public async Task Run([BlobTrigger("PathValue/{name}", Source = BlobTriggerSource.EventGrid, Connection = "ConnectionValue")] Stream stream, string name)
{
    using var blobStreamReader = new StreamReader(stream);
    var content = await blobStreamReader.ReadToEndAsync();
    _logger.LogInformation($"C# Blob Trigger (using Event Grid) processed blob\n Name: {name} \n Data: {content}");
}

In this definition Source = BlobTriggerSource.EventGrid indicates that an event subscription to the blob container (in the example PathValue) is used as the source of the event that starts the trigger.

Open the generated EventGridBlobTrigger.java file and you see a definition for an EventGridBlobTrigger function that looks something like this:

    @FunctionName("EventGridBlobTrigger")
    @StorageAccount("<STORAGE_ACCOUNT>")
    public void run(
        @BlobTrigger(name = "content", source = "EventGrid", path = "samples-workitems/{name}", dataType = "binary") byte[] content,
        @BindingName("name") String name,
        final ExecutionContext context
    ) {
        context.getLogger().info("Java Blob trigger function processed a blob. Name: " + name + "\n  Size: " + content.length + " Bytes");
    }

In this definition source = EventGrid indicates that an event subscription to the samples-workitems blob container is used as the source of the event that starts the trigger.

In the EventGridBlobTrigger folder, open the function.json file and find a binding definition like this with a type of blobTrigger and a source of EventGrid:

{
    "bindings": [
        {
            "name": "InputBlob",
            "type": "blobTrigger",
            "direction": "in",
            "path": "samples-workitems/{name}",
            "source": "EventGrid",
            "connection":""
        }
    ]
}

The path indicates that the samples-workitems blob container is used as the source of the event that starts the trigger.

Open the generated EventGridBlobTrigger.js file and you see a definition for a function that looks something like this:

const { app } = require('@azure/functions');

app.storageBlob('storageBlobTrigger1', {
    path: 'samples-workitems/{name}',
    connection: 'MyStorageAccountAppSetting',
    source: 'EventGrid',
    handler: (blob, context) => {
        context.log(
            `Storage blob function processed blob "${context.triggerMetadata.name}" with size ${blob.length} bytes`
        );
    },
});

In this definition, a source of EventGrid indicates that an event subscription to the samples-workitems blob container is used as the source of the event that starts the trigger.

Open the generated EventGridBlobTrigger.ts file and you see a definition for a function that looks something like this:

import { app, InvocationContext } from '@azure/functions';

export async function storageBlobTrigger1(blob: Buffer, context: InvocationContext): Promise<void> {
    context.log(
        `Storage blob function processed blob "${context.triggerMetadata.name}" with size ${blob.length} bytes`
    );
}

app.storageBlob('storageBlobTrigger1', {
    path: 'samples-workitems/{name}',
    connection: 'MyStorageAccountAppSetting',
    source: 'EventGrid',
    handler: storageBlobTrigger1,
});

In this definition, a source of EventGrid indicates that an event subscription to the samples-workitems blob container is used as the source of the event that starts the trigger.

Upgrade the Storage extension

To use the Event Grid-based Blob Storage trigger, you must have at least version 5.x of the Azure Functions Storage extension.

To upgrade your project with the required extension version, in the Terminal window, run this dotnet add package command:

dotnet add package Microsoft.Azure.Functions.Worker.Extensions.Storage.Blobs 
  1. Open the host.json project file, and review the extensionBundle element.

  2. If extensionBundle.version isn't at least 3.3.0 , replace the extensionBundle element with this version:

    "extensionBundle": {
        "id": "Microsoft.Azure.Functions.ExtensionBundle",
        "version": "[4.0.0, 5.0.0)"
    }
    

Prepare local storage emulation

Visual Studio Code uses Azurite to emulate Azure Storage services when running locally. You use Azurite to emulate the Azure Blob Storage service during local development and testing.

  1. If you haven't already done so, install the Azurite v3 extension for Visual Studio Code.

  2. Verify that the local.settings.json file has "UseDevelopmentStorage=true" set for AzureWebJobsStorage, which tells Core Tools to use Azurite instead of a real storage account connection when running locally.

  3. Press F1 to open the command palette, type Azurite: Start Blob Service, and press enter, which starts the Azurite Blob Storage service emulator.

  4. Select the Azure icon in the Activity bar, expand Workspace > Attached Storage Accounts > Local Emulator, right-click Blob Containers, select Create Blob Container..., enter the name samples-workitems, and press Enter.

    Screenshot showing how to select Create Blob Container in the local emulation in Visual Studio Code.

  5. Expand Blob Containers > samples-workitems and select Upload files....

    Screenshot showing how to select Upload Files in the samples-workitems container in local emulation in Visual Studio Code.

  6. Choose a file to upload to the locally emulated container. This file gets processed later by your function to verify and debug your function code. A text file might work best with the Blob trigger template code.

Run the function locally

With a file in emulated storage, you can run your function to simulate an event raised by an Event Grid subscription. The event info passed to your trigger depends on the file you added to the local container.

  1. Set any breakpoints and press F5 to start your project for local debugging. Azure Functions Core Tools should be running in your Terminal window.

  2. Back in the Azure area, expand Workspace > Local Project > Functions, right-click the function, and select Execute Function Now....

    Screenshot showing how to select the Execute Function Now button from the function in the local project workspace in Visual Studio Code.

  3. In the request body dialog, type samples-workitems/<TEST_FILE_NAME>, replacing <TEST_FILE_NAME> with the name of the file you uploaded in the local storage emulator.

  4. Press Enter to run the function. The value you provided is the path to your blob in the local emulator. This string gets passed to your trigger in the request payload, which simulates the payload when an event subscription calls your function to report a blob being added to the container.

  5. Review the output of this function execution. You should see in the output the name of the file and its contents logged. If you set any breakpoints, you might need to continue the execution.

Now that you've successfully validated your function code locally, it's time to publish the project to a new function app in Azure.

Prepare the Azure Storage account

Event subscriptions to Azure Storage require a general-purpose v2 storage account. You can use the Azure Storage extension for Visual Studio Code to create this storage account.

  1. In Visual Studio Code, press F1 again to open the command palette and enter Azure Storage: Create Storage Account.... Provide this information when prompted:

    Prompt Action
    Enter the name of the new storage account Provide a globally unique name. Storage account names must have 3 to 24 characters in length with only lowercase letters and numbers. For easier identification, we use the same name for the resource group and the function app name.
    Select a location for new resources For better performance, choose a region near you.

    The extension creates a general-purpose v2 storage account with the name you provided. The same name is also used for the resource group that contains the storage account. The Event Grid-based Blob Storage trigger requires a general-purpose v2 storage account.

  2. Press F1 again and in the command palette enter Azure Storage: Create Blob Container.... Provide this information when prompted:

    Prompt Action
    Select a resource Select the general-purpose v2 storage account that you created.
    Enter a name for the new blob container Enter samples-workitems, which is the container name referenced in your code project.

Your function app also needs a storage account to run. For simplicity, this tutorial uses the same storage account for your blob trigger and your function app. However, in production, you might want to use a separate storage account with your function app. For more information, see Storage considerations for Azure Functions.

Create the function app

Use these steps to create a function app in the Flex Consumption plan. When your app is hosted in a Flex Consumption plan, Blob Storage triggers must use event subscriptions.

  1. In the command pallet, enter Azure Functions: Create function app in Azure...(Advanced).

  2. Following the prompts, provide this information:

    Prompt Selection
    Enter a globally unique name for the new function app. Type a globally unique name that identifies your new function app and then select Enter. Valid characters for a function app name are a-z, 0-9, and -.
    Select a hosting plan. Choose Flex Consumption (Preview).
    Select a runtime stack. Choose the language stack and version on which you've been running locally.
    Select a resource group for new resources. Choose the existing resource group in which you created the storage account.
    Select a location for new resources. Select a location in a supported region near you or near other services that your functions access. Unsupported regions aren't displayed. For more information, see View currently supported regions.
    Select a storage account. Choose the name of the storage account you created.
    Select an Application Insights resource for your app. Choose Create new Application Insights resource and at the prompt provide the name for the instance used to store runtime data from your functions.

    A notification appears after your function app is created. Select View Output in this notification to view the creation results, including the Azure resources that you created.

Deploy your function code

Important

Deploying to an existing function app always overwrites the contents of that app in Azure.

  1. In the command palette, enter and then select Azure Functions: Deploy to Function App.

  2. Select the function app you just created. When prompted about overwriting previous deployments, select Deploy to deploy your function code to the new function app resource.

  3. When deployment is completed, select View Output to view the creation and deployment results, including the Azure resources that you created. If you miss the notification, select the bell icon in the lower-right corner to see it again.

    Screenshot of the View Output window.

Update application settings

Because required application settings from the local.settings.json file aren't automatically published, you must upload them to your function app so that your function runs correctly in Azure.

  1. In the command pallet, enter Azure Functions: Download Remote Settings..., and in the Select a resource prompt choose the name of your function app.

  2. When prompted that the AzureWebJobsStorage setting already exists, select Yes to overwrite the local emulator setting with the actual storage account connection string from Azure.

  3. In the local.settings.json file, replace the local emulator setting with same connection string used forAzureWebJobsStorage.

  4. Remove the FUNCTIONS_WORKER_RUNTIME entry, which isn't supported in a Flex Consumption plan.

  5. In the command pallet, enter Azure Functions: Upload Local Settings..., and in the Select a resource prompt choose the name of your function app.

Now both the Functions host and the trigger are sharing the same storage account.

Build the endpoint URL

To create an event subscription, you need to provide Event Grid with the URL of the specific endpoint to report Blob Storage events. This blob extension URL is composed of these parts:

Part Example
Base function app URL https://<FUNCTION_APP_NAME>.azurewebsites.net
Blob-specific path /runtime/webhooks/blobs
Function query string ?functionName=Host.Functions.<FUNCTION_NAME>
Blob extension access key &code=<BLOB_EXTENSION_KEY>

The blob extension access key is designed to make it more difficult for others to access your blob extension endpoint. To determine your blob extension access key:

  1. In Visual Studio Code, choose the Azure icon in the Activity bar. In Resources, expand your subscription, expand Function App, right-click the function app you created, and select Open in portal.

  2. Under Functions in the left menu, select App keys.

  3. Under System keys select the key named blobs_extension, and copy the key Value.

    You include this value in the query string of new endpoint URL.

  4. Create a new endpoint URL for the Blob Storage trigger based on the following example:

    https://<FUNCTION_APP_NAME>.azurewebsites.net/runtime/webhooks/blobs?functionName=Host.Functions.EventGridBlobTrigger&code=<BLOB_EXTENSION_KEY>
    

    In this example, replace <FUNCTION_APP_NAME> with the name of your function app, and <BLOB_EXTENSION_KEY> with the value you got from the portal. If you used a different name for your function, replace EventGridBlobTrigger with that function name.

You can now use this endpoint URL to create an event subscription.

Create the event subscription

An event subscription, powered by Azure Event Grid, raises events based on changes in the subscribed blob container. This event is then sent to the blob extension endpoint for your function. After you create an event subscription, you can't update the endpoint URL.

  1. In Visual Studio Code, choose the Azure icon in the Activity bar. In Resources, expand your subscription, expand Storage accounts, right-click the storage account you created earlier, and select Open in portal.

  2. Sign in to the Azure portal and make a note of the Resource group for your storage account. You create your other resources in the same group to make it easier to clean up resources when you're done.

  3. Select the Events option from the left menu.

    Add storage account event

  4. In the Events window, select the + Event Subscription button, and provide values from the following table into the Basic tab:

    Setting Suggested value Description
    Name myBlobEventSub Name that identifies the event subscription. You can use the name to quickly find the event subscription.
    Event Schema Event Grid Schema Use the default schema for events.
    System Topic Name samples-workitems-blobs Name for the topic, which represents the container. The topic is created with the first subscription, and you'll use it for future event subscriptions.
    Filter to Event Types Blob Created
    Endpoint Type Web Hook The blob storage trigger uses a web hook endpoint.
    Endpoint Your Azure-based URL endpoint Use the URL endpoint that you built, which includes the key value.
  5. Select Confirm selection to validate the endpoint URL.

  6. Select the Filters tab and provide the following information to the prompts:

    Setting Suggested value Description
    Enable subject filtering Enabled Enables filtering on which blobs can trigger the function.
    Subject Begins With /blobServices/default/containers/<CONTAINER_NAME>/blobs/<BLOB_PREFIX> Replace <CONTAINER_NAME and <BLOB_PREFIX> with values you choose. This sets the subscription to trigger only for blobs that start with BLOB_PREFIX and are in the CONTAINER_NAME container.
    Subject Ends With .txt Ensures that the function will only be triggered by blobs ending with .txt.

For more information on filtering to specific blobs, see Event Filtering for Azure Event Hubs.

  1. Select Create to create the event subscription.

Upload a file to the container

You can upload a file from your computer to your blob storage container using Visual Studio Code.

  1. In Visual Studio Code, press F1 to open the command palette and type Azure Storage: Upload Files....

  2. In the Open dialog box, choose a file, preferably a text file, and select Upload .

  3. Provide the following information at the prompts:

    Setting Suggested value Description
    Enter the destination directory of this upload default Just accept the default value of /, which is the container root.
    Select a resource Storage account name Choose the name of the storage account you created in a previous step.
    Select a resource type Blob Containers You're uploading to a blob container.
    Select Blob Container samples-workitems This value is the name of the container you created in a previous step.

Browse your local file system to find a file to upload and then select the Upload button to upload the file.

Verify the function in Azure

Now that you uploaded a file to the samples-workitems container, the function should be triggered. You can verify by checking the following on the Azure portal:

  1. In your storage account, go to the Events page, select Event Subscriptions, and you should see that an event was delivered. There might be up a five-minute delay for the event to show up on the chart.

  2. Back in your function app page in the portal, under Functions find your function and select Invocations and more. You should see traces written from your successful function execution.

Clean up resources

When you continue to the next step and add an Azure Storage queue binding to your function, you'll need to keep all your resources in place to build on what you've already done.

Otherwise, you can use the following steps to delete the function app and its related resources to avoid incurring any further costs.

  1. In Visual Studio Code, press F1 to open the command palette. In the command palette, search for and select Azure: Open in portal.

  2. Choose your function app and press Enter. The function app page opens in the Azure portal.

  3. In the Overview tab, select the named link next to Resource group.

    Screenshot of select the resource group to delete from the function app page.

  4. On the Resource group page, review the list of included resources, and verify that they're the ones you want to delete.

  5. Select Delete resource group, and follow the instructions.

    Deletion may take a couple of minutes. When it's done, a notification appears for a few seconds. You can also select the bell icon at the top of the page to view the notification.

For more information about Functions costs, see Estimating Consumption plan costs.

Next steps