Apex-事件驱动(3)

学习目标

完成本单元后,您将能够:

  • 描述如何订阅平台事件消息。
  • 使用Apex触发器订阅事件。
  • 用Apex测试方法测试平台事件。
  • 通过CometD订阅平台事件。

订阅平台事件

现在您已经看到了如何发布平台事件,您如何订阅他们以获得最新消息或发货的通知?在Salesforce平台上,Apex触发器,流程和流程接收事件通知。 Visualforce和Lightning组件应用程序通过CometD接收事件。在外部应用程序中,您也可以使用CometD订阅事件。

使用Apex触发器订阅平台事件通知

您可能以前使用过Apex触发器,以基于数据库事件执行操作。通过平台事件,过程是相似的。您只需在事件对象上插入一个插入Apex触发器来订阅传入事件即可。触发器在Apex中提供自动订阅机制。不需要明确创建和收听频道。触发器接收来自各种来源的事件通知,不管它们是通过Apex还是API发布的。

平台事件仅在插入触发器后才支持。后插入触发器事件对应于发布平台事件之后的时间。事件消息发布后,触发后插入触发器。

要创建平台事件触发器,请使用开发者控制台。

  1. 单击设置图标,选择 Developer Console, 然后单击 File | New | Apex Trigger.
  2. 提供一个名称并为sObject选择事件,然后单击 Submit.

开发者控制台会自动在触发器模板中添加after插入事件。另外,您可以方便地从“触发器”相关列表中的“设置”中的事件定义页面创建触发器,但是必须指定after insert关键字。

以下示例显示了Cloud News事件的触发器。它遍历每个事件并通过Urgent__c字段检查消息是否紧急。如果消息紧急,则触发器创建一个派发新闻记者的案例,并将事件位置添加到案例主题。

// 触发Cloud_News事件。
trigger CloudNewsTrigger on Cloud_News__e (after insert) {    
    // 列举所有要创建的案例。
    List<Case> cases = new List<Case>();
    
    // 获取案例所有者的队列ID
    Group queue = [SELECT Id FROM Group WHERE Name='Regional Dispatch' LIMIT 1];
       
    // 遍历每个通知
    for (Cloud_News__e event : Trigger.New) {
        if (event.Urgent__c == true) {
            // Create Case to dispatch new team.
            Case cs = new Case();
            cs.Priority = 'High';
            cs.Subject = 'News team dispatch to ' + 
                event.Location__c;
            cs.OwnerId = queue.Id;
            cases.add(cs);
        }
   }
    
    // 插入与收到的事件相对应的所有案例。
    insert cases;
}
设置调试日志记录

与标准或自定义对象上的触发器不同,平台事件上的触发器不会在与发布事件相同的Apex事务中执行。触发器在系统用户Automated Process实体下的自己的进程中运行。因此,与触发器执行相对应的调试日志由Automated Process实体创建,并且在Developer Console中不可用。要收集平台事件触发器日志,请在“安装”中为“自动过程”实体添加跟踪标志条目。

  1. 在安装程序中,在快速查找框中输入调试日志,然后单击 Debug Logs.
  2. 点击 New.
  3. 对于跟踪的实体类型,请选择 Automated Process.
  4. 选择您要收集的日志的开始日期和到期日期。
  5. 对于调试级别,输入*然后单击 Search.
  6. 选择一个预定义的调试级别,例如SFDC_DevConsole或单击New来创建您自己的调试级别。
  7. 点击 Save.

注意

Apex测试的调试日志是一个例外。它们包括在同一个测试执行日志中记录事件触发器。

有关平台事件触发器的注意事项

事件处理的顺序
触发器按收到的顺序处理平台事件通知。事件的顺序基于事件重播ID。 Apex触发器可以一次接收一批事件。事件的顺序保存在每个批次中。批处理中的事件可以来自一个或多个发布者。
异步触发器执行
平台事件触发器异步运行在其自己的进程中,不是发布事件的事务的一部分。因此,事件发布时间和触发器处理事件之间可能存在延迟。不要期望触发器执行的结果在事件发布之后立即可用。
自动化的过程系统用户
由于平台事件触发器不会在执行它们的用户(正在运行的用户)下运行,而是在Automated Process系统用户下运行,所以我们在CloudNewsTrigger示例中明确地设置了所有者ID字段。我们使用了一个称为Regional Dispatch的示例用户队列的ID作为触发器示例。如果您在触发器(例如案例或商机)中创建带有OwnerId字段的Salesforce记录,请明确设置所有者ID。对于案例和潜在客户,您可以使用分配规则来设置所有者。
此外,系统字段(例如CreatedById和LastModifiedById)引用自动处理实体,而不是正在运行的用户。
Apex Governor 限制
与标准或自定义对象触发器一样,平台事件触发器也受到Apex控制器限制。
Apex Trigger 限制
平台事件触发器共享许多自定义和标准对象触发器的相同限制。例如,您不能从触发器中同步创建Apex标注。

订阅事件定义页面上的相关列表

您可以在安装程序的“平台事件定义详细信息”页面上查看所有事件触发器的状态。 CometD用户不在此列表中。在订阅下,每个激活的触发器都与执行信息和状态一起列出。信息包括上次发布和上次处理事件的重播ID。由于错误不可恢复或权限不足,状态会指示触发器是否正在运行或已与订阅断开连接。仅当触发器重试次数达到最大次数时,才会达到错误状态。以下屏幕截图显示了“云新闻”事件详细信息页面上的“订阅”相关列表。

Subscriptions related list shows the state of subscribed triggers

测试平台事件触发器

通过添加Apex测试,确保您的平台事件触发器正常工作。在将任何Apex代码(包括触发器)打包或部署到生产之前,您的Apex代码必须进行测试。要在Apex测试中发布平台事件,请将发布语句放在Test.startTest和Test.stopTest语句中。

// 创建测试事件
Test.startTest();
// 发布事件
Test.stopTest();
// 在这里执行验证
在测试上下文中,发布方法调用将发布操作排队。 Test.stopTest()语句导致事件发布被执行。 Test.stopTest()后,执行您的验证。

以下是我们的Cloud_News事件及其相关触发器的测试类示例。发布事件会导致关联的触发器触发。在Test.stopTest()之后,测试通过检查Database.SaveResult中的isSuccess()返回的值来验证发布是否成功。另外,测试查询触发器创建的情况。如果找到案例记录,则触发器成功执行,并通过测试。

@isTest
public class PlatformEventTest {
    @isTest static void test1() {
        // 创建测试事件实例
        Cloud_News__e newsEvent = new Cloud_News__e(
            Location__c='Mountain City', 
            Urgent__c=true, 
            News_Content__c='Test message.');
        
        Test.startTest();

        // 调用方法来发布事件
        Database.SaveResult sr = EventBus.publish(newsEvent);
        
        Test.stopTest();
        
        // 在这里执行验证

        // 验证发布是否成功
        System.assertEquals(true, sr.isSuccess());

        // 检查创建的触发器是否存在。
        List<Case> cases = [SELECT Id FROM Case];
        // 验证是否发现此案例。
        // 在测试上下文中只有一个测试用例。
        System.assertEquals(1, cases.size());
    }
}

使用点击订阅平台事件通知

要订阅没有代码的事件消息,请创建一个在发生平台事件时启动的进程。

此屏幕截图显示了一个进程在发生Cloud News事件时开始。当它开始时,该过程查找邮件城市匹配事件通知位置的联系人记录。

Process Builder matching criteria screen

同样,您可以通过使用Wait元素来订阅具有流程的平台事件消息。当发生平台事件时,不是启动流程,而是先前启动的流程等待平台事件,然后恢复。例如,以下是等待Cloud News事件消息发生的Wait元素。只有当事件的位置匹配{!MailingCity_Location.MailingCity}时才会继续。 {!MailingCity_Location}是流中的一个sObject变量。

Cloud Flow Designer Wait element

使用CometD订阅平台事件通知

外部应用程序使用CometD订阅平台事件并执行长时间轮询。平台应用程序(如Visualforce页面和Lightning组件)也可以使用CometD。 CometD是一个可扩展的基于HTTP的事件路由总线,它使用了一种名为Comet的AJAX推送技术模式。它实现了Bayeux协议。长轮询(也称为Comet编程)允许模拟从服务器到客户端的信息推送。与普通轮询类似,客户端连接并请求来自服务器的信息。但是,如果信息不可用,服务器不会发送空的响应,而是等待信息可用(发生事件)。

Salesforce提供了一个Java库EMP连接器,该连接器实现了连接到CometD和监听通道的所有细节。您可以使用EMP Connector轻松订阅平台事件。 EMP连接器隐藏了订阅事件的复杂性。有关EMP Connector的更多信息,请查看Streaming API开发人员指南中的Java客户端示例。

通过CometD订阅平台事件通知的过程与订阅PushTopic事件或通用事件类似。唯一的区别是频道名称。以下是平台事件主题(频道)名称的格式:

/event/<EventName>__e
例如,如果您有名为“云新闻”的平台事件,请在订阅时提供此频道名称。
/event/Cloud_News__e
在CometD URL末尾指定API版本,如下所示。
// 连接到CometD端点
    cometd.configure({
               url: 'https://<Salesforce_URL>/cometd/41.0/',
               requestHeaders: { Authorization: 'OAuth <Session_ID>'}
    });

JSON格式的平台事件消息

交付平台事件的消息与Cloud News事件的以下示例类似。

{
  "data": {
    "schema": "_2DBiqh-utQNAjUH78FdbQ", 
    "payload": {
      "CreatedDate": "2017-04-27T16:50:40Z", 
      "CreatedById": "005D0000001cSZs", 
      "Location__c": "San Francisco", 
      "Urgent__c": true, 
      "News_Content__c": "Large highway is closed due to asteroid collision."
    }, 
    "event": {
      "replayId": 2
    }
  }, 
  "channel": "/event/Cloud_News__e"
}

事件消息中的模式字段包含平台事件模式的标识(在本例中为“schema”:“_2DBiqh-utQNAjUH78FdbQ”)。模式是版本化的 – 当模式改变时,模式ID也改变。

要确定事件的模式是否已更改,请通过REST API检索模式。通过对此REST API资源执行GET请求来使用模式标识:/vXX.X/event/eventSchema/Schema_ID。或者,您可以通过将事件名称提供给此端点来检索事件模式:/vXX.X/sobjects/Platform_Event_Name__e/eventSchema。有关更多信息,请参阅Force.com REST API开发人员指南。

注意

与PushTopic和泛型事件不同,平台事件不支持使用过滤的订阅。例如,订阅/事件/ Cloud_News__e?Location__c =’旧金山’按位置过滤不受支持。

现在您已经看到了如何在Salesforce平台和外部应用程序中使用平台事件,这种可能性是无止境的!将平台事件用于任何数量的应用程序和集成,例如处理业务交易或参与主动客户服务。借助平台事件,您可以采用基于事件的编程模式,并享受基于事件的软件架构的优势。