Reputation: 3682
I have an Azure Function with an HttpTrigger.
I want to return 202 Accepted immediately to the caller and then actually process the call, which takes about a second.
Is there some best practice way of doing this?
I don't want to do ANYTHING before returning the call, so it is out of the question to first call EventGrid or similar.
By calling EventGrid I can return as soon as the EventGrid call is done and the actual processing can be in another function that is subscribing to the event. I don't want this because of the time it takes to call EventGrid and it does fail from time to time or take longer than normal.
By adding a message to a queue I can accomplish the same as with the EventGrid and it also has the same problem as described above.
I know that by calling a method inside my function without await, it will not wait for the response and I will be able to return immediately. However, my tests show that this is highly unrealiable, but please let me know if you think this is the way to go and why.
I can use Thread and ThreadStart etc. to make this manually and I guess this is what I might do if required, but I am asking this question to search for a better solution.
Upvotes: 12
Views: 6340
Reputation: 96
The Durable Functions extension can help with this.
You can start an Orchestration via HTTP that will return a Status URL the client can poll for status.
Upvotes: 7
Reputation: 581
There is a FunctionInvocationFilterAttribute
which might be what you're looking for. This attribute is still in preview but works fine. You can create your own attribute implementing it and define what you want to do when the function is executing by overriding the OnExecutingAsync
method.
Something like that :
using System;
using System.IO;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using Microsoft.Azure.WebJobs.Host;
using System.Threading;
using System.Linq;
namespace FunctionApp
{
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public class ReturnResponseBeforeExecutionAttribute : FunctionInvocationFilterAttribute
{
public override Task OnExecutingAsync(FunctionExecutingContext executingContext, CancellationToken cancellationToken)
{
var request = executingContext.Arguments.Values.FirstOrDefault(argument => argument is HttpRequest) as HttpRequest;
request.HttpContext.Response.StatusCode = 202;
request.HttpContext.Response.Body.Flush();
request.HttpContext.Response.Body.Close();
return Task.CompletedTask;
}
}
public class DoStuff
{
[ReturnResponseBeforeExecution]
[FunctionName("DoStuff")]
public async Task<IActionResult> Run(
[HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)] HttpRequest req,
ILogger log)
{
log.LogInformation("C# HTTP trigger function processed a request.");
string name = req.Query["name"];
string requestBody = await new StreamReader(req.Body).ReadToEndAsync();
dynamic data = JsonConvert.DeserializeObject(requestBody);
name = name ?? data?.name;
string responseMessage = string.IsNullOrEmpty(name)
? "This HTTP triggered function executed successfully. Pass a name in the query string or in the request body for a personalized response."
: $"Hello, {name}. This HTTP triggered function executed successfully.";
return new OkObjectResult(responseMessage);
}
}
}
EDIT : Just realized it still waits for the function to be executed before returning the response though.
Upvotes: 1