'How to call a method on application crash before objects in DI container are disposed? c#
I have a console application that is running in Kubernetes. I want it to send an event through rabbit when it crashes on unhandled exception.
Here is simplified version of code:
namespace Arbitrage.DustCleaner
{
public class Program
{
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureServices((hostContext, services) =>
{
services.AddRabbit();
services.AddHostedService<DustCleanerService>();
services.AddServiceFaultHandler("peanut-arbitrage-dust-cleaner");
});
}
}
namespace Arbitrage.DustCleaner
{
public class DustCleanerService : BackgroundService
{
private readonly IDustCleaner _dustCleaner;
private readonly ServiceFaultHandler _faultHandler;
private readonly int _waitingTimeMilliseconds;
public DustCleanerService(
ICommandLineOptions<DustCleanerOptions> options,
IDustCleaner dustCleaner,
ServiceFaultHandler faultHandler)
{
_dustCleaner = dustCleaner;
_faultHandler = faultHandler;
var dustCleanerOptions = options.Value;
_waitingTimeMilliseconds = dustCleanerOptions.DustingIntervalInHours * 60 * 60 * 1000;
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
_faultHandler.SetupFaultHandling();
while (!stoppingToken.IsCancellationRequested)
{
await _dustCleaner.ExecuteAsync();
await Task.Delay(_waitingTimeMilliseconds, stoppingToken);
}
}
}
}
namespace Arbitrage.DustCleaner.Domain.Services
{
public class ServiceFaultHandler
{
private readonly IBus _bus;
private readonly string _serviceName;
public ServiceFaultHandler(IBus bus, string serviceName)
{
_bus = bus;
_serviceName = serviceName;
}
public void SetupFaultHandling()
{
AppDomain.CurrentDomain.UnhandledException += CurrentDomainOnUnhandledException;
}
private async void CurrentDomainOnUnhandledException(object sender, UnhandledExceptionEventArgs e)
{
if (!e.IsTerminating)
return;
var failedEvent = new ServiceFailedEvent
{
FailInfo = e.ExceptionObject.ToString(),
ServiceName = _serviceName
};
// _bus here is already disposes
await _bus.PublishAsync(failedEvent);
}
}
}
namespace Arbitrage.DustCleaner.Domain.Services
{
public class CexDustCleaner : IDustCleaner
{
public async Task ExecuteAsync()
{
throw new Exception("Some stupid error");
}
}
}
The problem is that when CurrentDomainOnUnhandledException
is called _bus
object has already beed disposed, so I can't send a message. Solution with try/catch in ExecuteAsync
won't work because some other services contains legacy code
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|