# 通知設計書 4-SendNotificationAsync

## 概要

本ドキュメントは、Roslynプロジェクトにおける`SendNotificationAsync`メソッドの設計仕様を記載するものである。このメソッドは、Language Server Protocol（LSP）に基づき、Language Serverからクライアントへ任意のJSON-RPC通知を非同期で送信する汎用メソッドである。

### 本通知の処理概要

`SendNotificationAsync`は、`IClientLanguageServerManager`インターフェースで定義されたメソッドであり、任意のLSP通知メッセージをクライアントに送信するための汎用的な非同期通信機能を提供する。パラメータなしの通知とパラメータ付き通知の両方をサポートし、JSON-RPC 2.0プロトコルに準拠した形式で通知を送信する。

**業務上の目的・背景**：LSPベースのLanguage Serverでは、サーバーからクライアントへ様々な種類の通知を送信する必要がある。診断情報の更新、ソースジェネレータのリフレッシュ、ワークプログレスの報告など、多様な通知タイプをサポートするため、汎用的な通知送信メカニズムが必要となる。このメソッドは、具体的な通知タイプに依存しない汎用的な送信機能を提供することで、新しい通知タイプの追加を容易にし、コードの再利用性を高める。

**通知の送信タイミング**：Language Serverの各種ハンドラやサービスから、クライアントへの通知が必要な任意のタイミングで呼び出される。具体的には、ソースジェネレータの変更時、ワークプログレスの更新時、設定変更の通知時などで使用される。

**通知の受信者**：LSPをサポートするエディタ（Visual Studio Code、Visual Studioなど）のクライアント。送信されたメソッド名に応じて、クライアント側の対応するハンドラが呼び出される。

**通知内容の概要**：メソッド名（文字列）とオプションのパラメータオブジェクトがJSON-RPC形式で送信される。パラメータはジェネリック型として指定可能で、自動的にJSONシリアライズされる。

**期待されるアクション**：クライアントは受信した通知のメソッド名に基づいて適切なハンドラを呼び出し、通知に応じた処理（UI更新、内部状態の更新など）を実行する。

## 通知種別

LSP汎用通知（任意のメソッド名をサポート）

## 送信仕様

### 基本情報

| 項目 | 内容 |
|-----|------|
| 送信方式 | 非同期（ValueTaskベース） |
| 優先度 | 中（通常のLSP通知） |
| リトライ | 無し（通知は送信のみ） |

### 送信先決定ロジック

通知はLanguage Serverに接続しているLSPクライアントに対して送信される。複数のクライアントへのブロードキャストではなく、現在の接続に対する1対1の通信。

## 通知テンプレート

### メソッドシグネチャ

```csharp
// パラメータなし通知
ValueTask SendNotificationAsync(string methodName, CancellationToken cancellationToken);

// パラメータ付き通知
ValueTask SendNotificationAsync<TParams>(string methodName, TParams @params, CancellationToken cancellationToken);
```

### JSON-RPC通知形式

```json
{
  "jsonrpc": "2.0",
  "method": "{methodName}",
  "params": { ... }
}
```

### 添付ファイル

| ファイル名 | 形式 | 条件 | 説明 |
|----------|------|------|------|
| N/A | - | - | LSP通知のため添付ファイルなし |

## テンプレート変数

| 変数名 | 説明 | データ取得元 | 必須 |
|--------|------|-------------|-----|
| methodName | LSPメソッド名 | 呼び出し元から直接渡される | Yes |
| params | 通知パラメータオブジェクト | 呼び出し元から直接渡される（ジェネリック型） | No |
| cancellationToken | キャンセルトークン | 呼び出し元から渡される | Yes |

## 送信トリガー・条件

### トリガー一覧

| トリガー種別 | トリガーイベント | 送信条件 | 説明 |
|------------|----------------|---------|------|
| システム処理 | ソースジェネレータ変更 | ジェネレータ出力が更新された場合 | workspace/semanticTokens/refresh通知 |
| システム処理 | ワークプログレス更新 | 進行状況が変化した場合 | $/progress通知 |
| システム処理 | トースト通知表示 | ユーザーへの通知が必要な場合 | window/_roslyn_showToast通知 |
| システム処理 | LSPサービスライフサイクル | サーバー状態変更時 | 各種ライフサイクル通知 |

### 送信抑止条件

| 条件 | 説明 |
|-----|------|
| クライアントが切断されている場合 | JSON-RPC接続が切断されている場合は送信失敗 |
| キャンセルされた場合 | CancellationTokenがキャンセルされた場合は送信中断 |

## 処理フロー

### 送信フロー

```mermaid
flowchart TD
    A[呼び出し元がSendNotificationAsyncを呼び出し] --> B{パラメータありか?}
    B -->|No| C[JsonRpc.NotifyWithParameterObjectAsync methodName のみ]
    B -->|Yes| D[JsonRpc.NotifyWithParameterObjectAsync methodName, params]
    C --> E[JSON-RPC通知を送信]
    D --> E
    E --> F{送信成功?}
    F -->|Yes| G[ValueTask完了]
    F -->|No| H[例外スロー]
    G --> I[終了]
    H --> I
```

## データベース参照・更新仕様

### 参照テーブル一覧

| テーブル名 | 用途 | 備考 |
|-----------|------|------|
| N/A | - | データベースアクセスなし（LSP通信のみ） |

### 更新テーブル一覧

| テーブル名 | 操作 | 概要 |
|-----------|------|------|
| N/A | - | データベースへの更新なし |

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 対処方法 |
|----------|---------|---------|
| JSON-RPC送信失敗 | クライアント接続が切断されている場合 | 例外は呼び出し元で処理 |
| シリアライズエラー | パラメータがJSONシリアライズできない場合 | 例外がスローされる |
| キャンセル | CancellationTokenがキャンセルされた場合 | OperationCanceledExceptionがスロー |

### リトライ仕様

| 項目 | 内容 |
|-----|------|
| リトライ回数 | 0（リトライなし） |
| リトライ間隔 | N/A |
| リトライ対象エラー | N/A |

## 配信設定

### レート制限

| 項目 | 内容 |
|-----|------|
| 1分あたり上限 | 制限なし（呼び出し元の判断に委ねる） |
| 1日あたり上限 | 制限なし |

### 配信時間帯

システムイベントに応じて即座に送信されるため、時間帯制限なし。

## セキュリティ考慮事項

- 任意のメソッド名を指定できるため、呼び出し元で適切なメソッド名を使用すること
- パラメータはJSONシリアライズされるため、機密情報の送信には注意が必要
- クライアントとの信頼関係が確立されたLSP接続上でのみ使用すること

## 備考

- `IClientLanguageServerManager`インターフェースは`ILspService`を継承
- `ClientLanguageServerManager`クラスが実装を提供
- 内部的には`StreamJsonRpc`ライブラリの`JsonRpc`クラスを使用
- `ValueTask`を使用することで、同期的に完了可能な場合のアロケーションを削減

---

## コードリーディングガイド

本通知を理解するために参照すべきファイルと、推奨する読み解き順序を以下に示す。

### 推奨読解順序

#### Step 1: データ構造を理解する

まず、インターフェース定義と戻り値の型を理解することが重要である。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | IClientLanguageServerManager.cs | `src/LanguageServer/Protocol/IClientLanguageServerManager.cs` | インターフェース定義、SendNotificationAsyncの2つのオーバーロード（行20-21）を理解する |

**読解のコツ**: `ValueTask`と`ValueTask<TResponse>`の違い、およびジェネリック型パラメータ`TParams`の使用方法に注目。

#### Step 2: エントリーポイントを理解する

実装クラスの詳細を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | LanguageServerNotificationManager.cs | `src/LanguageServer/Protocol/Handler/LanguageServerNotificationManager.cs` | ClientLanguageServerManagerの実装、JsonRpcの使用方法（行35-39） |

**主要処理フロー**:
1. **行35-36**: パラメータなしのSendNotificationAsync実装
2. **行38-39**: パラメータ付きのSendNotificationAsync実装（NotifyWithParameterObjectAsync使用）

#### Step 3: JsonRpcの使用方法を理解する

StreamJsonRpcライブラリとの連携を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | LanguageServerNotificationManager.cs | `src/LanguageServer/Protocol/Handler/LanguageServerNotificationManager.cs` | コンストラクタでのJsonRpcインスタンス受け取り（行16-24） |

#### Step 4: 呼び出し元を理解する

実際にSendNotificationAsyncを呼び出している箇所を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | SourceGeneratorRefreshQueue.cs | `src/LanguageServer/Protocol/Handler/SourceGenerators/SourceGeneratorRefreshQueue.cs` | ソースジェネレータリフレッシュ通知の送信例 |
| 4-2 | WorkDoneProgressManager.cs | `src/LanguageServer/Protocol/Handler/WorkDoneProgress/WorkDoneProgressManager.cs` | ワークプログレス通知の送信例 |
| 4-3 | ShowToastNotification.cs | `src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/Logging/ShowToastNotification.cs` | トースト通知の送信例 |
| 4-4 | LspServiceLifeCycleManager.cs | `src/LanguageServer/Protocol/Handler/ServerLifetime/LspServiceLifeCycleManager.cs` | ライフサイクル通知の送信例 |

### プログラム呼び出し階層図

```
呼び出し元（SourceGeneratorRefreshQueue等）
    │
    ├─ IClientLanguageServerManager.SendNotificationAsync(methodName)
    │      │
    │      └─ ClientLanguageServerManager
    │             │
    │             └─ _jsonRpc.NotifyWithParameterObjectAsync(methodName)
    │
    └─ IClientLanguageServerManager.SendNotificationAsync<TParams>(methodName, params)
           │
           └─ ClientLanguageServerManager
                  │
                  └─ _jsonRpc.NotifyWithParameterObjectAsync(methodName, params)
                         │
                         └─ StreamJsonRpc JSON-RPC通知送信
```

### データフロー図

```
[入力]                          [処理]                              [出力]

methodName: string ─────────┐
                            │
params: TParams? ───────────┼──▶ IClientLanguageServerManager ──▶ JSON-RPC Notification
                            │           │                              │
cancellationToken ──────────┘           │                              ▼
                                        ▼                         LSPクライアント
                                 ClientLanguageServerManager          │
                                        │                              ▼
                                        ▼                     クライアント側ハンドラ
                                 JsonRpc.NotifyWithParameterObjectAsync
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| IClientLanguageServerManager.cs | `src/LanguageServer/Protocol/IClientLanguageServerManager.cs` | インターフェース | 通知送信の契約定義 |
| LanguageServerNotificationManager.cs | `src/LanguageServer/Protocol/Handler/LanguageServerNotificationManager.cs` | ソース | 通知送信の実装 |
| SourceGeneratorRefreshQueue.cs | `src/LanguageServer/Protocol/Handler/SourceGenerators/SourceGeneratorRefreshQueue.cs` | ソース | 使用例（ソースジェネレータ） |
| WorkDoneProgressManager.cs | `src/LanguageServer/Protocol/Handler/WorkDoneProgress/WorkDoneProgressManager.cs` | ソース | 使用例（ワークプログレス） |
| ShowToastNotification.cs | `src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/Logging/ShowToastNotification.cs` | ソース | 使用例（トースト通知） |
| LspServiceLifeCycleManager.cs | `src/LanguageServer/Protocol/Handler/ServerLifetime/LspServiceLifeCycleManager.cs` | ソース | 使用例（ライフサイクル） |
