Calling ServiceBus' IQueueClient.CompleteAsync() from a different thread always fails - c#

I'm receiving from a queue using IQueueClient.RegisterMessageHandler(), and in the receiving method I'm then starting a Hangfire task. But in the Hangfire task, all calls to IQueueClient.CompleteAsync() to mark the message as consumed (because I'm using ReceiveMode.PeekLock mode) fail.
I suspect it's because the Hangfire task re-creates the IQueueClient, that it may be because the call to CompleteAsync() is from a different instance of IQueueClient? Or is something else possibly going wrong? I'm passing Message.SystemProperties.LockToken into the Hangfire task which is what is then being used by CompleteAsync.

I suspect it's because the Hangfire task re-creates the IQueueClient, that it may be because the call to CompleteAsync() is from a different instance of IQueueClient?
That's correct. LockToken is not enough to complete the message. You have to use the same client used to receive the message in order to complete it.

Related

Azure Batch Services: TaskStateMonitor on Intentional Task Deletion

In Azure batch services, when a task is added to a job, you are able to create a TaskStateMonitor which will wait for the completion/timeout of the added task. When a task completes (or timeouts), the monitor will return (or raise an exception).
What happens to the monitor if you delete the job before completion? Does the task monitor wait until the timeout is reached, does it raise a different exception, or does it consider the job as being completed?
Figured it out: After testing this on my end, The TaskStateMonitor will raise the following exception when it checks for a state and cannot find one
Microsoft.Azure.Batch.Common.BatchException: Operation returned an invalid status code 'NotFound'

Is there a way to return a response from an API call to ASP.NET while keeping the instance running?

I am writing an API using ASP.NET and I have some potentially long running code from the different end points. The system uses CQRS and Event Sourcing. A Command comes into to an end point and is then published as an event using MediatR. However the Handlers are potentially long running. Since some of the Requests coming in might be sent to multiple Handlers. This process could take longer than the 12s that AWS allows before returning an Error code.
Is there a way to return a response back to the caller to say that the event has been created while still contining with the process? That is to say fire off a separate task that performs the long running piece of code, that also catches and logs errors. Then return a value back to the user saying the Event has been successfully created?
I believe that ASP.NET spins up a new instance each time a call is made, will the old instance die one a value is returned, killing the task?
I could be wrong with a number of points here, this is my knowledge gleaned from the internet but I could have missunderstood articles.
Thanks.
Yes, you should pass the long-running task off to a background process and return to the user. When the task is complete, notifiy the user with whatever mechanism is appropriate for your site.
But do not start a new thread, what you want is to have a background service running for this, and use that to manage your request.
If a new thread is running the long operation it will remain “open/live” until it finishes. Also you can configure the app pool to always be active.
There are a lot of frameworks to work with long running tasks like Hangfire.
And to keep the user updated with the status of the task you can use SignalR to push notifications to the UI

What happens to the task that is initiated if the web api returns the response

I am trying to implement a task in fire and forget manner.
Lets look at the below piece of code.
public IHttpActionResult Update(int id)
{
var updatedResult = _updater.update(id);
// fire and forget a task
sendEmailToUser();
return ok();
}
private async Task sendEmailToUser()
{
var httpclient = new HttpClient();
// assume the client is initiated with required url and other headers
await httpclient.postasync("some url");
}
Given the above code, can i safely assume that whenever Update endpoint is called, sendEmailToUser task is triggered and will be run to completion ?
No. You should almost never start any background threads in web application. HTTP is suppose to be stateless and the web server was designed with that in mind.
The server might be put into sleep state when there is no incoming request for a set period of time. During that time all the background execution will be halt including the one you had. It might and might not get resume when the next request comes in.
Or when IIS decides to recycle your App domain on a scheduled basis your thread will get killed too.
If you really need background tasks then do that using windows service or run it as a separate console application.
Under normal conditions, it's reasonable to expect that the task will run to completion. It will go on independently.
Your biggest concerns, in this case, should be about the web API not being terminated, and the task not throwing an exception.
But if OP needs to be 100% sure, there are other safer ways to code that.

webapi 2 - how to properly invoke long running method async/in new thread, and return response to client

I am developing a web-api that takes data from client, and saves it for later use. Now i have an external system that needs to know of all events, so i want to setup a notification component in my web-api.
What i do is, after data is saved, i execute a SendNotification(message) method in my new component. Meanwhile i don't want my client to wait or even know that we're sending notifications, so i want to return a 201 Created / 200 OK response as fast as possible to my clients.
Yes this is a fire-and-forget scenario. I want the notification component to handle all exception cases (if notification fails, the client of the api doesn't really care at all).
I have tried using async/await, but this does not work in the web-api, since when the request-thread terminates, the async operation does so aswell.
So i took a look at Task.Run().
My controller looks like so:
public IHttpActionResult PostData([FromBody] Data data) {
_dataService.saveData(data);
//This could fail, and retry strategy takes time.
Task.Run(() => _notificationHandler.SendNotification(new Message(data)));
return CreatedAtRoute<object>(...);
}
And the method in my NotificationHandler
public void SendNotification(Message message) {
//..send stuff to a notification server somewhere, syncronously.
}
I am relatively new in the C# world, and i don't know if there is a more elegant(or proper) way of doing this. Are there any pitfalls with using this method?
It really depends how long. Have you looked into the possibility of QueueBackgroundWorkItem as detailed here. If you want to implement a very fast fire and forget you also might want to consider a queue to pop these messages onto so you can return from the controller immediately. You'd then have to have something which polls the queue and sends out the notifications i.e. Scheduled Task, Windows service etc. IIRC, if IIS recycles during a task, the process is killed whereas with QueueBackgroundWorkItem there is a grace period for which ASP.Net will let the work item finish it's job.
I would take a look on Hangfire. It is fairly easy to setup, it should be able to run within your ASP.NET process and is easy to migrate to a standalone process in case your IIS load suddenly increases.
I experimented with Hangfire a while ago but in standalone mode. It has enough docs and easy to understand API.

Triggering an async operation in from mvc controller

Here is my scenario.
I want to create a web endpoint that will kick off a service that may be long-running, perhaps 20-30 minutes. I'd like to return an HttpResponseResult immediately and trigger the service to run asynchronously, instead of having to wait for the service to complete before returning a response to client.
What is the easiest way to go about doing this? I don't need to return any sort of result from the service, just trigger it.
Just run a task using Task.Run(() => <trigger service call> ) and ignore the return value. The only down side of this is that it will consume a thread from the thread pool. If the service has an asynchronous version of the operation you are calling you can use a TaskCompletionSource
SignalR will be my choice to do this kind of behavior. Tutorial is here.
Basically, a client invokes a server method/action and is 'done' (you can continue and do whatever y you want in the client side). Once the server is done it pushes data/notification to client via RPC.
On the server side you can execute the code anyway you like, synchronously or async.

Categories

Resources