Azure function HTTP Trigger not cancelling request - c#

When I cancel my request from browser to a HTTP Trigger it does not cancel and continues execution when hosted on Azure.
My function example:
[FunctionName("Test")]
public async Task<IActionResult> Run(
[HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = null)] HttpRequest req,
CancellationToken cancellationToken,
ILogger log)
{
var allCancellationTokens = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, req.HttpContext.RequestAborted);
await Task.Delay(30000, allCancellationTokens.Token);
if (allCancellationTokens.IsCancellationRequested) {
log.LogInformation("Request was cancelled!");
return new StatusCodeResult(499);
}
return new OkObjectResult("Complete");
}
I have been testing the cancellation through Postman and axios cancel tokens.
It works when I run the project locally and cancel it, but does not seem to cancel once it's published to azure.
My expected result would be that it throws an OperationCanceledException if I cancel the request during the await Task.Delay(30000, allCancellationTokens.Token); However when checking logs on Azure Functions, just seems to carry on execution and complete the function.
Steps to reproduce:
Create a HTTP Trigger like the one defined above.
Publish the app to Azure.
Open the functions logs on Azure in the monitor section.
Using Postman, send a request to this function and cancel the request (within the timeout period of 30 seconds).
Won't cancel the request and will still execute.

CancellationToken is helpful for implementing graceful shutdown of your Functions runtime host when it is notified by the Operating System that something has gone wrong to terminate it, please see the following answer for more: https://stackoverflow.com/a/63439515/528779

Related

How can I find out where CancellationToken is being cancelled?

I have a very weird case where my ASP.NET Core Web API endpoint fails randomly due to CancellationToken being cancelled. I have that problem only when I run integration tests, the API works completely fine when I call it from Postman.
In order to understand what's going on, I'd like to know what causes the CancellationToken to have its state set to cancelled. Is there any way to enable some logging for that or any other solution?
The CancellationToken comes from the ASP.Net Core Web API action, it's created by the framework iteself.
// EDIT
Here's my action:
public async Task<ActionResult<TokenResponse>> GetToken(
[Required][FromBody] Parameters parameters,
ApiVersion apiVersion,
CancellationToken cancellationToken) { ... }
My application just passes that token through various layers.
From pure technical standpoint you can leverage cancelation callback (if you are the owner of CancellationTokenSource do not forget to call TryReset on it in case it is reused). For example:
CancellationToken cancellationToken = ...;
cancellationToken.Register(() => throw new Exception("Here")); // exception with stack trace will be thrown
Though not sure that this information will be as useful as you possibly expect.

Webhook callback getting unexpected response 301 from Azure Function

I've created an Azure Function and hosted it in Azure. It accepts "post" and "get" requests and I can run this locally and get some log output when I either GET or POST to it.
When I host this in Azure, I can get the output the same if I do a GET or POST, which is what I expect (via postman).
I'm using a third party tool for a callback to my Azure Function URL. When this callback gets sent, I don't get any output in the Azure CLI for logs. It is using the exact same address as I was using to get my output in the portal.
The third party tool is saying its getting an HTTP 301 response.
Why would the callback be getting an HTTP 301 when I can post/get to the same address from Postman and get a 200 back?
Function code:
[FunctionName("AddressNotification")]
public static async Task<IActionResult> Run(
[HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", Route = null)] HttpRequest req,
ILogger log)
{
log.LogInformation($"Address Callback function hit from req: {req.Host.ToString()}");
var content = await new StreamReader(req.Body).ReadToEndAsync();
log.LogInformation($"Request body: {content}");
return new OkResult();
}
Third party tool saying I'm getting a 301:
I would assume you have https only enabled in your function

Azure durable function "terminatePostUri" gives 404 when triggered

I'm creating an Azure Durable function app where the orchestrator run for a while but I need an option to cancel the orchestrator if needed. I'm trying to use the "terminatePostUri" from Postman but it gives me a 404 response.
Other instance management uris like statusQueryGetUri are working as expected.
Here's a code snippet of my Terminate Function.
[FunctionName("klaviyo_terminate_instance")]
public static Task Run([DurableClient(TaskHub = "%KlaviyoTaskHub%")] IDurableOrchestrationClient client,
[QueueTrigger("terminate-queue")] string instanceId)
{
return client.TerminateAsync(instanceId, "Called for terminate instance");
}
Here's the postman response.
So apparently the terminate uri works as a POST request (but not GET) despite not having any payload. Not sure what the reason for that is.
Source: https://learn.microsoft.com/en-us/azure/azure-functions/durable/durable-functions-http-api

Confused about running async methods in the background

Say I have the following methods, in my ASP.NET 5 Web API:
//(in a different class)
public static async Task SendStatus(string message)
{
await SendStatusMessage(message); //sends a status message to the client
}
[HttpGet("api/dowork")]
public async Task<IActionResult> DoWork()
{
await SendStatusToClient("starting to do work!");
//when it reaches this point, it should run the code in the background
await DoTheActualWork();
await SendStatusToClient("finished work!");
//I want the control back after it starts running the above code in the background, to send a 200 status code
return Ok();
}
This is how it should run:
It sends a status message, stating that it has started doing the work.
It does the work, and after the work is done, sends a status message. All of this should be done in the background.
Return a 200 (OK) status code to the user who requested the work. The actual work takes a significant amount of time and should still be running in the background.
How would I achieve this?
There are two answers helpful to you.
The first one, how to do it: Webapi2 - Return from controller action after one task completes, but continue with further Async processing
The second one, why not do it: How to answer a request but continue processing code in WebApi
So what to do now. I would suggest the following steps:
Create a queue. Either a database table an azure service bus queue, a rabbitmq queue or even a simple file or just a static memory structure. (Production loads require some persistence though)
Create a long running task to process the queued items. Web api supports background tasks, but you could create a service a job on the cloud or a windows service or any other application or service that works.

Does the Azure service bus client automatically use a retries for transient errors returned from the service bus?

I have a very simple Azure function that uses an Http Trigger to send messages to an Azure Service Bus topic. I want to retry this function if the service bus returns a transient error. I have reviewed the default policy, but I don't know how to verify if it will be used out of the box. Do I need to add anything to my function code to ensure that such a retry policy will be used?
I also want to log messages that fail to be loaded onto the service bus after the retry policy fails. Should I wrap the contents of the function in a try-catch block and perform the log in the catch statement?
[FunctionName("MessageLoader")]
[return: ServiceBus("%Topic_Name%", Connection = "Topic_Connection")]
public static async Task<TopicMessage> Run(
[HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = "domain/load-message")] HttpRequestMessage req)
{
var stringRequestBody = await req.Content.ReadAsStringAsync();
return JsonConvert.DeserializeObject<TopicMessage>(stringRequestBody);
}
Yes, in this case (Service Bus binding), the default retry policy is used. You do not need to do anything special. To verify if it's working, you should see failed dependencies in app insights whenever a call fails if you integrated it correctly.
To your second question, if it fails after the retry gives up, you do not need to log manually. You should see error logged in app insights automatically captured if you integrated it correctly.
If you want to log custom error on failure, you should use Servicebus message sender by creating it yourself instead of Function output binding.

Categories