Part 10: フューチャーメソッドと Queueable Apex のエラーハンドリング

## **Part 10: フューチャーメソッド (Future Methods) と Queueable Apex のエラーハンドリング**

前回は **バッチ処理 (Batch Apex) のエラーハンドリング** を解説しました。  
今回は **非同期処理のエラーハンドリング** として、  
**フューチャーメソッド (Future Methods) と Queueable Apex** に焦点を当てます。

---

## **1. フューチャーメソッドのエラーハンドリング**

### **1.1. フューチャーメソッドの特徴**
フューチャーメソッド (`@future`) は **非同期で処理を実行** し、  
**トランザクションの制限を回避する** のに役立ちます。  
特に **コールアウト (外部 API 呼び出し) や大量データの DML** に使われます。

#### **1.2. フューチャーメソッドのエラーハンドリングの課題**
- **通常の try-catch でエラーを処理できるが、エラーログを残さないと気づきにくい**
- **発生したエラーは呼び出し元に通知されない**
- **実行失敗しても自動リトライはされない**

---

### **2. フューチャーメソッドのエラーハンドリング実装例**

#### ✅ **OK 例: try-catch でエラーを記録**
```apex
public class FutureExample {
    @future(callout=true)
    public static void updateAccountIndustry(Set<Id> accountIds) {
        try {
            List<Account> accounts = [SELECT Id, Industry FROM Account WHERE Id IN :accountIds];
            for (Account acc : accounts) {
                acc.Industry = 'Technology';
            }
            update accounts;
        } catch (DmlException e) {
            ErrorLogService.logError(e, 'FutureExample', 'updateAccountIndustry');
        } catch (Exception e) {
            ErrorLogService.logError(e, 'FutureExample', 'updateAccountIndustry');
        }
    }
}
```

このコードでは：
- **`try-catch` で例外をキャッチ**
- **`ErrorLogService.logError()` でエラーメッセージを記録**
- **エラー発生時も他の処理に影響を与えない**

> **適用ケース:**  
> **非同期処理で DML 例外や予期しないエラーを記録し、原因を特定できるようにしたい場合**

---

## **3. Queueable Apex のエラーハンドリング**

### **3.1. Queueable Apex の特徴**
Queueable Apex (`System.Queueable`) は **フューチャーメソッドよりも柔軟** で、  
**オブジェクトをパラメータとして渡せる** などの利点があります。  
また、**`System.enqueueJob()` を使ってキューに登録することで、複雑な非同期処理が可能** です。

---

### **4. Queueable Apex のエラーハンドリング実装例**

#### ✅ **OK 例: try-catch でエラーハンドリング**
```apex
public class QueueableExample implements Queueable {
    private Set<Id> accountIds;

    public QueueableExample(Set<Id> accountIds) {
        this.accountIds = accountIds;
    }

    public void execute(QueueableContext context) {
        try {
            List<Account> accounts = [SELECT Id, Industry FROM Account WHERE Id IN :accountIds];
            for (Account acc : accounts) {
                acc.Industry = 'Technology';
            }
            update accounts;
        } catch (DmlException e) {
            ErrorLogService.logError(e, 'QueueableExample', 'execute');
        } catch (Exception e) {
            ErrorLogService.logError(e, 'QueueableExample', 'execute');
        }
    }
}
```

このコードでは：
- `Queueable` インターフェースを実装し、`execute()` メソッド内で処理
- `try-catch` を使用し、エラー発生時に **`ErrorLogService.logError()` で記録**

> **適用ケース:**  
> **非同期処理の中でオブジェクトを渡しつつ、エラー情報を記録したい場合**

---

### **5. `System.enqueueJob()` を使った再実行の仕組み**
フューチャーメソッドや Queueable Apex では、エラー発生時に **自動リトライされない** ため、  
**エラーログに記録された場合に、一定時間後に再実行する仕組みを追加** できます。

#### ✅ **OK 例: エラー時に再実行する**
```apex
public class QueueableRetryExample implements Queueable {
    private Set<Id> accountIds;
    private Integer retryCount;

    public QueueableRetryExample(Set<Id> accountIds, Integer retryCount) {
        this.accountIds = accountIds;
        this.retryCount = retryCount;
    }

    public void execute(QueueableContext context) {
        try {
            List<Account> accounts = [SELECT Id, Industry FROM Account WHERE Id IN :accountIds];
            for (Account acc : accounts) {
                acc.Industry = 'Technology';
            }
            update accounts;
        } catch (DmlException e) {
            ErrorLogService.logError(e, 'QueueableRetryExample', 'execute');
            if (retryCount < 3) { // 最大3回リトライ
                System.enqueueJob(new QueueableRetryExample(accountIds, retryCount + 1));
            }
        } catch (Exception e) {
            ErrorLogService.logError(e, 'QueueableRetryExample', 'execute');
        }
    }
}
```

このコードでは：
- **失敗した場合、最大 3 回まで `System.enqueueJob()` を使って再実行**
- **再実行回数を `retryCount` で管理し、無限ループを防ぐ**

> **適用ケース:**  
> **一時的なエラー (ロック競合、外部 API のタイムアウト) が発生する可能性がある場合**

---

### **6. エラーメールを送信**
Queueable Apex でも、エラーが発生したら **管理者にメール通知** するのが有効です。

#### ✅ **OK 例: エラー発生時にメール通知**
```apex
public void execute(QueueableContext context) {
    try {
        // メイン処理
    } catch (Exception e) {
        ErrorLogService.logError(e, 'QueueableExample', 'execute');
        
        // 管理者にメール通知
        Messaging.SingleEmailMessage mail = new Messaging.SingleEmailMessage();
        mail.setToAddresses(new String[] {'admin@example.com'});
        mail.setSubject('【警告】Queueable Apex でエラー発生');
        mail.setPlainTextBody('エラー内容: ' + e.getMessage());
        Messaging.sendEmail(new Messaging.SingleEmailMessage[] {mail});
    }
}
```

> **適用ケース:**  
> **エラーを即座に管理者に通知したい場合**

---

## **まとめ**
今回は **フューチャーメソッド (Future Methods) と Queueable Apex のエラーハンドリング** を解説しました。

✅ **フューチャーメソッド**
- `try-catch` でエラーハンドリング
- **エラーログを記録し、管理者が原因を特定できるようにする**

✅ **Queueable Apex**
- `try-catch` でエラーを記録
- **エラー時に `System.enqueueJob()` を使って再実行**
- **エラーメール通知を追加して管理者に通知**

> **次の Part 11** では、**プラットフォームイベントや非同期処理 (Scheduled Apex, Event-Driven Architecture) におけるエラーハンドリング** を解説します！