title: Risks of Using System.Threading.Timer in an ASP.Net/SignalR Environment
body: <p>We're running SignalR in a stand-alone ASP.Net app running in a virtual directory off our main ASP.Net website.</p>
  
  <p>In our SignalR hub implementation, we have a static <code>ConcurrentDictionary&lt;int, UserState&gt;</code> variable maintaining some light-weight user state across individual connections. Over time that variable will be added to based upon client-side actions (i.e. as new users start interacting with our website). This variable is essentially providing some simple state tracking across connections.</p>
  
  <p>We don't particularly want to add a special SignalR backplane which would require additional infrastructure dependencies as our data load is likely to be relatively lightweight and tracking this in-memory should be sufficient.</p>
  
  <p>When a user has been inactive for a long-enough period of time (let's say 1 hour) we want to remove them from the dictionary variable. Whatever process does this should be <em>guaranteed</em> to run on a consistent basis - so, not dependent upon user behaviour, but instead upon a timed duration. </p>
  
  <p>I have what I believe to be a good solution for doing this:</p>
  
  <pre><code>public class UserStateService : IUserStateService
  {
      private static readonly ConcurrentDictionary&lt;int, UserState&gt; recentUsers = new ConcurrentDictionary&lt;int, UserState&gt;();
      private static Timer timer;
  
      public static void StartCleanup()
      {
          timer = new Timer( CleanupRecentUsers, null, 0, 60000 );
      }
  
      public static void StopCleanup()
      {
          timer.Dispose();
      }
  
      private static void CleanupRecentUsers( object state )
      {
          var now = DateTime.UtcNow;
  
          var oldUsers = recentUsers.Select( p =&gt; p.Value ).Where( u =&gt; u.LastActionTime.AddHours( 1 ) &gt; now );
  
          foreach ( var user in oldUsers )
          {
              UserState removedUser;
              recentUsers.TryRemove( user.UserId, out removedUser );
          }
      }
  
      // other code for adding/updating user state.
  }
  </code></pre>
  
  <p>As mentioned, <em>I think</em> this is a good solution. However, I'm not very conversant in thread management (though I'm aware that dealing with static objects in ASP.Net is dangerous).</p>
  
  <p><code>StartCleanup()</code> and <code>StopCleanup()</code> are called once each at the start and end of the application lifecycle, respectively. The <code>UserStateService</code> is supplied to our <code>Hub</code> classes via our IoC container (Structure Map) and is currently not scoped with any special lifecycle handling (i.e. it's not <code>Singleton</code> or thread-scoped, simply per-instance request). </p>
  
  <p>We're already using static concurrent dictionaries in our production app and they're working fine without any known instances of performance issues. What I'm not sure about is running a <code>Timer</code> loop here.</p>
  
  <p>So, my question is, are there any obvious risks here relating to threads being blocked/locked (or CPU use generally going out of control for any reason) that I need to mitigate or which could make this approach unworkable?</p>