0

I have code that looks like this:

  private void DoWork() {
    try
    {
      MakeCallToServiceWhichCreatesResource();
      UpdateState()
    }
    catch (Exception e)
    {
      UpdateState()
    }
  }

However, there was an issue where when our service had a deployment, it killed threads instantly, without an exception. So the thread was killed in the middle of making a call to the service, which created an issue because the resource that the service call generated was not updated in state, and thus became dangling and wasn't recoverable. I then made a fix to the following:

  private void DoWork() {
    try
    {
      UpdateStateWithOutputInAnticipationOfServiceCall()
      MakeCallToServiceWhichCreatesResource();
    }
    catch (Exception e)
    {
      UpdateStateToRemoveOutput()
    }
  }

This would solve the issue of a thread being killed while the call is being made because the resource could be deleted later (and if the external service call failed, making an unnecessary delete call is acceptable). However, I am looking to add a unit test for this scenario now, but I'm not sure how to simulate total thread obliteration. Using Thread abort doesn't seem to work because it would throw an exception rather than kill immediately, but environment failfast wouldn't seem to work because it would kill the unit test environment as far as I can tell. Any ideas on how to build a unit test that can nuke a thread that runs the code?

Nimish Todi
  • 137
  • 1
  • 11

1 Answers1

0

Regarding how to abort a thread, either silently or loudly, you can take a look at this question. Spoiler alert, neither is possible in the latest .NET platform. If you feel sad about it, you might feel better by learning that the death of Thread.Abort is definitive and irreversible:

Thread.Abort for production scenarios is not going to come back to .NET Core. I am sorry.

Regarding how to improve your code, I would suggest familiarizing yourself with the finally keyword. It helps significantly at simplifying and robustifying the disposal of resources:

private void DoWork()
{
    try
    {
        MakeCallToServiceWhichCreatesResource();
    }
    finally
    {
        UpdateState();
    }
}

Regarding how to prevent your threads from dying silently, one idea is to avoid suppressing the errors in the catch block. The throw is your friend:

private void DoWork()
{
    try
    {
        MakeCallToServiceWhichCreatesResource();
        UpdateState();
    }
    catch (Exception ex)
    {
        UpdateState();
        throw;
    }
}

Now your threads will die loudly, taking down the process with them. This might not be what you want.

One way to find a balance between dying with screams and agony, and dying in total silence, is to use tasks instead of threads. You can offload the DoWork call to the ThreadPool with the Task.Run method, and you'll get back a Task object that represents the result of the execution. You can store this task in a field or in a list of tasks, and periodically inspect its properties like the Status, IsCompleted, IsFaulted, Exception etc to know how is doing. You can also attach continuations to it (ContinueWith), in order to log its completion or whatever. Or you can await it, if you are familiar with async and await. The best part is that if your task fails, the thread on which it runs will not die with it. The thread will return to the ThreadPool, and will be available for future Task.Runs or other work.

Task workTask = Task.Run(() => DoWork());
Theodor Zoulias
  • 34,835
  • 7
  • 69
  • 104