title: How to exit clean from WebAPI background service
body: <p>The code below is a Web API that prints on behalf of a SPA. For brevity I've omitted <code>using</code> statements and the actual printing logic. That stuff all works fine. The point of interest is refactoring of the printing logic onto a background thread, with the web api method enqueuing a job. I did this because print jobs sent in quick succession were interfering with each other with only the last job printing.</p>
  
  <p>It solves the problem of serialising print jobs but raises the question of how to detect shutdown and signal the loop to terminate.</p>
  
  <pre><code>namespace WebPrint.Controllers
  {
      public class LabelController : ApiController
      {
          static readonly ConcurrentQueue&lt;PrintJob&gt; queue = new ConcurrentQueue&lt;PrintJob&gt;();
          static bool running = true;
          static LabelController()
          {
              ThreadPool.QueueUserWorkItem((state) =&gt; {
                  while (running)
                  {
                      Thread.Sleep(30);
                      if (queue.TryDequeue(out PrintJob job))
                      {
                          this.Print(job);
                      }
                  }
              });
          }
          public void Post([FromBody]PrintJob job)
          {
              queue.Enqueue(job);
          }
  
      }
      public class PrintJob
      {
          public string url { get; set; }
          public string html { get; set; }
          public string printer { get; set; }
      }
  }
  </code></pre>
  
  <p>Given the way I acquire a thread to servicing the print queue, it is almost certainly marked as a background thread and should terminate when the app pool tries to exit, but I am not certain of this, and so I ask you, dear readers, for your collective notion of best practice in such a scenario.</p>
  
  <hr>
  
  <p>Well, I <em>did</em> ask for best practice. </p>
  
  <p>Nevertheless, I don't have long-running background tasks, I have short-running tasks. They arrive asynchronously on different threads, <strong>but must be executed serially and on a single thread</strong> because the WinForms printing methods are designed for STA threading. </p>
  
  <p>Matt Lethargic's point about possible job loss is certainly a consideration, but for this case it doesn't matter. Jobs are never queued for more than a few seconds and loss would merely prompt operator retry. </p>
  
  <p>For that matter, using a message queue doesn't solve the problem of "what if someone shuts it down while it's being used" it merely moves it to another piece of software. A lot of message queues aren't persistent, and you wouldn't believe the number of times I've seen someone use MSMQ to solve this problem and then fail to configure it for persistence.</p>
  
  <p>This has been very interesting.</p>
  
  <p><a href="http://thecodelesscode.com/case/156" rel="nofollow noreferrer">http://thecodelesscode.com/case/156</a></p>