Nullreference exception does not show up when async Task discarded - asynchronous

I have an async Task with a method signature defined like this:
public async Task<bool> HandleFooAsync()
When executing this task in an async way and discarding the results, exceptions happening in this task do not show up in our logs.
_ = _slackResponseService.HandleFooAsync();
When I await the execution of the task I see the error in our logs
var result = await _slackResponseService.HandleFooAsync();
Is this expected behaviour? Is there a way to achieve a solution in between: "do not wait for the result, but log errors nevertheless.." ? We invested hours debugging our logging setup, just to learn that our logging setup is correct, but discard means in dotnet that everything is discarded - even logs. Which is a quite a new perspective for us, coming from a Python background.
Our logging setup follows the default logging setup for dotnet core 3 https://learn.microsoft.com/en-us/aspnet/core/fundamentals/logging/?view=aspnetcore-3.1

Yes, it is an expected behavior. Call in that way can be considered like an anti-pattern. You can read about it C# Async Antipatterns
You need something which is called as "Fire and forget". One of its implementation can be find in repo AsyncAwaitBestPractices (nuget available too).

A Task in .net and netcore is meant to be awaited. If it is not awaited, the scope might be destroyed before the async method has finished.
If you want to run tasks in the background and not wait for a result you can use BackgroundService in .netcore or a third party such as Hangfire which supports fire and forget jobs out of the box
https://medium.com/#daniel.sagita/backgroundservice-for-a-long-running-work-3debe8f8d25b
https://www.hangfire.io/

One solution is to subscribe to the TaskScheduler.UnobservedTaskException event. It is not ideal because the event is raised when the faulted Task is garbage collected, which may happen long after the actual fault.
Another solution could be to use an extension method every time a task is fired and forgotten. Like this:
_slackResponseService.HandleFooAsync().FireAndForget();
Here is a basic implementation of the FireAndForget method:
public async static void FireAndForget(this Task task)
{
try
{
await task;
}
catch (Exception ex)
{
// log the exception here
}
}

Related

dotnet console app, using generic host, HostedService, Windows Task Scheduler stays in running state

Trying to figure out why my console app won't stop running.
Using the following approach in a dotnet core application main method:
await new HostBuilder().
...
.ConfigureServices((hostContext, services) =>
{
services.AddHostedService<MyHostedService>();
})
.UseConsoleLifetime()
.Build()
.RunAsync();
Publishing and scheduling that task from the Windows Task Scheduler using the following settings works:
All good so far. All code is properly executed. However, the task stays running, the process never ends. (not even after pressing refresh on the UI of the task scheduler)
Is this expected? If not, how do I get the process to terminate?
If expected, does it still make sense then, to use Generic Host / Hosted Service in a scheduled console app that just starts, runs, and stops?
Answer based on Microsoft.Extensions.Hosting 2.2.0
This behavior is expected, due to your usage of the Generic Host:
It keeps running until shut down or disposed, and you have no shutdown mechanism in place. I assume you expect the Generic Host to shut down after IHostedService.StartAsync(CancellationToken) of your MyHostedService ran to completion. This is not the case, because there might be other IHostedService implementations registered and executed in sequence, and/or a long running BackgroundService which returns control when its ExecuteAsync(CancellationToken) is not completing synchronously to allow other services to run in parallel.
To stop your application gracefully after your MyHostedService completes when running the host via RunAsync, you should constructor-inject the IApplicationLifetime into your MyHostedService and call StopApplication after your Task has completed.
internal class MyHostedService : IHostedService
{
private readonly IApplicationLifetime _appLifetime;
public MyHostedService(IApplicationLifetime appLifetime)
{
_appLifetime = appLifetime;
}
public async Task StartAsync(CancellationToken cancellationToken)
{
await Task.Delay(1000); //your scheduled work
_appLifetime.StopApplication();
}
public Task StopAsync(CancellationToken cancellationToken)
{
return Task.CompletedTask;
}
}
Also, the application may be stopped via either AppDomain.CurrentDomain.ProcessExit or Console.CancelKeyPress, both events are subscribed to by the ConsoleLifetime, which is pre-registered as the default lifetime implementation.
You can read more about lifetime management in the docs.
Microsoft.Extensions.Hosting 3.0.0 - currently in preview - marked IApplicationLifetime obsolete and recommends using IHostApplicationLifetime instead

SignalR just terminate single long running task among many within a specific client

I have been searching for right methodology to achieve this scenario without any luck.
This is regarding multiple long running tasks to a specific client, let's say there has been three tasks running in single client asynchronously at time t0, t1 and t2.
Clients.Client(TheConnectionID).Task1(GUID1) //at t0
Clients.Client(TheConnectionID).Task1(GUID2) //at t1
Clients.Client(TheConnectionID).Task1(GUID3) //at t2
Later, from server(Hub) user's request was sent to Task started running from t1.
Server know the GUID sent for the Task1 started at t1.
Clients.Client(TheConnectionID).Cancel(GUID2) //To cancel task started at t1
I tried to pair the GUID with CancellationToken and somehow throw operation cancelled exception with no luck. Somehow the thread where the exception thrown seems not the correct thread where t1 Task is running..
Please someone shed me light what I am doing wrong or if this is never possible with signalr invoke methods on client side.
Answering my own question seems awkward but I think this could be valuable to whom in similar situation. Also this solution with my observations could bring further discussion shedding some light.
Here is what I have found:
Based on the invoke of user request:
Clients.Client(TheConnectionID).Cancel(GUID)
You can do a handling of cancellation routine per the specific task in the client side:
try
{
concurrentCTSDictionary.TryGetValue(GUID, out CancellationTokenSource cts);
cts.Cancel();
}
The actual event handler, which was running task and token fed:
async Task SomeMethodUserWantCancel([]args, CancellationToken ct)
{
// Option #1 or #2
}
Now here is what gets a little strange,
When I used option #1, the thread containing throwing exception was not running on the same thread where actual task was running and task kept running even when exception thrown. That's why I posted question to stackoverflow.
Option #1:
using (var ctr = ct.Register(async () =>
{
ct.ThrowIfCancellationRequested();
}))
{
while (longtaskrunning)
{
await longTask();
}
}
Option #2 worked and solved my issue:
while (longtaskrunning)
{
ct.ThrowIfCancellationRequested();
await longTask();
}

Cosmo ChangeFeed -Errors,exceptions and Service fail scenario's

All,
I am using Change Feed Processor Library.Want to know the best way to handle service failure along with the exceptions/errors scenario's in ProcessChangesAsync method. Below are the events am referring to.
1) Service failure - Service having the processor library crashed in the middle of some operation. How to start the process from the same document(doc on failure instance)? is there any inbuilt mechanism where change feed will start with the last failed documents? E.g. Let assume,in current batch we have 10 docs.5 processed successfully and then service breaks because of network failure or by some other reasons.Will my process starts with 6th document once service is re-started? How to achieve this?
2) Exception and Errors- Any errors in ProcessChangesAsync method can be handle using try catch at the global level but how to persist those failure records and make them available for the next batch? Again,looking for any available inbuilt mechanism in change feed process.
1) The Processor Library, by default, checkpoints after a successful run of ProcessChangesAsync. In the latest library version, you can customize the Checkpointer to do manual checkpoints in case you need it. If for some reason the processor shuts down before checkpointing, then it will start processing next from the the last successful checkpoint stored in the Leases collection. In your case, it will start with the first document again, so you will never lose a change but you could experience double processing (this is an "at least once" model).
2) There is no built-in mechanism that you can leverage, handling exceptions within the ProcessChangesAsync is your responsibility. You could not only add a global try/catch but, in the case you are looping over the documents, add a try/catch inside the loop, to handle a failing document (maybe send it to queue for later analysis/post-process) without losing the batch. If you require logging for those errors (I'm assuming that's what you mean by persisting errors?), then the latest version is compatible with LibLog, so plugging your own custom logging is as simple as:
using Microsoft.Azure.Documents.ChangeFeedProcessor.Logging;
var hostName = "SampleHost";
var tracelogProvider = new TraceLogProvider(); //You can use any provider supported by LibLog
using (tracelogProvider.OpenNestedContext(hostName))
{
LogProvider.SetCurrentLogProvider(tracelogProvider);
// After this, create IChangeFeedProcessor instance and start/stop it.
}
Source
Extra info for the comments
To avoid exceptions halting the batch or causing a batch to be reprocessed, you can have handling like this:
public async Task ProcessChangesAsync(IChangeFeedObserverContext context, IReadOnlyList<Document> documents, CancellationToken cancellationToken)
{
try
{
foreach(var document in documents)
{
try
{
// Do your work for the document
}
catch(Exception ex)
{
// Something happened with the current document, handle it, send it to a queue / another storage to analyze, log it. This catch will make the loop continue with the next.
}
}
}
catch(Exception ex)
{
// Something unhandled happened, log it and avoid throwing it again so the next batch is processed
}
}

ASP.Net Web Service: Running code Asynchronously

I have a web service that can be broken down into two main sections:
[WebMethod]
MyServiceCall()
{
//Do stuff the client cares about
//Do stuff I care about
}
What I'd like to do is run that 2nd part on another thread, so that the client isn't waiting on it: once the user's logic has completed, send them their information immediately, but continue processing the stuff I care about (logging, etc).
From a web service, what is the recommended way of running that 2nd piece asynchronously, to get the user back their information as quickly as possible? BackgroundWorker? QueueUserWorkItem?
You may want to look into Tasks which are new to .NET 4.0.
It lets you kick off an asynchronous operation, but also gives you an easy way to see if it's done or not later.
var task = Task.Factory.StartNew(() => DoSomeWork());
It'll kick off DoSomeWork() and continue without waiting so you can continue doing your other processing. When you get to the point where you don't want to process anymore until your asynchronous task has finished, you can call:
task.Wait();
Which will wait there until the task has completed. If you want to get a result back from the task, you can do this:
var task = Task.Factory.StartNew(() =>
{
Thread.Sleep(3000);
return "dummy value";
});
Console.WriteLine(task.Result);
A call to task.Result blocks until the result is available.
Here's a tutorial that covers Tasks in greater detail: http://www.codethinked.com/net-40-and-systemthreadingtasks
The easiest way to fire off a new thread is probably:
new Thread(() =>
{
/// do whatever you want here
}).Start();
Be careful, though - if the service is hit very frequently, you could wind up creating a lot of threads that block each other.

ASP.NET CacheDependency out of ThreadPool

In an async http handler, we add items to the ASP.NET cache, with dependencies on some files. If the async method executes on a thread from the ThreadPool, all is fine:
AsyncResult result = new AsyncResult(context, cb, extraData);
ThreadPool.QueueUserWorkItem(new WaitCallBack(DoProcessRequest), result);
But as soon as we try to execute on a thread out of the ThreadPool:
AsyncResult result = new AsyncResult(context, cb, extraData);
Runner runner = new Runner(result);
Thread thread = new Thread(new ThreadStart(runner.Run());
... where Runner.Run just invokes DoProcessRequest,
The dependencies do trigger right after the thread exits. I.e. the items are immediately removed from the cache, the reason being the dependencies.
We want to use an out-of-pool thread because the processing might take a long time.
So obviously something's missing when we create the thread. We might need to propagate the call context, the http context...
Has anybody already encountered that issue?
Note: off-the-shelf custom threadpools probably solve this. Writing our own threadpool is probably a bad idea (think NIH syndrom). Yet I'd like to understand this in details, though.
Could not figure out the details...
Found a workaround, though: in most IAsyncResult implementation, once the operation is completed there is a direct call to the callback. We replaced this, and now queue the callback into the ThreadPool. Hence, the callback executes within the ThreadPool and can register dependencies that last.

Resources