Blazor Server でブラウザを閉じても処理を継続する
はじめに
Blazor Web Appのサーバ側で、時間のかかる処理を行っている間、ブラウザを閉じたりしないようにUIをブロックしていたのですが、開いたままにしておくのも何かと不便なので、バックグラウンドサービスにしてみました。
前提
- .NET 8
実装
タスク
バックグラウンド処理のモデルを定義します。
更新対象の「レコードID」と「完全/部分」種別を保持します。
キュー
タスクを共有するFIFOを定義します。
同じ処理が既に待機中なら登録しないようにしたいのですが、Channel
はスキャンに向かないし、DBはロックしたくないので、別途ConcurrentDictionary
で待機列を管理しています。
待機列に含まれるか確認するContains
と、処理完了時に待機列から除去するCompleted
が用意されています。
サービス
実際の処理内容を定義します。StartAsync
は、アプリの起動時に呼ばれ、別スレッドでバックグラウンド処理を開始して、自身はすぐ終わります。
バックグラウンド処理でスコープサービスを利用するために、まずスコープを生成し、その中でサービスを注入しています。
そして、キューからタスクを取り出して順に処理UpdateBookFromSiteAsync
します。
タスクがなくなれば、新しいタスクがキューに登録されるまで待機します。
個々のタスクが完了する際は、待機列(辞書)から自身を除去します。
アプリのシャットダウン時にはStopAsync
が呼ばれます。
DIコンテナへの登録
起動時にサービスを登録します。
builder.Services.AddSingleton<UpdateBookQueueService> ();
builder.Services.AddHostedService<UpdateBookService> ();
これらはアプリ全体で共有するので、キューUpdateBookQueueService
はシングルトンです。
サービスUpdateBookService
はIHostedService
を実装したシングルトンとしてホストされ、アプリのライフサイクルに統合されます。
使用例
キューの注入
着目中のレコードがキューに登録されているか判別
キューにタスクを登録 (処理の追加)
await UpdateBookQueue.EnqueueAsync (new UpdateBookTask { Id = SelectedItem.Id, FullUpdate = fullUpdate, });
個々のレコードが処理(待機)中か否かを表示
おわりに
最後までお読みいただきありがとうございました。
サンプルコードの全体は、以下のリポジトリにあります。
何かお気づきの際は、是非ご指摘ください。
あるいは、「それでも解らない」、「自分はこう捉えている」などといった、ご意見、ご感想も歓迎いたします。
Discussion