async について
時間のかかる処理をバックグラウンドに移し、HTTP リクエストや UI の応答性を保つための非同期設計リファレンスです。信頼性の要件、フレームワークの選択肢、よくある失敗を扱います。
主な機能
- 01バックグラウンド処理に移す判断基準
- 02冪等性と重複排除
- 03リトライ・バックオフ・デッドレターキュー
- 04並列の競合コンシューマー
- 05ライフサイクルログ・メトリクス・アラート
- 06PHP と Node.js のフレームワーク選択肢
活用シーン
- 01メールや文書生成のワーカー処理化
- 02遅いサードパーティ API 呼び出しへの対応
- 03リトライとデッドレター処理の設計
- 04バックグラウンドタスクの障害監視
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ thebeardedbearsas/ claude-craft --skill asyncインストール後、Claude Code で/asyncを入力して読み込まれたか確認します。
同梱ファイルREFERENCE.md
詳細
Async-First — クイックリファレンス
200 ms を超える処理をバックグラウンドワーカーに移し、UI/API の応答性を保ちます。
非同期処理を有効にするタイミング
| ケース | 非同期処理? |
|---|---|
| トランザクションメールの送信 | ✅ |
| PDF 生成/CSV エクスポート | ✅ |
| 200 ms を超えるサードパーティ API 呼び出し | ✅ |
| 夜間のバッチ処理 | ✅ |
| 単純なデータベース読み取り | ❌ |
絶対に守るべき 5 つの不変条件
- HTTP は 200 ms 未満。 このしきい値を超える処理はすべて別の場所に移す必要があります。
- 冪等性は必須です。 メッセージは再実行される可能性があるため、その前提で設計します(冪等性キー、重複排除)。
- リトライ + デッドレターキュー。 3 回試行し、ジッターを加えた指数バックオフを適用します。それでも失敗した場合は → DLQ に移動してアラートを発します。
- 競合コンシューマー。 ピークを吸収できるよう、4~8 個のワーカーを並行して稼働させます。
- ライフサイクルの追跡。 構造化ログ、メトリクス(レイテンシ、エラー率、DLQ の深さ)、アラートを用意します。
推奨フレームワーク
| スタック | フレームワーク | 備考 |
|---|---|---|
| Symfony | Symfony Messenger | AMQP、Redis、Doctrine のトランスポートに対応。Stamps をサポート |
| Laravel | Laravel Queue(本番環境では Horizon) | Redis または SQS を利用。監視機能を標準搭載 |
| PHP のフレームワーク非依存 | Ecotone | DDD、サガ、スケジューラー、統合メッセージング |
| Node.js | BullMQ または RabbitMQ | Redis をバックエンドとし、ダッシュボードを提供 |
最小限のパターン(Symfony Messenger)
// Message (immutable DTO)
final class SendWelcomeEmail
{
public function __construct(public readonly string $userId) {}
}
// Handler
final class SendWelcomeEmailHandler
{
public function __invoke(SendWelcomeEmail $message): void
{
// Idempotency check
if ($this->emailLog->wasSent($message->userId, 'welcome')) {
return;
}
$this->mailer->sendWelcome($message->userId);
$this->emailLog->record($message->userId, 'welcome');
}
}
// Dispatch (controller)
$this->bus->dispatch(new SendWelcomeEmail($user->id));
重大なアンチパターン
- ❌ 冪等性キーなしで、冪等であるべき処理をハンドラーに直接実装する → 再実行時に二重処理になります。
- ❌ ハンドラー内で
try { ... } catch (\Throwable) { /* swallow */ }を使う → 失敗しているのにメッセージが処理済みとしてマークされます。 - ❌ メール/PDF のペイロード全体をメッセージに保存する → ID のみを渡して検索する方法を推奨します。そうしないと RabbitMQ がパンクします。
- ❌ サードパーティへの呼び出しにサーキットブレーカーを設けない → プロバイダーがダウンすると DLQ が急増します。
さらに詳しく
詳細、Laravel/Ecotone のパターン、設定例、OpenTelemetry によるオブザーバビリティ、ライフサイクルイベント、フェーズごとのチェックリストについては、
@.claude/skills/async/REFERENCE.mdを参照してください。
コメント
Markdown 対応