Azure / azure-functions-dotnet-worker

Azure Functions out-of-process .NET language worker
MIT License
403 stars 166 forks source link

Improved middleware support to enable Durable Functions #739

Closed cgillum closed 2 years ago

cgillum commented 2 years ago

Orchestrator functions in Durable Functions have some very special requirements in terms of how they deal with inputs, outputs, and invocation. In WebJobs, we were able to take advantage of abstractions like invocation handlers to inject trigger-specific middleware into the orchestrator function execution pipeline. This was needed so that we could wrap the function execution in the body of a Durable Task Framework orchestration, manipulate the function inputs and outputs, and short-circuit the function execution when an await is encountered for the first time. However, there are some issues with the .NET worker extensibility that make it hard for us to implement this same functionality for .NET Isolated.

I looked at IFunctionsWorkerMiddleware, which seems to be the closest thing to invocation handlers, but there seem to be a few issues with it:

The issues above are ordered by perceived severity.

anthonychu commented 2 years ago

@cgillum Let's set up something in the new year to discuss this and update this thread.

julealgon commented 2 years ago

@cgillum Let's set up something in the new year to discuss this and update this thread.

Any updates you guys could share?

cgillum commented 2 years ago

I believe it's being worked on as we speak, and I'm waiting eagerly to try it out. :) (speaking about the middleware part)

kshyju commented 2 years ago

Yes, the second item is in-progress. #798 tracks the progress of that work.

kshyju commented 2 years ago

Version 1.8.0-preview1 of Microsoft.Azure.Functions.Worker package introduces a few new APIs which addresses the 3 items mentioned.

  1. To update input binding data, output binding data and invocation result, use any of the below extension methods on FunctionContext.
    
    public static ValueTask<InputBindingData<T>> BindInputAsync<T>(BindingMetadata bindingMetadata);
    public static InvocationResult<T> GetInvocationResult<T>();;
    public static InvocationResult GetInvocationResult();
    public static IEnumerable<OutputBindingData<T>> GetOutputBindings<T>();

// Http trigger specific public static ValueTask<HttpRequestData?> GetHttpRequestDataAsync(); public static HttpResponseData? GetHttpResponseData();


[The sample project](https://github.com/Azure/azure-functions-dotnet-worker/tree/main/samples/CustomMiddleware) has some examples of this API usage.

2.  We also added the [support for startup hooks](https://github.com/Azure/azure-functions-dotnet-worker/pull/830). This allow extension authors to register extension specific startup code, which can include registering middleware relevant to the extension. See the [PR description](https://github.com/Azure/azure-functions-dotnet-worker/pull/830) for example.
3. The `UseWhen` extension method can be used to register a middleware which gets executed conditionally. Example usage [here](https://github.com/Azure/azure-functions-dotnet-worker/blob/main/samples/CustomMiddleware/Program.cs#L23).
justinmchase commented 2 years ago

Is it possible to update the input bindings themselves during the startup?