AppConfiguration icon indicating copy to clipboard operation
AppConfiguration copied to clipboard

Use App Configuration in Azure Functions Triggers

Open BigBd1 opened this issue 6 years ago • 18 comments

Hello,

In an Azure Function V2, is it possible to bind the connection string or the queue name of the QueueTrigger attribute to an Azure App Configuration Setting ?

Thanks for your help !

BigBd1 avatar Nov 28 '19 17:11 BigBd1

@BigBd1, with a quick look, I don't see an easy way to retrieve the QueueTrigger information from App Configuration. User code can retrieve configuration from App Configuration only at runtime but QueueTrigger attribute requires the information at build time.

This will be something we will have to take a deeper look and probably discuss with the Azure Functions team.

cc: @lisaguthrie @yegu-ms

zhenlan avatar Dec 04 '19 05:12 zhenlan

I'm trying to read the queue name from App Configuration as well, but without luck. And yes, it seems the problem is that settings are read at runtime only.

For ServiceBus connection strings, it is solved by having a standard name for the setting, i.e. AzureWebJobsServiceBus, which is known by Azure Functions and loaded outside your solution. It isn't a custom string loaded manually and provided to an extension function, as described here.

What is the current status? Is this something you expect to support?

lundmikkel avatar Jan 28 '20 11:01 lundmikkel

QueueTrigger attribute requires the information at build time.

It does require a string at build time, but by using a %Namespace:Key% identifier it will be loaded at runtime. I have a suspicion that it might be possible to somehow hook into the configuration system to provide this value 🤔 After all, the key is typically provided in a local.settings.json

JosXa avatar Jun 21 '20 03:06 JosXa

@JosXa, the value is available at runtime, but Azure Functions need the value earlier than that. In the current design of Azure Functions, it's too late when the configuration is loaded from App Configuration at runtime.

zhenlan avatar Jun 21 '20 03:06 zhenlan

@BigBd1 Maybe we can generalize the issue title to Use App Configuration setting for Azure Function Triggers, as every dynamically configurable trigger is affected?

JosXa avatar Jun 21 '20 16:06 JosXa

Is there any resolution for this issue? I am looking any way to read the topicname,subscriptionname, ServiceBusConnectionString in ServiceBusTrigger from azure app configuration. Please let me know.

cvanama avatar Jan 26 '21 00:01 cvanama

@cvanama I stumble uppon this issue a few weeks ago as I wanted to use App Configuration for SignalR and CosmosDB parameters. This is actually simpler than it looks and you should be able to update the following code with a service bus.

First the Function itself:

public class CosmosSignalFunction
    {
        [FunctionName("function")]
        public async Task Run(
            [CosmosDBTrigger(
                databaseName: "%CosmosDB:DatabaseName%",
                collectionName: "%CosmosDB:CircleRepository:Name%",
                ConnectionStringSetting = "CosmosDB:ConnectionString",
                CreateLeaseCollectionIfNotExists = true,
                LeaseCollectionName = "leases")]IReadOnlyList<Document> input,
            [SignalR(
                HubName = "WishlistHub", 
                ConnectionStringSetting = "SignalR:ConnectionString")] IAsyncCollector<SignalRMessage> signalRMessages,
            ILogger log)
        {
            foreach (var entry in input)
            {
                // Do stuff
            }
        }
    }

As you can see, nothing much here, I'm just using bindings expression for my parameters. Cf: https://docs.microsoft.com/en-us/azure/azure-functions/functions-bindings-expressions-patterns

The magic happens in the Startup class of the function (I assume that you use Azure Function ~2 or higer), this is where you inject all your services and dependencies.

 public class Startup : IWebJobsStartup
    {
        public IConfiguration Configuration { get; set; }

        public void Configure(IWebJobsBuilder builder)
        {
            var configurationBuilder = new ConfigurationBuilder();
            configurationBuilder.CreateDefaultAzureFunctionConfiguration();

            Configuration = configurationBuilder.Build();

            builder.Services.Replace(ServiceDescriptor.Singleton(typeof(IConfiguration), Configuration));

            ConfigureService(builder.Services);
        }

        public IServiceCollection ConfigureService(IServiceCollection services)
        {
            // Options
            services.Configure<DefaultDocumentDbOptions>(
                Configuration.GetSection(DefaultDocumentDbOptions.SectionName));

            return services;
        }
    }

The important line is that one:

builder.Services.Replace(ServiceDescriptor.Singleton(typeof(IConfiguration), Configuration));

This will replace the configuration injected through the App Settings by the Azure Function SDK by the configuration built with App Configuration. So when using the parameters bindings expressions you must refer to the App Configuration section of your parameter.

Btw, the configurationBuilder.CreateDefaultAzureFunctionConfiguration() is a custom extension method that manage the App Configuration with AddAzureAppConfiguration, there is nothing special there.

JulesP96 avatar Jan 26 '21 08:01 JulesP96

@JulesP96 Thanks lot for your reply, i will try this approach and will get back to you if found any issues.

cvanama avatar Jan 26 '21 15:01 cvanama

@JulesP96 this worked perfectly thank you.

One thing that tripped me up - notice that Connection string is not being replaced here and isn't surrounded by % it is literally the name of the setting that holds the connection string.

Also, while this works I do get the following warning

The Functions scale controller may not scale the following functions correctly because some configuration values were modified in an external startup class.

For my purposes this is not an issue because we are actually limiting the instances to specifically not scale (so downstream services aren't overwhelmed) but it would be great for azure app configuration to be supported first-class by azure functions.

crhistianramirez avatar Mar 05 '21 16:03 crhistianramirez

@JulesP96 thanks for sharing. Just add a note for others who may come across this thread.

  • You don't have to replace the Azure Functions default IConfiguration. You can add Azure App Configuration as an extra configuration source to your Function App. See details in the quick start.
  • Your Function App may work locally but won't start if it's deployed to Azure Functions with a consumption plan. The issue is tracked in https://github.com/Azure/azure-functions-host/issues/7210.

The Function App sample in this repo is updated to include this https://github.com/Azure/AppConfiguration/blob/main/examples/DotNetCore/AzureFunction/FunctionApp/ReadQueuedMessage.cs

zhenlan avatar Mar 22 '21 09:03 zhenlan

Is there also a solution for this problem in case a out of process function is used. Unfortunately the solution mentioned by @JulesP96 does not seem to work in that scenario. I added it to the program.cs but if I set a breakpoint it hits only after the function is started.

.ConfigureServices((context, services) => { var configuration = context.Configuration; services.Replace(ServiceDescriptor.Singleton(typeof(IConfiguration), configuration));

beukerz avatar May 18 '22 09:05 beukerz

Is there also a solution for this problem in case a out of process function is used. Unfortunately the solution mentioned by @JulesP96 does not seem to work in that scenario. I added it to the program.cs but if I set a breakpoint it hits only after the function is started.

.ConfigureServices((context, services) => { var configuration = context.Configuration; services.Replace(ServiceDescriptor.Singleton(typeof(IConfiguration), configuration));

I have the same problem, did you find any solution?

davicbaba avatar Jun 07 '22 00:06 davicbaba

No unfortunately not. I am using the functions configuration for now. The out of process functions are not mature at all, there are many things that do not work yet or only work with a work around if you do something more than the basic stuff.

beukerz avatar Jun 07 '22 08:06 beukerz

The support for expression resolution for the out-of-process Azure Functions is tracked at https://github.com/Azure/azure-functions-dotnet-worker/issues/1253.

zhenlan avatar Mar 20 '23 16:03 zhenlan

Is there any update on this? Now NET7 only supports azure functions isolated and having to replicate configurations in each function instead of using app configuration is pretty bad. Considering we COULD do it in Azure Function In-Process

christianarg avatar May 24 '23 13:05 christianarg

While we are waiting for the Azure Functions team to address https://github.com/Azure/azure-functions-dotnet-worker/issues/1253. An alternative solution is to leverage the App Configuration reference feature in App Service/Azure Functions:

Assume you have a Storage queue triggered Function app and you reference the queue name from the variable queuename in your Function. You can

  1. Add a key-value named Storage:QueueName with no label in App Configuration for the actual queue name.
  2. Create an App Setting queuename in Azure Functions and set its value to something like this:
    @Microsoft.AppConfiguration(Endpoint=https://<your-store-name>.azconfig.io; Key=Storage:QueueName)
    

What's used in step 2 is an App Configuration reference. See here for more information. This way, you can manage your Function trigger information in App Configuration and step 2 is a one-time change.

zhenlan avatar May 27 '23 03:05 zhenlan