Trouble catching exception on Azure Service Bus SendAsync method - c#

I'm trying to use the following code to setup a failure condition, namely were there is no network path available, so the code shouldn't be able to send to the Service bus at all. I know this because I disable my network ports when I test.
I am still having trouble with the Async nature of the code though. I don't know in a console application like I have how to attach something that would log out the exception that I know should be generated.
How do I see that exception text?
public async Task TestQueueExists()
{
_queueClient = new QueueClient(AppSettings.McasServiceBusConnectionString,
AppSettings.ListServSyncQueueName);
Logger.Information(
$"Queue Created to: {_queueClient.QueueName} with RecieveMode: {_queueClient.ReceiveMode}");
try
{
await _queueClient.SendAsync(new Message("Test".ToUtf8Bytes()));
}
catch (Exception e)
{
Console.WriteLine(e);
throw;
}
}

According to your code, I assumed that you are using the Azure Service Bus .NET Standard client library Microsoft.Azure.ServiceBus. Per my test, you could leverage the following code to capture the exception as follows:
try
{
await _queueClient
.SendAsync(new Message(Encoding.UTF8.GetBytes("hello world")))
.ContinueWith(t =>
{
Console.WriteLine(t.Status + "," + t.IsFaulted + "," + t.Exception.InnerException);
}, TaskContinuationOptions.OnlyOnFaulted);
Console.WriteLine("Done");
}
catch (Exception e)
{
Console.WriteLine(e);
}
If the network is break, you may capture the exception as follows:

The issue I ran into was that I was using a Console application and the Console app runs sync out of the box. I had to modify my Main to return a Task and use async for the exception to be caught, which makes sense.
ie
internal class Program
{
static async Task Main(string[] args)
{
[..]
}
}

Related

How should a service exit to prevent an error?

I'm developing a Windows service in C#, .NET 6.0 following the instructions on https://learn.microsoft.com/en-us/dotnet/core/extensions/windows-service The service runs as expected, but when I stop the service, it logs an error
A task was canceled.
Exception:
System.Threading.Tasks.TaskCanceledException: A task was canceled.
at AWLService.WindowsBackgroundService.ExecuteAsync(CancellationToken stoppingToken) in C:\Minerva\Projects\AWLService_Test\WindowsBackgroundService.cs:line 22
The ExecuteAsync for this program is as follows:
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
try
{
while (!stoppingToken.IsCancellationRequested)
{
string joke = _jokeService.GetJoke();
_logger.LogWarning("{Joke}", joke);
await Task.Delay(TimeSpan.FromMinutes(1), stoppingToken);
}
}
catch (Exception ex)
{
_logger.LogError(ex, "{Message}", ex.Message);
// Terminates this process and returns an exit code to the operating system.
// This is required to avoid the 'BackgroundServiceExceptionBehavior', which
// performs one of two scenarios:
// 1. When set to "Ignore": will do nothing at all, errors cause zombie services.
// 2. When set to "StopHost": will cleanly stop the host, and log errors.
//
// In order for the Windows Service Management system to leverage configured
// recovery options, we need to terminate the process with a non-zero exit code.
Environment.Exit(1);
}
}
I've tried catching TaskCanceledException. When I do that and add Environment.Exit(0), I still get the error. If I take out Environment.Exit, the service terminates without an error, but it logs "Service stopped successfully" twice.
What is the proper way I should be ending my service?
Thank you.
EDIT:
I added a handler for TaskCanceledException as follows:
catch (TaskCanceledException ex)
{
//Do nothing, we're exiting normally.
Environment.Exit(0);
}
When I do that, stopping the service through MMC shows an error "Error 1067: The process terminated unexpectedly" and a message is not logged indicating the service was stopped. Stopping it with sc on the command line doesn't show an error, but it also doesn't log a message that the service was stopped.
If I remove the Environment.Exit(0) line, MMC no longer shows an error, but the "Service stopped successfully" log message is written twice.
Catch the OperationCancelledException and log something different to the console in the handler. I suspect in your original handler (not shown) you were still probably doing this: _logger.LogError(ex, "{Message}", ex.Message);
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
try
{
while (!stoppingToken.IsCancellationRequested)
{
string joke = _jokeService.GetJoke();
_logger.LogWarning("{Joke}", joke);
await Task.Delay(TimeSpan.FromMinutes(1), stoppingToken);
}
}
catch (OperationCancelledException)
{
_logger.LogInformation("The service has stopped");
Environment.Exit(0);
}
catch (Exception ex)
{
_logger.LogError(ex, "{Message}", ex.Message);
}
}

Logging exceptions in fire&forget tasks

I try to start some action in background, I am not interested in its result, but in case of an error I'd like to log it, and - of course - prevent the application (here: a Windows service) from crashing.
public static void CreateAndStartTaskWithErrorLogging(Action _action, string _componentName, string _originalStacktrace = null)
{
DateTime started = HighPrecisionClock.Now;
Task task = new Task(_action);
task.ContinueWith(_continuation => _continuation.LogExceptions(_componentName, started, _originalStacktrace));
task.ConfigureAwait(false);
task.Start();
}
internal static void LogExceptions(this Task _t, string _componentName, DateTime _started, string _originalStacktrace = null)
{
try
{
_t.Wait(1000);
}
catch (Exception ex)
{
Logger.LogError(_componentName, $"An exception occurred in a fire-and-forget task which was started at {_started}.\r\n" +
$"The original stack trace is:\r\n{_originalStacktrace}");
Logger.LogException(_componentName, ex);
}
try
{
_t.Dispose();
}
catch (Exception dex)
{
Logger.LogException(_componentName, dex);
}
}
Without ConfigureAwait(false) and without _t.Dispose(), the catch works and logs the exception. But the application crashes several seconds later (i.e. on the Finalizer thread?). The entry in the Microsoft Event Viewer shows that exception.
With ConfigureAwait and _t.Dispose(), I do not see the exception in the logs, the application just crashes.
What's wrong with the idea shown above?
Edit:
Meanwhile I tested without ConfigureAwait but with _t.Dispose. I could catch about 10 such exceptions, and none made the application crash. That seems to solve the issue, but I do not understand the reason for that, so the situation is still bad.
What does ConfigureAwait(false) do to Exceptions in the task (or in tasks started within that task, e.g. by a Parallel.ForEach further down)?
Why does the Dispose - which is called on the continuation, not the task proper according to a comment - prevent the crash (the Finalizer does not call Dispose, but Dispose may set some flags influencing its behavior)?
Edit 2:
Also that does not work all the time, only most of the time. Suggested solution 1 below also fails sometimes.
In the crashing context, the function is called with Utilities.TaskExtensions.CreateAndStartTaskWithErrorLogging(() => DataStore.StoreSyncedData(data), Name);, where DataStore is set to a composite which in turn calls Parallel.ForEach(m_InnerDataStores, _store => { _store.StoreSyncedData(_syncedData); }); on its members. One of them writes a video with the Accord library, which sometimes causes an AccessViolation at <Module>.avcodec_encode_video2(libffmpeg.AVCodecContext*, libffmpeg.AVPacket*, libffmpeg.AVFrame*, Int32*), i.e. the exception may come from non-managed code.
Of course, I could try to catch it somewhere down there - but that's not the objective of this method. I expect it to be able to safely run any code in the background without crashing the application.
This is my suggestion for logging errors:
public static void OnExceptionLogError(this Task task, string message)
{
task.ContinueWith(t =>
{
// Log t.Exception
}, TaskContinuationOptions.OnlyOnFaulted | TaskContinuationOptions.ExecuteSynchronously);
}
Usage example:
var task = Task.Run(action);
task.OnExceptionLogError("Oops!");
try
{
await task;
}
catch
{
// No need to log exception here
}

How can I catch the exceptions In Asp.net core that happen In thread

There are some tasks that I attached an action to. I have a middleware for observing all of the exceptions. Now, there is a problem with thread exception. I've already thrown an exception manually in body of the action, but when I throw an exception the application goes to break mode state and I can't monitor the exceptions.
Before mvc in configure, I put my error handling middleware
public class ErrorHandlingMiddleware
{
private readonly RequestDelegate next;
public ErrorHandlingMiddleware(RequestDelegate next)
{
this.next = next;
}
public async Task Invoke(HttpContext context /* other dependencies */)
{
try
{
await next(context);
}
catch (Exception ex)
{
await HandleExceptionAsync(context, ex);
}
}
private static Task HandleExceptionAsync(HttpContext context, Exception exception)
{
var code = HttpStatusCode.InternalServerError;
var result = JsonConvert.SerializeObject(new { error = exception.Message });
context.Response.ContentType = "application/json";
context.Response.StatusCode = (int)code;
return context.Response.WriteAsync(result);
}
}
//and this is the piece of code that run all tasks.
foreach (var item in BotList)
{
BotHandler BotObject = new BotHandler(item,conn);
Task.Run(() => { BotObject.Run();});
}
//
public void Run()
{
//BotClient.StopReceiving();
BotClient.OnMessage += BotOnMessageReceived;
BotClient.OnMessageEdited += BotOnMessageReceived;
BotClient.OnCallbackQuery += BotOnCallbackQueryReceived;
}
private async void BotOnMessageReceived(object sender, MessageEventArgs messageEventArgs)
{
try
{
//do something
string a = null;
var b = a.ToString();
}
catch(Exception exp )
{
throw exp
}
}
}
As I understood you run this code in action of controller:
//and this is the piece of code that run all tasks.
foreach (var item in BotList)
{
BotHandler BotObject = new BotHandler(item,conn);
Task.Run(() => { BotObject.Run();});
}
The main problem is that you are trying to run the task for an already finished request. That is why ExceptionHandlingMiddleware (and actually other middlewares) can't handle anything. To fix your issue you can add try/catch block to handle an unexpected exception.
I would strongly advise not to start a background task during an HTTP request. It's error-prone approach as a task may shut down at any time and you won't even notice. Instead of this approach, it's better to use background task (msdn, SO Discussion), some kind of AWS lambda/Azure function or another task scheduler.
In case you need to do some recalculation job after HTTP method is called you may consider async message processing to trigger the process.
if you go here https://msdn.microsoft.com/en-us/magazine/jj991977.aspx you will read that.
Exceptions from an Async Void Method Can’t Be Caught with Catch
So you cannot catch exception (the middleware cannot) which you are throwing in your BotOnMessageReceived method (in a Catch part).
So you have 2 solutions.
Remove async keyword
Or Catch app unhandled exceptions if its possible. For example in normal .net framework console app, you have event in App called unhandled exceptions, and can handle such situations like yours.
I have also found smth here, maybe it will help
How do I catch unhandled exceptions in ASP .NET Core 2.0 before the page is rendered?

thread is dead priority cannot be accessed

I'm developing an application using some multithreading.
I have a thread that produces some data each 200ms (vibration data from an acquisition device). And each time i reacieve the data I start several tasks to do stuff. On my development PC there is no error. But when I deploy the project on a less powerful tablet I have the following message appearing several times :
thread is dead. priority cannot be accessed.
Here is my code :
private void myCallback1Axis(IAsyncResult ar)
{
GC.Collect();
try
{
if (runningTask == ar.AsyncState)
{
data = reader.EndReadWaveform(ar); // GET THE DATA
// LAUNCH FFTs' THREADS
CancellationToken ct = cts.Token;
task1 = System.Threading.Tasks.Task.Factory.StartNew(() =>
{
try
{
if (ct.IsCancellationRequested)
{
Console.WriteLine("Task {0}: Cancelling", task1.Id);
return;
}
Console.WriteLine("Task {0}: {1}/2 In progress", task1.Id, 1);
ConsumeToFFT(new FFT_Parameters(data.GetRawData(), overlap1, (int)Fmax1,
NbLines1, HP, avg1, window1, switchFreqUnit1.Value, swVelo.Value));
}
catch (OperationCanceledException)
{
// Any clean up code goes here.
Console.WriteLine("Task {0}: Cancelling", task1.Id);
//throw; // To ensure that the calling code knows the task was cancelled.
}
catch (Exception)
{
// Clean up other stuff
//throw; // If the calling code also needs to know.
}
}, ct);
}
catch (DaqException ex)
{
MessageBox.Show(ex.Message);
runningTask = null;
myTask.Dispose();
}
}
I read that I have to :
Put threads into background before starting (here)
But nothing more. I'm stuck with those messages and I can not trace them. Any ideas how can I fix this?
Thank you very much.
(I'm using c#, visual studio, .net 4.0)
Actually I was not able to trace the error, and by a certain miracle it's not there any more. The only thing that I've changed is here :
BlockingCollection<double[]> flowData = new BlockingCollection<double[]>(1);
Declaring my data as BlockingCollection and then use it like that in my consumer :
double[] dataToProcess = flowData.Take();
and like that in my producer :
flowData.TryAdd(data.GetRawData());
I think that the fact that my data was not protected against thread race condition generated the error. Even if I am not using any Thread Priority in my code, having better protection of my shared data was the solution to get rid of my error.
Sorry guys, it's not the greatest explanation but at least I don't have the error anymore. Thank you for your help.

How to catch errors from worker threads in console application written in C#

I currently have a small console application that runs a number of Tasks (using Parallel.ForEach) and each one of these tasks creates sub-threads using ThreadPool.QueueUserWorkItem.
I would like the application to handle any exception thrown by these tasks/threads.
Will surrounding the Parallel.ForEach statement with try..catch work if the threads throw any errors or will they just die out?
EDIT: These sub-threads simulate users of the system. Refer to this question.
Surrounding the statement will not do the job. You can do something like this:
public static void Main(string[] args)
{
string[] files = System.IO.Directory.GetFiles(#".", "*.*");
Parallel.ForEach(files, x =>
{
try
{
MyAction(x);
}
catch(Exception ex)
{
Console.WriteLine(ex.ToString());
}
});
}
static void MyAction(string x)
{
throw new ApplicationException("Testing: " + x);
}
Don't use QUWI. I have a brief comparison of background task types on my blog (Task, BackgroundWorker, Delegate.BeginInvoke, ThreadPool.QueueUserWorkItem, and Thread).
For background tasks, Task is the clear winner. QueueUserWorkItem is very low-level by comparison.
In particular, your problem is error propogation, and Task has built-in support for this that is entirely lacking in QueueUserWorkItem. You could build it in yourself by wrapping your delegate in a try/catch, storing the exception as part of the delegate argument (or as a bound variable of a lambda expression), explicitly checking it later, and doing some technically unsupported reflection to preserve the stack trace.
But why bother? Task supports error propogation out of the box.
you can handle all exceptions with try/catch, for example:
try
{
MyParallelMethod();
}
catch(Exception e)
{
//...
}
and in your method, do something like that:
public void MyParallelMethod()
{
var data = new List<String>();
//...
Parallel.ForEach(data, d =>
{
try
{
//...
}
catch (Exception e)
{
//...
}
});
}
Will surrounding the Parallel.ForEach statement with try..catch work if the threads throw any errors or will they just die out?
No, you need to put try/catch inside the sub threads.
Error handling must be implemented in the task itself (the job each ). You need to make sure the task you are creating handles the exception.
Parallel.ForEach will not handle it for you since the exception will be raised not in the thread which is calling the Parallel.ForEach.
Alternative is to use Task<T>.

Categories