Azure durable function "terminatePostUri" gives 404 when triggered - c#

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

Related

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.

401 Unauthorized when querying durable function status

I need some help with Azure Durable Functions.
I created a new durable function with VS Code in C# and deployed it to Azure via the VS Code azure function extension. The function app resource was already created manually in the portal. I use
FUNCTIONS_WORKER_RUNTIME: dotnet
FUNCTIONS_EXTENSION_VERSION: ~2
I can trigger the creation of an durable task and but when I query the status with the statusQueryGetUri, I only get a 401 Unauthrized. The http trigger of the function itself is anonymous and does not require authentication (for debug purpose only).
The requests look like this (I used Postman to send the requests):
HTTP POST https://{function-app}.azurewebsites.net/api/SayHello_HttpStart
Response:
{
"id": "da3259a462084e86a34f8ce9859a6ed6",
"statusQueryGetUri": "https://{function-app}.azurewebsites.net/runtime/webhooks/durabletask/instances/da3259a462084e86a34f8ce9859a6ed6?taskHub=DurableFunctionsHub&connection=Storage&code=ua4tHacVv9JDH5phKCJI1OdKGXQSB/MMUX8WIv1E0OyZANqrRY3L/g==",
"sendEventPostUri": "https://{function-app}.azurewebsites.net/runtime/webhooks/durabletask/instances/da3259a462084e86a34f8ce9859a6ed6/raiseEvent/{eventName}?taskHub=DurableFunctionsHub&connection=Storage&code=ua4tHacVv9JDH5phKCJI1OdKGXQSB/MMUX8WIv1E0OyZANqrRY3L/g==",
"terminatePostUri": "https://{function-app}.azurewebsites.net/runtime/webhooks/durabletask/instances/da3259a462084e86a34f8ce9859a6ed6/terminate?reason={text}&taskHub=DurableFunctionsHub&connection=Storage&code=ua4tHacVv9JDH5phKCJI1OdKGXQSB/MMUX8WIv1E0OyZANqrRY3L/g==",
"rewindPostUri": "https://{function-app}.azurewebsites.net/runtime/webhooks/durabletask/instances/da3259a462084e86a34f8ce9859a6ed6/rewind?reason={text}&taskHub=DurableFunctionsHub&connection=Storage&code=ua4tHacVv9JDH5phKCJI1OdKGXQSB/MMUX8WIv1E0OyZANqrRY3L/g==",
"purgeHistoryDeleteUri": "https://{function-app}.azurewebsites.net/runtime/webhooks/durabletask/instances/da3259a462084e86a34f8ce9859a6ed6?taskHub=DurableFunctionsHub&connection=Storage&code=ua4tHacVv9JDH5phKCJI1OdKGXQSB/MMUX8WIv1E0OyZANqrRY3L/g=="
}
The Get Request is then simply:
GET https://{function-app}.azurewebsites.net/runtime/webhooks/durabletask/instances/da3259a462084e86a34f8ce9859a6ed6?taskHub=DurableFunctionsHub&connection=Storage&code=ua4tHacVv9JDH5phKCJI1OdKGXQSB/MMUX8WIv1E0OyZANqrRY3L/g==
Did I miss some configuration I have to set to allow access to the uri? What logs might help me figure out what the problem is?
When I run the code locally there are no problems and everything works as expected.
Thanks a lot for all help!
Note that the statusQueryGetUri is an admin endpoint which always requires a System Key.
GET <rootUrl>/runtime/webhooks/durabletask/instances/<GUID>
?taskHub={taskHub}
&connection={connection}
&code={systemKey}
As an alternative, you could also set the x-functions-key header of the http request with this key.
More info on the usage of the HTTP endpoints in the docs.

Azure Function Generic Webhook

Using Visual Studio 2017, I created a Function App with a Generic WebHook:
public static class FunctionWebHook
{
[FunctionName("FunctionWebHook")]
public static async Task<object> Run([HttpTrigger(WebHookType = "genericJson")]HttpRequestMessage request, TraceWriter log)
{
log.Info($"Webhook was triggered!");
string jsonContent = await request.Content.ReadAsStringAsync();
log.Info(jsonContent);
return request.CreateResponse(HttpStatusCode.NoContent);
}
}
The code is little more than the default template. I deployed this to my Azure account and tried to invoke it. I used the 'Get function url' link on the portal to get the correct URL, this included both the code and clientId parameters. When I try to POST JSON to the function (with content type set to application/json) I receive a 400 Bad Request:
{"Message":"The 'code' query parameter provided in the HTTP request did not match the expected value."}
I've check the code parameter and it is correct. I've also re-created the Function App several times, however I continue to receive the error. When I invoke the function using the Portal's Run command it executes correctly.
Has anyone come across this issue before?
So I use Restlet Client for any API work and it seems it has a strange issue. I copied the default (Host Key) from the Portal and pasted the URL into the Restlet Client and for some reason the last '==' of the code parameter is dropped. I tried the request using Postman and that request worked!
Thanks for all of the comments and the reply!
Which key did you choose to authenticate your request? There are 3 types of keys. Please choose the default(Function key) and use the generated URL and the key. I tested it on my side and the function key could pass the validation from server.
For more information of function key and host key, link below is for your reference.
Azure Function WebHook API Keys

What is the simplest way to run a timer-triggered Azure Function locally once?

I have a few C# Azure Functions that run on a schedule using timer triggers. I've set them up like so, where %TimerSchedule% refers to a cron expression in the app settings:
public static void Run([TimerTrigger("%TimerSchedule%")]TimerInfo myTimer, TraceWriter log)
During development, I often want to run the functions locally using Azure Functions Tools for Visual Studio + Azure Functions Core Tools. But when I hit F5 to debug the function locally it (usually) doesn't run immediately. Instead, it starts waiting for the next occurrence as per the timer schedule. So for example, if my cron expression says to run daily at 8PM, I'd have to wait until 8PM for the function to actually run on my machine.
So my question is: What is the simplest and best way to make a function run once locally?
Things I have tried or considered:
Use a more frequent timer schedule just for local development
This is OK but not perfect – you still have to wait a little bit unless it's very frequent, and if it's very frequent then the function might run multiple times. This is what I'm doing now.
Write a console app or unit test that directly calls the function's Run() method
This isn't 100% straightforward because you have to provide TimerInfo and TraceWriter arguments to Run() – and I've found surprisingly little documentation for that.
Microsoft's Strategies for testing your code in Azure Functions page is not very helpful on this topic – it only mentions timer triggers as a way to test other trigger types.
In a perfect world, I'd hit F5 and the function would immediately run once – just like developing a "normal" .NET app.
I had the same question, and used the DEBUG-flag to have the RunOnStartup only while debugging:
public static void Run(
[TimerTrigger("* 0 7 * * 1-5"
#if DEBUG
, RunOnStartup=true
#endif
)]TimerInfo myTimer, TraceWriter log)
{
You could perhaps use the RunOnStartup flag as documented here. It doesn't quite meet your brief regarding it only running once, but it should at least execute it locally once the app has started.
/// Gets or sets a value indicating whether the function should be invoked
/// immediately on startup. After the initial startup run, the function will
/// be run on schedule thereafter.
Example using attribute binding:
[TimerTrigger("%TimerSchedule%", RunOnStartup = true)]TimerInfo myTimer
From https://learn.microsoft.com/en-us/azure/azure-functions/functions-run-local?tabs=windows%2Ccsharp%2Cbash#non-http-triggered-functions
Non-HTTP triggered functions
For all kinds of functions other than HTTP triggers and webhooks, you can test your functions locally by calling an administration endpoint. Calling this endpoint with an HTTP POST request on the local server triggers the function. You can optionally pass test data to the execution in the body of the POST request. This functionality is similar to the Test tab in the Azure portal.
You call the following administrator endpoint to trigger non-HTTP functions:
http://localhost:{port}/admin/functions/{function_name}
To pass test data to the administrator endpoint of a function, you must supply the data in the body of a POST request message. The message body is required to have the following JSON format:
{
"input": "<trigger_input>"
}
If you are using VS Code, use the Azure Functions extension:
Hit F5 to enter debug mode, this starts the function app.
Go to the Azure icon in the Activity bar.
Under Local Project, find the function you want to run, right click, and select "Execute Function Now".
Check out this MS quickstart guide.
Using postman should do the trick. Follow the below steps to Run or debug you Timer Trigger Locally.
1 . RUN your Project.
Open Postman and past this url http://localhost:{port}/admin/functions/{function_name}
Make sure to use a POST Method with Json body of
{
"input": ""
}
Press SEND.
You Should receive a response of 202.
I had the same question. I fixed it with a Unittest.
Indeed you need to stub out the TraceWriter and the TimerInfo.
Here some code how I did this.
TimerInfo:
public class ScheduleStub : TimerInfo
{
public ScheduleStub(TimerSchedule schedule, ScheduleStatus status, bool isPastDue = false) : base(schedule, status, isPastDue)
{
}
}
And the TraceWriter:
public class TraceWriterStub : TraceWriter
{
protected TraceLevel _level;
protected List<TraceEvent> _traces;
public TraceWriterStub(TraceLevel level) : base(level)
{
_level = level;
_traces = new List<TraceEvent>();
}
public override void Trace(TraceEvent traceEvent)
{
_traces.Add(traceEvent);
}
public List<TraceEvent> Traces => _traces;
}
Start your function with this curl command
curl --request POST -H "Content-Type:application/json" --data '{"input":""}' http://localhost:7071/admin/functions/{function_name}
The input data is required, without it the function won't be triggered.
Another approach is to trigger manually the function from Postman:
Manually run a non HTTP-triggered function.
POST /admin/functions/<function name> HTTP/1.1
Host: localhost:<port>
Content-Type: application/json
{}
For me, it looks like that on postman for a timerTrigger function called Function1:
Just add another function with HTTP trigger type within the same class, add your code, or call your Run method from that function and invoke it from your browser.
Be sure to comment/remove that function when deployed to prod, or you will have the ability to trigger the function via HTTP calls in prod.

CORS error only when not 'await' in a ASP WebApi project

In a C# WebApi project plus angular js, the browser shows "No 'Access-Control-Allow-Origin' header is present on the requested resource".
I enabled the CORS in starup class:
app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);
In fact, other controllers in the same project are working fine. After debugging, I see that the problem is when I start a task without the 'await'. In the controller, I need to send an email at end of the process, but I did not want to wait for the sending, it is not important, it is just a notification, so I throw the sending task without waiting. In this case, the CORS problem appears when the service is called from angularjs. In reality, the service is called and it works, but the post function of angularjs returns error and the browser console shows the CORS message.
public async Task SaveData(DemoModel form)
{
... code for saving data...
SendEmailDemo();
}
However, if I add the 'await' word and wait for sending the email, everything works fine.
public async Task SaveData(DemoModel form)
{
... code for saving data...
await SendEmailDemo();
}
I am confused and I am not clear about the reason. Somebody can explain what I am missing?

Categories