メインの ASP.Net Web サイトの仮想ディレクトリで実行されているスタンドアロンの ASP.Net アプリで SignalR を実行しています。
SignalR ハブの実装では、ConcurrentDictionary<int, UserState>
個々の接続全体で軽量のユーザー状態を維持する静的変数があります。その変数は、クライアント側のアクションに基づいて時間の経過とともに追加されます (つまり、新しいユーザーが当社の Web サイトとやり取りを開始すると)。この変数は基本的に、接続全体でいくつかの単純な状態追跡を提供しています。
データの読み込みは比較的軽量である可能性が高く、このメモリ内の追跡で十分であるため、インフラストラクチャの依存関係を追加する必要がある特別な SignalR バックプレーンを追加することは特に望んでいません。
ユーザーが十分な時間 (たとえば 1 時間) 非アクティブであった場合、それらを辞書変数から削除したいと考えています。これを行うプロセスが何であれ、これは一貫して実行されることが保証されるべきです- したがって、ユーザーの行動に依存するのではなく、一定の期間に依存します。
私はこれを行うための良い解決策であると信じているものを持っています:
public class UserStateService : IUserStateService
{
private static readonly ConcurrentDictionary<int, UserState> recentUsers = new ConcurrentDictionary<int, UserState>();
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 => p.Value ).Where( u => u.LastActionTime.AddHours( 1 ) > now );
foreach ( var user in oldUsers )
{
UserState removedUser;
recentUsers.TryRemove( user.UserId, out removedUser );
}
}
// other code for adding/updating user state.
}
前述のとおり、これは良い解決策だと思います。ただし、私はスレッド管理にあまり精通していません (ただし、ASP.Net で静的オブジェクトを扱うのは危険であることは承知しています)。
StartCleanup()
アプリケーションのライフサイクルの開始時とStopCleanup()
終了時にそれぞれ 1 回ずつ呼び出されます。は、IoC コンテナー (構造マップ) を介しUserStateService
てクラスに提供され、Hub
現在、特別なライフサイクル処理でスコープが設定されていません (つまりSingleton
、スレッド スコープではなく、単にインスタンスごとのリクエスト)。
私たちはすでに本番アプリで静的並行辞書を使用しており、パフォーマンスの問題の既知のインスタンスなしで正常に動作しています. よくわからないのは、Timer
ここでループを実行していることです。
したがって、私の質問は、スレッドがブロック/ロックされている (または CPU 使用が一般的に何らかの理由で制御不能になっている) ことに関連して、緩和する必要がある、またはこのアプローチを実行できなくする可能性のある明らかなリスクはありますか?