Open dhermyt opened 3 years ago
Can you share more details about your scenario?
Are you trying to programmatically set those values? This is not supported with the isolated worker, and something that would cause problems in consumption environments, so we just want to better understand your requirements. Thanks!
Hello Fabio,
In my case the queue name comes from the configuration and should be set dynamically. This is how it looked in the previous SDK:
private const string InputQueueName = "%ServiceBus:Queues:QueueName%";
[Function(FunctionName)]
public async Task RunAsync([ServiceBusTrigger(InputQueueName)] Message message, CancellationToken cancellationToken)
{
Here is the example on SO: https://stackoverflow.com/a/30515085
Thank you for the additional details.
This is indeed a limitation with the model, currently, as you don't have the ability to inject a name resolver in the context used by the extension.
Flagging this so we can discuss an appropriate approach to meet the requirement.
@ankitkumarr FYI, this would benefit from the worker driven indexing/metadata work.
This is a blocker for us moving from Web Jobs to Azure Functions.
@dhermyt I totally agree we should be able to inject our custom NameResolver like we can with the "normal" Azure Functions (called now class library AFAIK).
https://docs.microsoft.com/en-us/azure/app-service/webjobs-sdk-how-to#version-3x-6
var builder = new HostBuilder();
var resolver = new CustomNameResolver();
builder.ConfigureWebJobs(b =>
{
b.AddAzureStorageCoreServices();
});
builder.ConfigureServices(s => s.AddSingleton<INameResolver>(resolver)); // This is how to do it with "normal" azure functions and WebJobs
var host = builder.Build();
using (host)
{
await host.RunAsync();
}
But have in mind that the Isolated mode does implement a the default NameResolver es mentioned here https://docs.microsoft.com/en-us/azure/app-service/webjobs-sdk-how-to#custom-binding-expressions
"There's a default NameResolver that takes effect if you don't provide a custom one. The default gets values from app settings or environment variables."
So, while it's not as powerful and flexible as a custom NameResolver, it may work for you as the default behaviour is reading from an appsetting/enviromentvariable.
So this:
[Function("Function1")]
public void Run([ServiceBusTrigger("%myqueueName%", Connection = "MyConnection")] string myQueueItem, FunctionContext context)
{
var logger = context.GetLogger("Function1");
logger.LogInformation($"C# ServiceBus queue trigger function processed message: {myQueueItem}");
}
reads the queue name from a configuration setting / enviroment variable called myqueueName. I have tested this myself both locally and in Azure.
I insist, we should be able to inject our custom NameResolver for max flexibility
This is a blocker for us moving from Web Jobs to Azure Functions.
It's the same for us, we're planning to migrate in-process functions to isolated and this is another roadblock we need to overcome. @fabiocav is there any plan to port this feature?
Hi @fabiocav, is there any public information/github issue on worker driven indexing/metadata work
?
Is there any update here? It seems I can't even put my queue names in a separate 'queue-names.json' file
eg
builder
.AddJsonFile("local.settings.json", optional: true, reloadOnChange: true)
.AddJsonFile("queue-names.json", optional: true, reloadOnChange: true)
.AddEnvironmentVariables();
If the queue names are in queue-names.json
then it simply doesn't work.
They have to be in local.settings.json
I've also tried several variations of trying to inject a custom INameResolver (with a dotnet-isolated) function before I came across this github issue. As with others, it always hits the internal name resolver first, barfs and then stops, before getting to mine, by which time it's too late.
Given that .NET 8 is forcing Functions into being isolated process (and no more in-process), it would be good if we could get this resolved ;)
Thank you 👍🏻
I've also tried several variations of trying to inject a custom INameResolver (with a dotnet-isolated) function before I came across this github issue. As with others, it always hits the internal name resolver first, barfs and then stops, before getting to mine, by which time it's too late.
Given that .NET 8 is forcing Functions into being isolated process (and no more in-process), it would be good if we could get this resolved ;)
Thank you 👍🏻
I agree - I'm going to try and do a blog post on how I worked around this - but it's convoluted, build step, generate local.settings.json for each user. Honestly, such a lot of work for something that should be so simple!
I've also tried several variations of trying to inject a custom INameResolver (with a dotnet-isolated) function before I came across this github issue. As with others, it always hits the internal name resolver first, barfs and then stops, before getting to mine, by which time it's too late. Given that .NET 8 is forcing Functions into being isolated process (and no more in-process), it would be good if we could get this resolved ;) Thank you 👍🏻
I agree - I'm going to try and do a blog post on how I worked around this - but it's convoluted, build step, generate local.settings.json for each user. Honestly, such a lot of work for something that should be so simple!
what is the solution that you have implemented? I am pretty much stuck with the same issue. I am unable to resolve the name for the expression from appSettings
I just ran into this today. At least I'm not alone.
My scenario is pretty simple. I have a TimerTrigger with a CRON time. I know I can add that to the environment variables and it will work. What I want(ed) was to be a little smarter about it and provide a default.
builder.Configuration["SCHEDULER_CRON_TIME"] = builder.Configuration["SCHEDULER_CRON_TIME"] ?? "*/1 * * * * *";
However, that doesn't work, because the internal Function logic doesn't seem to be playing off the same configuration.
Like others I tracked this down to the name resolver, in my case, TimerSchedule.cs:
string resolvedExpression = nameResolver.ResolveWholeString(attribute.ScheduleExpression);
This seems like a really basic thing. As far as I can tell the Azure Function stuff has it's own internal service registration, because I don't even see DefaultNameResolver in the service collection.
I also ran into this issue. I sthere any change planned ?
Hi there,
I ran into this problem yesterday and dug into it.
1) From what I can see the resolving of the %token% value from Environment variables is done in Func.exe / the Host in Azure Functions.
2) The Metadata that is needed for the runner to register with all the queue etc is sent across via a GRPC call on start up.
3) This metadata is generated at design time by a Code Generator and is in a class which implements IFunctionMetadataProvider.
I have been able to create a new class internal class ConfigurableFunctionMetadataProvider(IFunctionMetadataProvider baseProvider, IConfiguration configuration, ILogger<ConfigurableFunctionMetadataProvider> logger) : IFunctionMetadataProvider { .... }
which then decorates the existing entry in the ServiceCollection services.Decorate<IFunctionMetadataProvider, ConfigurableFunctionMetadataProvider>();
(via scrutor) and walks the metadata coming back and replacing the tokens from what is configured in IConfiguration before passing it on.
I would just paste the code here but it is entwined in a customer project and I would have to rewrite it afresh if others were going to use it. If people need it let me know and I will invest the time to do that for you. Or ask on SO and link the question after this message and I will update there for you (and others).
Jonathan
@ac931274 sounds really interesting - I'd be curious to see it if at all possible: I ended up doing some WILD post build script to create user-specific queues and change local.settings.json
Here's the node.js script
const fs = require('fs');
const os = require('os');
const settingsPath = '../src/Function/local.settings.json';
const serviceBusQueueNamesPath = '../infra/config/servicebus-queue-names.json';
const clean = (input) => input.replace(/-/g, '');
const hostname = os.hostname().split('.')[0];
const user = os.userInfo().username;
const prefix = `${clean(user)}-${clean(hostname)}-`;
if (!fs.existsSync(settingsPath)) {
console.warn('local.settings.json path does not exist ('+settingsPath+')');
process.exit(1);
}
if (!fs.existsSync(serviceBusQueueNamesPath)) {
console.error('ServiceBus Queue Names path does not exist ('+settingsPath+')');
process.exit(1);
}
// I have the queue names stored in a json file
// (nb: this is also for deployment, not just this)
const serviceBusQueueNames = JSON.parse(fs.readFileSync(serviceBusQueueNamesPath, 'utf8'));
const localSettings = JSON.parse(fs.readFileSync(settingsPath, 'utf8'));
for (const key in serviceBusQueueNames) {
localSettings.Values[key] = prefix + serviceBusQueueNames[key];
}
fs.writeFileSync(settingsPath, JSON.stringify(localSettings, null, 2), 'utf8');
console.log('local.settings.json updated successfully.');
And I call this in the csproj like this
<Target Name="UpdateLocalSettings" BeforeTargets="Build" Condition="Exists('$(ProjectDir)local.settings.json')">
<Exec Command="node UpdateLocalSettings.js" WorkingDirectory="$(SolutionDir)tools" />
</Target>
.. as I said, quite wild, but had to get something working
@ac931274 I am also interested in seeing your workaround to this. This issue is blocking our migration to isolated worker, which is a little scary since they're saying in process isn't going to be updated anymore.
I have added my code to Stack Overflow here : https://stackoverflow.com/questions/78897966/azure-functions-trigger-variables-isolated-functions/78897967#78897967
Please upvote, question and answer, if useful.
Hello,
Is it still possible to pass dynamic queue name to Service Bus trigger? Previously INameResolver was used for that, but the new extension is missing this interface.