本稿は、Salesforce 開発者の視点から、Salesforce Platform Eventsの強力な機能について解説します。
背景と応用シーン
従来のシステム開発では、コンポーネント間の連携が密結合(Tightly Coupled)になりがちでした。例えば、注文が作成された際に、在庫管理システムを更新し、さらに出荷システムに通知を送り、最後に顧客にメールを送信する、といった一連の処理を単一のトランザクションで実行するとします。このアプローチでは、いずれか一つのシステムの障害がプロセス全体を停止させるリスクや、将来的な仕様変更が他のすべてのコンポーネントに影響を及ぼすという保守性の問題がありました。
ここで登場するのが、Event-Driven Architecture (イベント駆動型アーキテクチャ) という設計思想です。これは、システム内で発生した「イベント(出来事)」をメッセージとして発行(Publish)し、そのイベントに関心のある他のシステムがそれを購読(Subscribe)して処理を行うモデルです。このモデルにより、各システムは疎結合(Loosely Coupled)となり、独立して開発、デプロイ、スケールすることが可能になります。
Salesforceにおけるこのアーキテクチャの中核を担うのが Platform Events (プラットフォームイベント) です。Platform Eventsは、Salesforceプラットフォーム内外のシステム間で、リアルタイムかつスケーラブルな通信を実現するためのメッセージングサービスです。
具体的な応用シーン:
- 外部システム連携: Salesforceで「商談」が「成立」になった瞬間にイベントを発行し、外部のERPシステムがそれを購読して請求書を自動生成する。
- 非同期処理の実行: 大量のレコード更新や複雑な計算処理をトリガーから切り離し、イベントを発行することで非同期に実行させ、ユーザーの操作性を損なわないようにする。
- リアルタイムUI更新: あるユーザーの操作によってバックエンドで重要な変更が発生した際にイベントを発行し、他のユーザーが開いているLightning Web Components (LWC) の画面をリアルタイムに更新する。
- IoTデバイス連携: 工場のセンサーが異常を検知した際にイベントを発行し、Salesforce上でケースを自動起票してサービス担当者に通知する。
原理説明
Platform Eventsの仕組みは、publish/subscribe model (パブリッシュ/サブスクライブモデル)に基づいています。このモデルは、主に3つの要素で構成されます。
1. Event (イベント):
発生した事象に関する情報を含むメッセージです。Salesforceでは、Platform EventはカスタムオブジェクトのようにAPI参照名(`__e`で終わる)とカスタム項目を定義してスキーマを決定します。これにより、どのようなデータがイベントに含まれるかが明確になります。
2. Event Bus (イベントバス):
発行されたすべてのイベントが流れる共有のチャネルです。発行者(Publisher)はイベントバスにイベントを送信し、購読者(Subscriber)はイベントバスをリッスンして関心のあるイベントを受信します。Salesforceのマルチテナントアーキテクチャ上で、スケーラブルかつ安全にメッセージを配信する役割を担います。
3. Publisher (発行者) と Subscriber (購読者):
Publisherはイベントを作成し、イベントバスに発行するコンポーネントです。Apex、フロー、プロセスビルダー、REST API、SOAP APIなど、様々な方法でイベントを発行できます。
Subscriberはイベントバスをリッスンし、特定のイベントを受信してアクションを実行するコンポーネントです。Apex Trigger、フロー、CometDを利用した外部クライアント、またはLWCなどがSubscriberになり得ます。
イベントが発行されると、それはイベントバスに送信され、イベントを受信待ちしているすべての購読者に配信されます。重要な特徴として、発行者はどの購読者がイベントを受け取るかを知る必要がなく、購読者も発行者が誰であるかを知る必要がありません。この「疎結合」が、システムの柔軟性と拡張性を飛躍的に向上させます。
また、Platform EventsにはPublish Behavior (公開動作)という重要な設定があります。これはイベントをトランザクション内でいつ発行するかを制御します。
- Publish After Commit (コミット後に公開): デフォルトの動作です。トランザクションが正常にデータベースにコミットされた後にのみ、イベントが発行されます。これにより、トランザクションがロールバックされた場合に、誤ったイベントが発行されるのを防ぎます。最も安全で推奨される方法です。
- Publish Immediately (すぐに公開): トランザクションのコミット状態に関わらず、`EventBus.publish()`が実行された瞬間にイベントが発行されます。トランザクションが後に失敗しても、イベントは取り消されません。ロギングなど、トランザクションの結果に関わらず実行したい特定のケースでのみ使用が推奨されます。
示例代码
ここでは、開発者が最もよく利用するであろうApexを使用したPlatform Eventsの実装例を見ていきましょう。「注文状況が更新された」ことを通知する`Order_Event__e`というプラットフォームイベントを定義したと仮定します。このイベントには`Order_Number__c` (Text) と `Status__c` (Text) という2つのカスタム項目があります。
1. ApexによるPlatform Eventの発行
Apexクラスから`Order_Event__e`イベントを発行するコードです。`EventBus.publish()`メソッドを使用します。
// 発行したいイベントのインスタンスを作成するリスト
List<Order_Event__e> orderEvents = new List<Order_Event__e>();
// 1つ目のイベントを作成
Order_Event__e event1 = new Order_Event__e(
Order_Number__c = '1001',
Status__c = 'Shipped'
);
orderEvents.add(event1);
// 2つ目のイベントを作成
Order_Event__e event2 = new Order_Event__e(
Order_Number__c = '1002',
Status__c = 'Delivered'
);
orderEvents.add(event2);
// イベントのリストをイベントバスに発行
// EventBus.publish() メソッドは、発行操作の結果を含む Database.SaveResult のリストを返します。
List<Database.SaveResult> results = EventBus.publish(orderEvents);
// 結果を反復処理して、発行が成功したかどうかを確認
for (Database.SaveResult sr : results) {
if (sr.isSuccess()) {
// 発行成功
System.debug('Successfully published event with ID: ' + sr.getId());
} else {
// 発行失敗時のエラー処理
for(Database.Error err : sr.getErrors()) {
System.debug('Error returned: ' +
err.getStatusCode() +
' - ' +
err.getMessage());
}
}
}
コード解説:
まず、発行したいPlatform Eventオブジェクト(この場合は`Order_Event__e`)のインスタンスを作成し、リストに追加します。次に、`EventBus.publish()`メソッドにそのリストを渡すことで、イベントがイベントバスに送信されます。このメソッドはトランザクションセーフであり、複数のイベントを一度に発行することができます。戻り値の`Database.SaveResult`をチェックすることで、各イベントの発行が成功したか失敗したかを確認できます。
2. Apex TriggerによるPlatform Eventの購読
発行された`Order_Event__e`をApex Triggerで購読し、関連する処理を実行します。Platform Eventに対するTriggerは、`after insert`でのみ動作します。
// プラットフォームイベント 'Order_Event__e' に対するトリガー
// イベントメッセージを受信した後に実行されるため、'after insert' を使用
trigger OrderEventTrigger on Order_Event__e (after insert) {
// 複数のイベントメッセージが一度に処理される可能性があるため、
// Trigger.New をループ処理する
for (Order_Event__e event : Trigger.New) {
System.debug('Received Order Event:');
System.debug(' Order Number: ' + event.Order_Number__c);
System.debug(' Status: ' + event.Status__c);
// ここでイベントに基づいたビジネスロジックを実行する
// 例:関連する注文レコードの状況を更新する、Chatterに投稿するなど
// Taskを作成する例
Task newTask = new Task(
Subject = 'Follow up on order ' + event.Order_Number__c,
Status = 'Not Started',
Priority = 'Normal'
);
// DML操作はループの外で行うのがベストプラクティス
// ここでは説明のために簡略化しているが、実際にはリストに貯めてループ外でinsertする
// insert newTask;
}
}
コード解説:
このトリガーは`Order_Event__e`オブジェクトに対して定義されています。イベントが発行されると、この`after insert`トリガーが起動します。`Trigger.New`には、受信したイベントメッセージのリストが含まれています。ループ内で各イベントのペイロード(`Order_Number__c`や`Status__c`などの項目値)にアクセスし、それに応じたビジネスロジックを実装します。重要なのは、各Subscriber(この場合はトリガー)は独立したトランザクションで実行されるという点です。
注意事項
Platform Eventsを効果的に利用するためには、以下の制限や考慮点を理解しておくことが不可欠です。
- 権限: Platform Eventを発行・購読するには、プロファイルまたは権限セットで、対象のPlatform Eventオブジェクトに対する「作成」権限(発行)および「参照」権限(購読)が必要です。
- API制限: Platform Eventsにはガバナ制限があります。1時間あたりのイベント発行数や配信数には上限が設けられています(エディションによって異なります)。大量のイベントを扱うシステムを設計する際は、Salesforceのドキュメントで最新の制限値を必ず確認してください。
- イベントの保持期間: イベントメッセージはイベントバスに24時間(CometDクライアントによるReplay機能利用時は最大72時間)保持されます。この期間を過ぎるとイベントは失われます。永続的なデータストレージとしては利用できません。
- エラー処理: あるSubscriberが処理に失敗しても、イベントの発行や他のSubscriberの処理には影響しません。各Subscriberは自身のトランザクション内でエラーハンドリングを堅牢に実装する必要があります。例えば、トリガー内でtry-catchブロックを使用したり、失敗した処理を後でリトライする仕組みを検討したりすることが重要です。
- トランザクションの独立性: イベントの発行者と購読者は、それぞれ別のトランザクションで実行されます。これにより、購読者側の処理の成否が発行者側のトランザクションに影響を与えることはありません。これは疎結合の大きな利点ですが、一貫性を保つための設計には注意が必要です。
- スキーマの変更管理: 一度定義したPlatform Eventの項目は、後から変更(データ型の変更や削除)が困難な場合があります。特に、多くのSubscriberが利用しているイベントのスキーマを変更する際は、慎重な計画と影響範囲の調査が必要です。
まとめとベストプラクティス
Salesforce Platform Eventsは、現代的なアプリケーション開発に不可欠なイベント駆動型アーキテクチャをSalesforceプラットフォーム上で実現するための強力なツールです。システム間の連携を疎結合に保ち、スケーラビリティと保守性を向上させることで、複雑なビジネス要件にも柔軟に対応できるアプリケーションの構築を可能にします。
開発者としてのベストプラクティス:
- 明確なイベントスキーマを設計する: イベントには、その「出来事」を説明するために必要十分な情報のみを含めるようにします。SObjectの全項目をそのままコピーするのではなく、コンテキストに合わせた軽量なデータ構造を心がけましょう。
- `Publish After Commit`を原則とする: データの整合性を保つため、トランザクションが成功した場合にのみイベントが発行される`Publish After Commit`をデフォルトの選択肢とします。
- Subscriberの冪等性(Idempotency)を確保する: ネットワークの問題などで同じイベントが再配信される可能性もゼロではありません。Subscriberは、同じイベントを複数回受信しても問題が発生しないように(冪等に)設計することが理想的です。
- ガバナ制限を監視する: `Limits.getPlatformEventUsage()`メソッドなどを活用し、アプリケーションがAPI制限に近づいていないかを監視する仕組みを導入しましょう。
- イベントの命名規則を確立する: 組織内で複数のイベントが利用されることを見越し、「`{オブジェクト名}_{アクション}_Event__e`」のような一貫した命名規則を設けることで、管理性が向上します。
Platform Eventsを正しく理解し、これらのベストプラクティスに従うことで、Salesforce開発者はより堅牢で、スケーラブルで、そして未来の変化に強いシステムを構築することができるでしょう。
コメント
コメントを投稿