Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Conditionally run the methods of a class on a separate thread

I have a class that saves logging information to the database (in an NServiceBus message Handle method).

Most of the time that logging can be done on a separate thread (and transaction) from the main process. But it all needs to be done on the same background thread (meaning that they have to be done in order, just not in sync with the main process).

However, once it starts Foreign Keying to the actual data from NServiceBus, it needs to be on the same thread.

Here is some example code:

public class MyExample
{

   public void LogSomeStuff(Stuff stuff)
   {
      using (MoveOutsideTransaction())
      {
         // Do Method Stuff here
         dataAccess.SaveChanges();
      }
   }


   public void LogSomeOtherStuff(Stuff stuff)
   {
      using (MoveOutsideTransaction())
      {
         // Do Other Method Stuff here
         dataAccess.SaveChanges();
      }
   }

   private IDisposable MoveOutsideTransaction()
   {
       if (loggingOutsideTransaction)
           return new TransactionScope(TransactionScopeOption.Suppress);

       return null;
   }
}

I am wondering if there is a way to use my transaction conditional to also conditionally move the running to a different thread. (But only when it suppresses the transaction.)

like image 656
Vaccano Avatar asked Nov 04 '22 03:11

Vaccano


1 Answers

I am wondering if there is a way to use my transaction conditional to also conditionally move the running to a different thread.

You cannot just move the execution of a method onto a different thread. Threads do not work that way in general. However, what you can do is setup a dedicated thread that can participate in a marshaling operation which does, more or less anyway, simulate the transfer of execution to another thread. It is important to drive home the point that this dedicated thread must be specially coded to accept this marshaling operation.

Here is how it works.

public class DedicatedThread
{
  private BlockingCollection<Action> actions = new BlockingCollection<Action>();

  public DedicatedThread()
  {
    var thread = new Thread(
      () =>
      {
        while (true)
        {
          Action action = actions.Take();
          action();
        }
      });
  }

  public void SubmitAction(Action action)
  {
    actions.Add(action);
  }
}

And you might use it like this.

if (loggingOutsideTransaction) 
{  
  // Execute asynchronously on a dedicated thread.
  dedicatedThread.SubmitAction(yourActionDelegate); 
}
else
{
  // Execute synchronously.
  yourActionDelegate();
}
like image 147
Brian Gideon Avatar answered Nov 09 '22 06:11

Brian Gideon