# バッチ設計書 19-Channels::Whatsapp::TemplatesSyncSchedulerJob

## 概要

本ドキュメントは、Chatwootシステムにおける WhatsApp チャネルのメッセージテンプレート同期スケジューリング処理を実行するバッチ処理の設計を記述するものです。

### 本バッチの処理概要

本バッチは、一定期間更新されていない WhatsApp チャネルを検出し、各チャネルに対してテンプレート同期ジョブをキューイングするスケジューラー処理を実行します。

**業務上の目的・背景**：WhatsApp Business APIを使用したメッセージ送信では、事前に承認されたメッセージテンプレートを使用する必要があります。これらのテンプレートはWhatsApp側で管理されており、新規作成や更新、削除が行われることがあります。本バッチにより、WhatsApp側のテンプレート情報を定期的にChatwootに同期することで、エージェントが常に最新のテンプレートを使用できるようにします。

**バッチの実行タイミング**：TriggerScheduledItemsJobから5分毎にトリガーされます。

**主要な処理内容**：
1. message_templates_last_updatedが3時間以上前、またはNULLのWhatsAppチャネルを検索
2. 未更新が古い順にソート（NULL優先）
3. 処理件数をBULK_EXTERNAL_HTTP_CALLS_LIMIT（25件）に制限
4. 各チャネルに対してTemplatesSyncJobをキューイング

**前後の処理との関連**：本バッチはTriggerScheduledItemsJobから呼び出される子ジョブです。本バッチが親ジョブとしてTemplatesSyncJob（孫ジョブ）をキューイングします。

**影響範囲**：3時間以上更新されていないWhatsAppチャネルが対象となります。本バッチ自体はジョブキューへのエンキュー処理のみを行い、直接的なデータ更新は行いません。

## バッチ種別

ジョブスケジューリング / トリガー処理

## 実行スケジュール

| 項目 | 内容 |
|-----|------|
| 実行頻度 | 5分毎 |
| 実行時刻 | 毎時0分、5分、10分、15分、... |
| 実行曜日 | 毎日 |
| 実行日 | 毎日 |
| トリガー | TriggerScheduledItemsJob経由 |

## 実行条件

### 前提条件

| 条件 | 説明 |
|-----|------|
| TriggerScheduledItemsJobが稼働していること | 親ジョブからのトリガーが必要 |
| データベース接続が可能であること | channel_whatsappテーブルへのアクセスに必要 |

### 実行可否判定

本バッチは無条件で実行されます。対象チャネルが存在しない場合も正常終了します。

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | デフォルト値 | 説明 |
|-------------|-----|-----|-------------|------|
| なし | - | - | - | パラメータは不要 |

### 入力データソース

| データソース | 形式 | 説明 |
|-------------|------|------|
| channel_whatsapp | DB | WhatsAppチャネルレコード |

## 出力仕様

### 出力データ

| 出力先 | 形式 | 説明 |
|-------|------|------|
| Sidekiqジョブキュー | Queue | TemplatesSyncJobがlowキューにエンキューされる |

### 出力ファイル仕様

ファイル出力はありません。

## 処理フロー

### 処理シーケンス

```
1. バッチ開始
   └─ lowキューから起動
2. WhatsAppチャネルを更新日時順にソート
   └─ message_templates_last_updated IS NULL DESC, message_templates_last_updated ASC
3. 3時間以上更新されていないチャネルをフィルタ
   └─ message_templates_last_updated <= 3.hours.ago OR message_templates_last_updated IS NULL
4. 処理件数を制限
   └─ limit(BULK_EXTERNAL_HTTP_CALLS_LIMIT) = 25件
5. 各チャネルに対してTemplatesSyncJobをエンキュー
   └─ Channels::Whatsapp::TemplatesSyncJob.perform_later(channel)
6. バッチ終了
```

### フローチャート

```mermaid
flowchart TD
    A[バッチ開始] --> B[Channel::Whatsapp取得]
    B --> C[更新日時順にソート NULL優先]
    C --> D[3時間以上更新なしでフィルタ]
    D --> E[limit BULK_EXTERNAL_HTTP_CALLS_LIMIT]
    E --> F{チャネルあり?}
    F -->|No| H[バッチ終了]
    F -->|Yes| G[TemplatesSyncJob.perform_later]
    G --> F
```

## データベース操作仕様

### 操作別データベース影響一覧

| 処理 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| WhatsAppチャネル取得 | channel_whatsapp | SELECT | 更新が古いチャネルを取得 |

### テーブル別操作詳細

#### channel_whatsapp

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| SELECT | id, message_templates_last_updated | message_templates_last_updated <= 3.hours.ago OR IS NULL | ORDER BY NULL DESC, ASC |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | StandardError | DB操作失敗時 | Sidekiqの標準リトライ機構により再実行 |

### リトライ仕様

| 項目 | 内容 |
|-----|------|
| リトライ回数 | Sidekiqのデフォルト設定 |
| リトライ間隔 | 指数バックオフ |
| リトライ対象エラー | StandardError全般 |

### 障害時対応

バッチ失敗時は次回の定期実行（5分後）で自動的にリカバリされます。緊急時はRailsコンソールから手動実行可能です：
```ruby
Channels::Whatsapp::TemplatesSyncSchedulerJob.perform_now
```

## トランザクション仕様

| 項目 | 内容 |
|-----|------|
| トランザクション範囲 | なし（読み取りとジョブエンキューのみ） |
| コミットタイミング | N/A |
| ロールバック条件 | N/A |

## パフォーマンス要件

| 項目 | 内容 |
|-----|------|
| 想定処理件数 | 最大25件（BULK_EXTERNAL_HTTP_CALLS_LIMIT） |
| 目標処理時間 | 数秒 |
| メモリ使用量上限 | limit指定により一定に制御 |

## 排他制御

- 同時実行制御なし
- 5分間隔の実行であるため、重複実行のリスクは低い
- 子ジョブ（TemplatesSyncJob）は同一チャネルでの重複キューイングが発生する可能性があるが、外部API呼び出しは冪等

## ログ出力

| ログ種別 | 出力タイミング | 出力内容 |
|---------|--------------|---------|
| 開始ログ | バッチ開始時 | Sidekiq標準ログ |
| 進捗ログ | - | 明示的なログ出力なし |
| 終了ログ | バッチ終了時 | Sidekiq標準ログ |
| エラーログ | エラー発生時 | Sidekiq標準エラーログ |

## 監視・アラート

| 監視項目 | 閾値 | アラート先 |
|---------|-----|----------|
| 処理時間 | 5分以上 | Sidekiq監視システム |
| エラー件数 | 1件以上 | Sidekiq監視システム |

## 備考

- BULK_EXTERNAL_HTTP_CALLS_LIMIT = 25（lib/limits.rb）
  - 外部API呼び出しを伴う処理のため、同時実行数を制限
- message_templates_last_updated IS NULL優先ソート
  - 新規作成されたチャネル（まだ同期していない）を優先的に処理
- 3時間（3.hours.ago）の閾値設定
  - WhatsApp側のテンプレート更新頻度を考慮した設定
- Arel.sql使用
  - NULLソートのために生SQLを使用
