What is the best way to use Firstchanceexception in multithreading application?

Asked

Viewed 36 times

2

I have an application (which is a Windows service) that currently runs N Threads. What I want to do is capture whichever error that occurs in the application to write to a log file '.txt'. Only I want to do it so global.

I’m wearing the event FirstChanceException, only that this event executes only by Appdomain and if only to register the event in the main thread of the application, all errors would be recorded in a single file '.txt', causing a lot of competition and etc.

So I thought I’d create several Appdomains (each AppDomain with one of those Threads I have in the app) to capture exceptions of each Thread. I made a test application and it works: at the end I have a log file for each Thread.

Only my doubts are:

  1. Is this the best way to globally capture exceptions in N Threads applications? Would you have another way to do this?
  2. Creating an Appdomain for each Thread will not generate any process overload in S.O.?
  3. If you crash Firstchanceexception, you will get an endless loop of errors. Especially if you write in text file. Would have some Firstchanceexpception alternative?

Research I’ve already done: https://docs.microsoft.com/pt-br/dotnet/framework/app-domains/application-domains?view=netframework-4.8

https://docs.microsoft.com/pt-br/dotnet/api/system.appdomain.firstchanceexception?view=netframework-4.8

https://docs.microsoft.com/pt-br/dotnet/api/system.runtime.loader.assemblyloadcontext?view=netcore-2.2

https://stackoverflow.com/questions/5569580/exceptions-in-multithreaded-application/43934857

Below follows what I did for testing:

public class Program
{

    private static ReaderWriterLockSlim lock_ = new ReaderWriterLockSlim();

    public static void Main(string[] args)
    {
        try
        {

            AppDomain.CurrentDomain.FirstChanceException += (object sender, FirstChanceExceptionEventArgs e) =>
            {
                GravarLog(e.Exception);
            };

            AppDomain domain1 = AppDomain.CreateDomain("Consumidor-1");
            domain1.FirstChanceException += (object sender, FirstChanceExceptionEventArgs e) =>
                        {
                            GravarLog(e.Exception);
                        };

            Consumer consumer1 = (Consumer)domain1.CreateInstanceAndUnwrap(
                                          typeof(Consumer).Assembly.FullName,
                                          typeof(Consumer).FullName);

            consumer1.Iniciar();


            AppDomain domain2 = AppDomain.CreateDomain("Consumidor-2");
            domain2.FirstChanceException += (object source, FirstChanceExceptionEventArgs e) =>
            {
                GravarLog(e.Exception);
            };

            Consumer consumer2 = (Consumer)domain2.CreateInstanceAndUnwrap(
                                          typeof(Consumer).Assembly.FullName,
                                          typeof(Consumer).FullName);

            consumer2.Iniciar();


        }
        catch (Exception ex)
        {
            throw;
        }

        Console.ReadLine();
    }

    private static void GravarLog(Exception exception)
    {

        lock_.EnterWriteLock();
        try
        {
            File.AppendAllText($"D:\\Temp\\Log\\Thread-{Thread.GetDomainID()}-error.txt",
                         DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:ff") + " - " +
                         $@"{AppDomain.CurrentDomain.FriendlyName} -> FirstChanceException: {exception.Message}");
        }
        finally
        {
            lock_.ExitWriteLock();
        }
    }

}

    public class Consumer : MarshalByRefObject
{        
    public void Iniciar()
    {

        var tarefa = new Thread(() =>
        {

            int contador = 1;

            while (true)
            {
                contador++;

                var resultado = VerificarRegras();

                Thread.Sleep(10000);
            }

        });

        tarefa.Start();

    }

    public string VerificarRegras()
    {

        string regraNegocio = "Tudo OK!";

        try
        {
            throw new ArgumentException("Thrown Exception" + Environment.NewLine);
        }
        catch
        {
            regraNegocio = "A validação da regra retornou...";
        }

        return regraNegocio;
    }

}
  • 1

    Because your work of Threads is not managed by a common class, where in this class there are exceptions management? Imagine a class ThreadManager that possesses an object Thread. You can make this class receive one Action, where the constructor class would receive this action. A private function with the name, for example, DoWork() (example) would invoke this Action with a global Try-catch. The log is generated based on the ThreadId. And instead of you spawnar N threads, you spawna N managers thread.

  • You may even have other things to do that might make your solution better, but you could only tell by knowing the case. Why do I wonder why N threads, for example

  • @Kevinkouketsu actually has 42 threads in the app today, but this number can go up. What happens: the application processes messages that were sent by the middleware Rabbitmq. Each Thread is a Consumidor / Assinante of a queue of messages in Rabbitmq, and has the task of receiving and processing each message. In fact each Thread represents a "task/process" to process message. If instead of each thread a process was created, it would have all the operating system scheduling and in the Windows task manager would appear 42 ". exe". So I opted for Threads.

No answers

Browser other questions tagged

You are not signed in. Login or sign up in order to post.