microsoft / DurableFunctionsMonitor

A monitoring/debugging UI tool for Azure Durable Functions

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

[DotNetBackend] Support for .NET functions in isolated worker mode

oleks9o6 opened this issue · comments

It seems that in the future the preferred way of running Azure Functions will be in isolated worker mode. It would be nice to have support for it.

I just noticed, that version 6.1.0 added a dependency on Microsoft.NET.Sdk.Functions package that is incompatible with isolated worker mode:

Microsoft.NET.Sdk.Functions package is meant to be used with in-proc function apps. Please remove the reference to this package in isolated function apps.

Version 6.0.0 doesn't work with isolated worker mode either but it does not cause errors.

Thanks for that @oleks9o6 !
Indeed, Microsoft.NET.Sdk.Functions (and hence DurableFunctionsMonitor.DotNetBackend) is incompatible with .NET Isolated, so to be able to "inject" DfMon into .NET Isolated projects we would need to reimplement and push the backend as a separate NuGet package anyway.
Let's track that activity under this ticket.

commented

NET Isolated support would be most welcome! 🥳

Just published an alpha version of DurableFunctionsMonitor.DotNetIsolated, which can be 'injected' into your .NET 7 Isolated Function.

Would greatly appreciate any feedback.

How to use

  • Install from NuGet: dotnet add package DurableFunctionsMonitor.DotNetIsolated --version 6.3.0-alpha2
  • Initialize by calling .UseDurableFunctionMonitor() extension method, like this:
         var host = new HostBuilder()
             .ConfigureFunctionsWorkerDefaults((hostBuilderContext, workerAppBuilder) => {
    
                 workerAppBuilder.UseDurableFunctionsMonitor();
    
             })
             .Build();
    

By default all settings are read from env variables (all the same config settings are supported), but those can be programmatically (re)configured like this:

        var host = new HostBuilder()
            .ConfigureFunctionsWorkerDefaults((hostBuilderContext, workerAppBuilder) => {

                workerAppBuilder.UseDurableFunctionsMonitor((settings, extensionPoints) => 
                {
                    // Override DfMon's settings here
                    settings.Mode = DfmMode.ReadOnly;
                    // ....
                });

            })
            .Build();

Limitations

  • No way to configure path to DfMon's endpoint, so it will always appear at the API root (http://localhost:7071/my-route-prefix). If you have other HTTP endpoints and any of them got overshadowed, then you'll need to move them to some other path.
  • Multiple Storage connection strings are not supported, only the default one (AzureWebJobsStorage).
  • Support for Durable Entities is limited (since they are not supported in Isolated mode yet anyway).
  • For non-default durability providers you'll need to provide custom routines for retrieving instance history etc.. This should be done via extensionPoints parameter of .UseDurableFunctionsMonitor() configuration method. Code for MSSQL storage provider can be directly copied from here.

Please, let me know how it works for you.

Just published an alpha version of DurableFunctionsMonitor.DotNetIsolated, which can be 'injected' into your .NET 7 Isolated Function.

Would greatly appreciate any feedback.

Thanks for the update and instructions!

I tried it and was able to run it in our solution - durable functions on-premises with MSSQL as storage. So, the extensionPoints section came in handy🤗
The issue I faced (and you mentioned it in limitations) is HTTP endpoints overshadowing. I did not dig too deep yet, but all the GET requests were replaced, nevertheless, the POST ones were not.

I'm going to look into authentication options and try more advanced scenarios in the forthcoming weeks.

The issue I faced (and you mentioned it in limitations) is HTTP endpoints overshadowing.

Yeah, I'm afraid there is no easy way to make DfMon endpoint's path configurable in Isolated mode. HttpTrigger.Route value can only be a constant, and changing it would require a rebuild.

I can only think of injecting DfMon as a source code, using a Roslyn code generator, but really not sure it is worth the effort.

Maybe @fabiocav has any better ideas...

Yeah, I'm afraid there is no easy way to make DfMon endpoint's path configurable in Isolated mode. HttpTrigger.Route value can only be a constant, and changing it would require a rebuild.

It looks like DFM intercepts all the requests because of DfmServeStaticsFunction that uses the route {p1?}/{p2?}/{p3?}. So, it is impossible to have its own function that is triggered with a GET request.
I'm not sure how to fix this in the right way but, maybe, using a hardcoded prefix e.g. statics/ or some route constraints to p1, p2, and p3 parameters could solve the problem.

Then I'm afraid we have no other option than to lock DfMon's path prefix to something unique (as you suggested).

I've just set it to /durable-functions-monitor and pushed the updated package as https://www.nuget.org/packages/DurableFunctionsMonitor.DotNetIsolated/6.3.0-beta1 .

DfMon should now appear at http://localhost:7071/durable-functions-monitor and shouldn't hide anything anymore.
And then at the root you can always do a redirect, if needed:

        [Function(nameof(HttpRoot))]
        public HttpResponseData Run([HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = "/")] HttpRequestData req)
        {
            var response = req.CreateResponse(HttpStatusCode.TemporaryRedirect);
            response.Headers.Add("Location", "durable-functions-monitor");
            return response;
        }

Please, tell me if it works better.

Please, tell me if it works better.

It works much better now, thank you😊

I've been using it for quite some time - and it works nicely (.NET8 in isolated mode).
The only issue I have is lots of timeouts when there are thousands of instances that are processing at the same time but I assume it is rather an issue with the storage (MS SQL server in my case) itself.

I think the issue can be closed.