How to create an async/background process within a WCF operation? - c#

In my WCF operations I will do the logic necessary for the operation: save a record, get a dataset, etc. and in some cases I need to log the activity as well. However, in these cases I feel that there is no point in having the client application waiting for the WCF operation to log the activity. I would like to fire off the logging process and then immediately return whatever necessary to the client without waiting for the logging process to complete.
I do not care to know when the logging process is complete, just fire and forget.
I also prefer to use BasicHttpBinding to maintain maximum interoperability.
Is this possible? Would anyone care sharing coding samples or links to sites with coding examples?

This can be accomplished pretty easily using any number of threading techniques.
For a very simple example, try modifying this:
// Log something going on.
System.Threading.ThreadPool.QueueUserWorkItem((args) =>
{
System.Diagnostics.EventLog.WriteEntry("my source", "my logging message");
});
Inside that lambda method you can use whatever logging class you prefer, and you can include local variables to the logger if you want to log some current state.

Related

Will non-awaited async functions definitely attempt finish in ASP.NET Core Web API?

It's my understanding that controllers get destroyed after an http request is made. Is there any assurances that the .NET Core runtime will wait until all threads initiated in an async action have terminated/ended before destroying the controller instance?
I have code below with an async controller action that calls an async function. I don't need to know if the async function actually succeeds or not (e.g. sending the email), I just want to make sure that it attempts to. My fear is that the .NET Core runtime will possibly kill the thread in the middle of execution.
Spoiler alert I ran the code below in my development environment and it does send the email every time (I put a real email). But I don't know if the behavior would change in a production environment.
Any thoughts/guidance?
[HttpGet]
public async Task SendEmail()
{
// If I would prefix this with 'await' the controller
// action doesn't terminate until the async function returns
this.InternalSendEmail();
}
private async Task InternalSendEmail()
{
try
{
await this.Email.Send("to#example.com", "Interesting subject", "Captivating content");
}
catch (Exception exc)
{
Log(exc);
}
}
What happens to the controller instance - nothing you can't manage
First, when we talk about destroying the controller instance let's be more precise. The instance won't get GCd as long as there's still a control flow that has access to this. It can't. So your controller instance will be fine in that regard at least until your private method finishes.
What will happen is your controller method will return and control flow will go to the next stage in the middleware chain, meaning your API consumer will likely get the http response before the email is sent. You will lose your HttpContext and all that goes with it when this happens. Thus if there's anything in your Log method or anything else in InternalSendEmail that relies on the HttpContext you need to make sure that information is extracted and provided to the background method before the controller method returns.
What happens to the thread - almost certainly nothing
As far as the thread goes, most likely the email will be sent on a different thread in the thread pool from that of the original controller method, but either way, no the .NET runtime isn't going to care about your controller method returning before every task it fired off has completed, let alone kill the thread. That's well above its paygrade. Moreover it's very rare for threads to be killed in any instance these days because it's not just your control flow that's affected but completely unrelated async contexts could be dependent on that thread too.
IIS Application Pool recycling and other things that COULD potentially kill your background task
The only reasonably likely thing that would cause your background task not to complete would be if the process terminated. This happens for example during an IIS Application Pool reset (or equivalent if you're using dotnet hosting), obviously a server restart, etc. It can also happen if there's a catastrophic event like running out of memory, or nasty things like memory faults unique to unsafe or native code. But these things would kill all pending HTTP requests too.
I have seen anecdotal assertions that if there are no pending HTTP requests it makes it more likely that IIS will recycle the application pool on its own even if you have other active code running. After many years of maintaining an application that uses a very similar pattern for many non-critical long-running tasks, I have not seen this happen in practice (and we log every application start to a local TXT file so we would know if this were happening). So I am personally skeptical of this, though I welcome someone providing an authoritative source proving me wrong.
That said, we do set the application pool to reset every day at 4 AM, so to the extent that IIS would be inclined to involuntarily reset our app pools (as it does need to happen every now and then) I suspect this helps mitigate that, and would recommend it regardless. We also allow only one CPU process per application, rather than allowing IIS to fire off processes whenever it feels like it; I suspect this also makes it less likely IIS would kill the process involuntarily.
In sum - this is perfectly fine for non-critical tasks
I would not use this for critical tasks where unambiguous acknowledgement of success or failure is needed, such as in life critical applications. But for 99+% of real world applications what you're doing is perfectly fine as long as you account for the things discussed above and have some reasonable level of fault tolerance and failsafes in place, which the fact that you're logging the exception shows you clearly do.
PS - If you're interested in having robust progress reporting and you aren't familiar with it, I would look into SignalR, which would allow you to notify the client of a successful email send (or anything else) even after the API call returns, and is shockingly easy to use. Plus an open websocket connection would almost certainly prevent IIS from mistaking a returned API method for an opportunity to kill the process.
Is there any assurances that the .NET Core runtime will wait until all threads initiated in an async action have terminated/ended before destroying the controller instance?
No, this is absolutely not guaranteed.
I don't need to know if the async function actually succeeds or not (e.g. sending the email), I just want to make sure that it attempts to. My fear is that the .NET Core runtime will possibly kill the thread in the middle of execution.
You cannot be sure that it will attempt to do so. The thread (and entire process) may be terminated at any time after the HTTP response is sent. In general, request-extrinsic code is not guaranteed to complete.
Some people are fine with losing some work (e.g., in this case, missing some emails). I'm not, so my systems are all built on a basic distributed architecture, as described on my blog.
It's important to note that work can be lost during any shutdown, and shutdowns are normal:
Any rolling upgrade triggers shutdowns (i.e., application updates).
IIS/ASP.NET recycles every 19 hours by default.
Runtime and OS patches require shutdowns.
Cloud hosting causes shutdowns (both at the VM level and higher levels).
Bottom line: shutdowns are normal, and shutdowns cause any currently-running request-extrinsic work to be lost. If you're fine with occasionally losing work, then OK; but if you require an assurance that the work is done, then you'll need a basic distributed architecture (a durable queue with a background processor).
There are more basic control flow issues with that logic what you trying to do. Your biggest problem is not the garantee about it is finished or not.
The example you present is very simple, but in real life example you will need some context in InternalSendEmail when it is executed. Because the request is completely served at the time it is executed, there will not be HttpContext, with all the consequences, for example you can not even log the IP address of the the request, not talking about all the more advanced context bound things like the user (or any other security principal) etc.
Of course you can pass anything as parameter (for example the IP address) but probably your logging infra (or your custom log enricher) will not work with that. Same is true for any other pipeline component which depends on the context.

Is there a pattern or an easy way to cancel a specific run in an Azure WebJob Function

In my multi-tenant application I have a background process that runs in a webjob and can take several minutes. The time varies according to each customer's data.
But sometimes, when I'm testing something, I start the process and (looking at the logs) soon I realize something is wrong and I want to cancel that specific run.
I cannot just kill all the messages in the queue or stop the WebJob, because I'd be killing the processes that are running for the other customers.
And I want to do it programmatically so I can put a Cancel button in my web application.
I was not able to find the best architecture approach (or a pattern) to work with this kind of execution cancellation.
I read about passing a CancellationTokenSource, but I couldn't think of how I would call the Cancel() method on the specific run that I want to cancel. Should I store all currently running tokens in a static class? And then send another message to the webjob telling that I want to cancel it?
(I think that might be the answer, but I'm afraid I'm overthinking. That's why I'm asking it here.)
My Function is as simple as:
public static void EngineProcessQueue([QueueTrigger("job-for-process")] string message, TextWriter log)
{
// Inside this method there is a huge codebase
// and I'm afraid that I'll have to put the "if (token.IsCancelled)" in lots of places...
// (but that's another question)
ProcessQueueMessage(message, log);
}
QueueTrigger is essentially a function trigger. The Cancel you want should not be supported.
Because once the function execution method is entered, the specific business logic code may have asynchronous operations. Assuming that even if we delete or stop the QueueTrigger at this time, business data will be affected and rollback cannot be achieved.
The following is my personal suggestion,
because I think the cancel operation can be improved from the business logic:
Use redis cache, and create a object name of mypools, to store your bussiness command.
When running webjob, we can get all Queue, we also can find in Azure Storage Explore. And we can save it in mypools with specical command.
The format of command should be ClientName-TriggerName-Status-Extend. Such as Acompany-jobforprocess-run-null, when this command has not been executed yet, we can modify it with Acompany-jobforprocess-cancel-null.
We can set Azure WebJob queue name at runtime. Then dynamically handle business in the program.For the executed business, data rollback is performed.

How to correctly invoke big logic in another Thread/Task?

Here is my problem, I got a WCF project, which doesnt really matter in fact because it's more about C#/.NET I believe. In my WCF Service when client is requestinq one of the methods I make the validation of the input, and if it succeeds I start some business logic calculactions. I want to start this logic in another thread/task so after the input validation I can immediately return response. Its something like this:
XXXX MyMethod(MyArgument arg)
{
var validation = _validator.Validate(arg);
if (validation.Succeed)
{
Task.Run(() => businessLogic())
}
return MyResponseModel();
}
I need to make it like this because my buesinessLogic can take long time calculactions and database saves in the end, but client requesting the Service have to know immediately if the model is correct.
In my businessLogic calculactions/saves that will be running in background thread I have to catch exceptions if something fail and save it in database. (its pretty big logic so many exceptions can be thrown, like for example after calculactions im persisting the object in the database so save error can be thrown if database is offline for example)
How to correctly implement/what to use for such a requirements? I am just giving consideration if using Task.Run and invoking all the logic in the action event is a good practice?
You can do it like this.
Be aware, though, that worker processes can exit at any time. In that case outstanding work will simply be lost. Maybe you should queue the work to a message queue instead.
Also, if the task "crashes" you will not be notified in any way. Implement your own error logging.
Also, there is no limit to the number of tasks that you can spawn like this. If processing is too slow more and more work will queue up. This might not at all be a problem if you know that the server will not be overloaded.
It was suggested that Task.Run will use threads and therefore not scale. This is not necessarily so. Usually, the bottleneck of any processing is not the number of threads but the backend resources being used (database, disk, services, ...). Even using hundreds of threads is not in any way likely to be a bottleneck. Async IO is not a way around backend resource constraints.

Correct way to implement a client-call to a long running server-side method

I am working on SOAP-client in WCF to communicate with a self-hosted WCF service for remote controlling a piece of software that I am developing. This software has a very long running operation (lets call it Print) that will run for several minutes, perhaps up to an hour. I am trying to figure out how to implement the method Print given the following requirements:
The server should be able to raise FaultExceptions to the client, in case something goes wrong.
The client should be informed ASAP should the connection to the service be lost.
The server-side process of Print should continue to run if disconnected, so that the client can reconnect and continue to monitor the process and abort it if necessary.
Since I am new to WCF, I am unsure how to implement this. I currently see two alternatives:
Make Print an async method so that I can "fire and forget" it until it finishes or throws a FaultException. This seems straight-forward, but I see this "problem": There is a client-side request timeout in WCF with default value of 1 minute, which also applies to async methods (if I am not mistaken) and which I would therefore have to increase significantly. This seems a bit like a hack.
Implement the async behavior of Print myself by splitting its behavior into a non-async method StartPringing that starts a server-side task for printing and returns directly (or throws an exception in case something goes wrong) and a client-callback method PrintingFinished. I could then use the callback PrintingFinished to signal to the client, when the print-process has finished or a use an additional callback PrintingFailed to send an exceptions in case something goes wrong. This implementation would be "hidden" behind the async method Print, so that it behaves like any other async method that might throw an exception. Here I see the following challenge: I will have to implement the whole exception callback-stuff myself, to handle exceptions that occur after StartPringing has returned (from StartPringing itself I can throw FaultExceptions).
For both cases I will have to work out how to detect, when the connection is servered (which I am currently doing using a ping method on the service) and then somehow get that event to throw an exception from within the method Print. Implementation-wise this seems more aligned with alternative (2), since I need to already implement all the other event handlers for when the print-process finishes or an exception is thrown. However I am unsure how I would implement this for alternative (1).
So which one of the two alternatives is "better". By better I mean the following considerations:
1. Aligned with the "standard" way in WCF for implementing such a long running method.
2. Maintainability and extensibility.
If I should consider any other alternative, I would be grateful for any other suggestion.
For what I understand of your problem I think if you need a real async communication with reliability to use a message queue like MSMQ. You can use it with WCF : https://msdn.microsoft.com/en-us/library/ms789048(v=vs.110).aspx
Update
In your case, you can use a SOAP call to send print command to the server because it sync and you need to know if the server handle the request. After in the printing operation is long and async. When this operation finish (exception or not) it need to notify client(s). But client could be shutdown for example. For that communication a Message Queue is the solution, MQ ensure that the message will be transmit.
https://en.wikipedia.org/wiki/Message_queue
If you don't want use MSMQ, you can implement a web service on client side to be notified by the printing server, using for example a UUID to match call and notification in a map in memory or in a Data Base.

Shutting down a Long-running process in a Windows Service

I have a Windows Service that performs a long-running process. It is triggered by a timer and the entire process can take a few minutes to complete. When the timer elapses the service instantiates a management object that performs the various tasks, logs the results and then exits.
I have not implemented anything to handle those occasions when the server is shutdown during the middle of the process. It could cause some problems. What is the best practice to handle this?
Can only give vague suggestions since I don't know what task you are actually doing.
If it is something to do w/ database, there is transaction that can be rolled back if it is not committed.
If it involves some file manipulation, perhaps take a look at this article on Transactional NTFS. You can use it in combination w/ TransactionScope object to ensure atomic transaction.
If you are dealing with web services, well the service boundary will dictate when one transaction starts / ends and when the other one begins, use compensation model (if you break something on your part, you need to provide a way later on, after recovery, a way to notify / execute compensation scripts on the other end. (Think about ordering book online and how to handle backorder, cancellation, etc.)
For tracking mechanism, log every steps and the timelines for troubleshooting if something like shutdown occurs.
If your describing essentially a batch process its ok to have a timer that does work at an interval - much of the world works that way.
If its long running, try to keep your units of work, or batches, small enough that your process can at least check to see if its been signaled to stop or not. This will allow the service to exit gracefully instead of essentially ignoring the service stop message.
Somewhere in your timer function you have a property, IsShutdownRequired or some such, that your checking (assuming some loop processing). This property is set to true in the service stop control message, which allows your process to gracefully exit by either not trying to do more work, or as Jimmy suggested, rolling back that work if in a transaction.
Ideally, smaller batches would be better than one big one.

Categories