EventHub send message, but System.Net.Sockets.SocketException on Application Insights - c#

I have this code below that sends message to azure EventHub, at first it works fine
public async Task SendMessage(string message) {
var producer = new EventHubProducerClient(this.connectionString, this.eventHubName);
using (EventDataBatch eventBatch = await producer.CreateBatchAsync()) {
if (!eventBatch.TryAdd(new EventData(message))) {
throw new Exception($"Event is too large for the batch and cannot be sent.");
}
try {
await producer.SendAsync(eventBatch);
}
catch(Exception ex) {
saveLog(message, ex);
}
finally {
await producer.DisposeAsync();
}
}
}
but in Application Insights I'm facing this message exception:
A Task's exception(s) were not observed either by Waiting on the Task
or accessing its Exception property. As a result, the unobserved
exception was rethrown by the finalizer thread. A connection attempt
failed because the connected party did not properly respond after a
period of time, or established connection failed because connected
host has failed to respond
Exception type:
System.Net.Sockets.SocketException
I've tried to add a ContinueWith (OnlyOnFaulted or OnlyOnCanceled), as below, to log it,
but now I get in the catch Exception (not in ExceptionHandle ) as "A task was canceled"
try {
await producer.SendAsync(eventBatch)
.ContinueWith(t => ExceptionHandle(t, message), TaskContinuationOptions.OnlyOnFaulted);
}
How can I handle these exceptions that App Insights display?

If you need to handle the task exception by using a ContinueWith (OnlyOnFaulted or OnlyOnCanceled) we can get this exception in catch block only. By default, if the task runs successfully, it throws Exception if the Task IsFaulted we can get the exception from Catch Block.
To fix this issue:
Use UnobservedTaskException event which observe the Task Exceptions and it doesn't terminate by default. The exception can be handled by the runtime.

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);
}
}

Why does a synchronous .NET Core CAP subscriber cause an exception and for the catch block not to be hit?

Note: This poor behavior only occurs if I make the CAP subscriber method synchronous. If it's async (async Task in the method signature), no exception occurs.
When using .NET Core CAP to get messages off a RabbitMQ, an exception occurs in our repo metho, and the catch block of the event handler never gets hit.
[CapSubscribe(nameof(IntegrationEvent))]
public void Handle(IntegrationEvent integrationEvent)
{
_logger.LogInformation("some message");
// Wrap in try/catch, otherwise retries will kick in. If the recalc fails, it's usually due to bad data.
try
{
_recalcProcessor.RecalcByPolicyAsync(integrationEvent.RecalculationDate, integrationEvent.EmployeeId,
integrationEvent.PolicyId);
}
catch (Exception ex)
{
// THIS DOESN'T GET HIT UNLESS THE METHOD IS ASYNC
_logger.LogError(ex, "some message");
}
}
And here is RecalcByPolicyAsync, that is basically just a pass-through to the repo method:
public async Task RecalcByPolicyAsync(DateTime recalcFromDate, long employeeId, long policyId)
{
List<AccrualGroup> groups;
using (var uow = _uowFactory.Create(false))
{
groups = await uow.AccrualRepo.GetAccrualGroupsByPolicyIdAsync(policyId);
}
}
This is the line that produces the exception in the repo method. Remember, this exception doesn't happen if the event handler is async.
_ = await Connection.QueryAsync<DomainEntity1, DomainEntity2>(...
This is the exception:
System.InvalidOperationException: 'Invalid attempt to call FieldCount
when reader is closed.' This exception was originally thrown at this
call stack: [External Code]
Xxx.Shared.Infrastructure.Repositories.AccrualRepo.GetAccrualGroupsByPolicyIdAsync(long)
in AccrualRepo.cs
When the exception occurs, no catch blocks are hit on the way back up the call stack. The process seems to end and that's it. Why would that happen just by making the handler synchronous?
If the handler is async, like this, things just work:
public async Task Handle(RecalcEmployeeAccrualPolicyIntegrationEvent integrationEvent)
However, we don't want to process our event messages async because they happen all at once and we exhaust our SQL connections.

System.OperationCanceledException occurs occassionally in async function with try catch

All,
I have a production ASP.NET core 2.2 application managing websockets connections. Very occasionally we get exception unhandled errors inside a try catch block if a client resets the connection during transmission, which should be a condition we can handle in code (we disconnect the client).
The try catch block in the code below isn't catching the occasional client disconnect / resets as the error is in CoreLib.dll not the C# code, I suspect it might have to do with not setting up async function correctly??
Any ideas what is causing it, and how to work around it?
// Process web sockets request
private static async Task<bool> ReceiveBin(MQTT.Broker myClient, CancellationToken ct = default(CancellationToken))
{
var buffer = new ArraySegment<byte>(new byte[RECV_BUFF_SIZE]);
using (var ms = new MemoryStream())
{
WebSocketReceiveResult result = null;
try
{
do
{
ct.ThrowIfCancellationRequested();
result = await myClient.socket.ReceiveAsync(buffer, ct); <== Unhandled exception breaks here
ms.Write(buffer.Array, buffer.Offset, result.Count);
}
while (!result.EndOfMessage);
}
catch (Exception ex) // v1 ASP Core sometimes throw errors when client aborts session
{
CloseWSSess(myClient, "Error receiving from client - resetting session. Error: " + ex.Message);
return false;
}
...
Error from the await statement => An exception of type 'System.OperationCanceledException' occurred in System.Private.CoreLib.dll and wasn't handled before a managed/native boundary

Task continue with not working upon exception

I am in a strange situation, I am using task and continue with upon faulted i am calling one method to process upon faulted or success but the function does not get fired.
Below is my code but upon expcetion it does not executes the UdpateResult method, what I am missing here.
var task = new Task.Factory.StartNew(SomeMethod());
task.ContinueWith(
t1 => Handler.UpdateResult(t1.Result, t1.Exception),
TaskContinuationOptions.ExecuteSynchronously);
try
{
task.Wait();
}
catch (AggregateException exception)
{
foreach (var innerException in exception.Flatten().InnerExceptions)
{
if (innerException is InvalidOperationException)
{
throw innerException;
}
throw new InvalidOperationException(string.Empty, innerException);
}
}
You're trying to use t1.Result within your continuation. If t1 has faulted, then accessing t1.Result will itself throw an exception.
You either need a single continuation which can handle any kind of end result, or you should attach different continuations for success and failure cases.

Task Parallel Library and exception

I have an application that are executing 4 different jobs parallel. I use the parallel task library.
The code looks like this:
while (true)
{
var fetch = new FetcherHandler();
var tasks = new Task[4];
tasks[0] = Task.Factory.StartNew(fetch.GetJobs);
tasks[1] = Task.Factory.StartNew(fetch.GetStatusNew);
tasks[2] = Task.Factory.StartNew(fetch.GetJobsForStatus);
tasks[3] = Task.Factory.StartNew(fetch.GetStatusOld);
Task.WaitAll(tasks);
Thread.Sleep(10000);
}
The thread.Sleep above will never be reached since all these 4 tasks is in a never ending loop. Code example for the first task:
public void GetJobs()
{
while (true)
{
try
{
handler.GetNewJob();
}
catch (Exception exception)
{
var mail = new MailService();
mail.SendExeption("Error has accured in GetJobs", exception);
throw;
}
}
}
Thread.Sleep(15000); }}
The above code works great, it does some jobs and then it sleeps for 15 sec, and then it does it again. The problem occurres when I get an exception.
The exception is caught alright, and sends me an mail, but the thred doesn't continue in the loop after the exception, so the GetNewJob() method will never get executed again.
Any ideas what happens to the thread when exception hits, and how I can "save" the thread so it can continue?
Becasue you throw an exception, so the exception propagates on top of the stack and break execution of the source thread.
catch (Exception exception)
{
var mail = new MailService();
mail.SendExeption("Error has accured in GetJobs", exception);
throw; //THIS LINE !
}
You can use an event to raise it, say, ExceptionCaught(..) and listen for that event inside your program.
Just remove the throw; at the end of your catch clause.
From MSDN:
A throw statement can be used in a catch block to re-throw the
exception that is caught by the catch statement.
So you're rethrowing the caught exception which causes the thread to interrupt, never executing again...
More information: What happens when a .NET thread throws an exception?

Categories