Thursday, February 6, 2020

Salesforce Platform Events

Platform events are part of Salesforce’s enterprise messaging platform, providing an event-driven messaging architecture to enable apps to communicate inside and outside of Salesforce. An event-driven (or message-driven) software architecture consists of event producers, event consumers, and channels. The architecture is suitable for large distributed systems because it decouples event producers from event consumers, thereby simplifying the communication model in connected systems. One or more subscribers can listen to the same event and carry out actions.

Systems in request-response communication models make a request to a web service or database to obtain information about a certain state. The sender of the request establishes a connection to the service and depends on the availability of the service. Also, the external system pushing data into Salesforce is dependent on the completion of the transaction, i.e. if data is being pushed into an sobject and if there are triggers running on the data being pushed, then the external system must wait until all the business logic in the trigger completes its execution. 
In comparison, systems in an event-based model obtain information and can react to it in near real-time when the event occurs. Event producers don’t know the consumers that receive the events. Any number of consumers can receive and react to the same events. Both parties are also not dependent on each other.
The only dependency between producers and consumers is the semantic of the message content.

A platform event is a special kind of Salesforce entity, similar in many ways to an sObject. But
  1. Unlike custom or standard objects, you can’t update or delete event records. All platform event fields are read-only by default.
  2. You can set read and create permissions for platform events. Grant permissions to users in profiles or in permission sets. 
  3. You can’t restrict access to a particular field. Field-level security permissions don’t apply and the event message contains all fields.
  4. Because event publishing is equivalent to a DML insert operation, DML limits and other Apex governor limits apply.

Publish Immediately vs Publish After Commit

Platform event messages are published either immediately or after a transaction is committed, depending on the publish behavior you set in the platform event definition.
  1. Publish Immediately: The event message is published when the publish call executes. Select this option if you want the event message to be published regardless of whether the transaction succeeds. Also choose this option if the publisher and subscribers are independent, and subscribers don't rely on data committed by the publisher. For example, the immediate publishing behavior is suitable for an event used for logging purposes. With this option, a subscriber might receive the event message before data is committed by the publisher transaction. The allOrNone header is ignored when publishing through the APIs. Some events can be published even when others fail in the same call.
  2. Publish After Commit: The event message is published only after a transaction commits successfully. Select this option if subscribers rely on data that the publishing transaction commits. For example, a process publishes an event message and creates a task record. A second process that is subscribed to the event is fired and expects to find the task record. Another reason for choosing this behavior is when you don't want the event message to be published if the transaction fails. The allOrNone header value takes effect. If allOrNone is set to true, no events are published if at least one event fails in the same call.

High-Volume Platform Events

In API version 45.0 and later, your new custom event definitions are high volume by default. High-volume platform events offer better scalability than standard-volume platform events.
High-volume platform events are published asynchronously. After the publishing call returns with a successful result, the publish request is queued in Salesforce. The event message might not be published immediately.
High-volume platform event messages are stored for 72 hours. You can retrieve past event messages when using CometD clients to subscribe to a channel.
To know about high-volume platform event default allocations, check the documentation.

Publishing Platform Events

  • To publish event messages with Process Builder, add a Create a Record action to the appropriate process. Where you'd usually pick an object to create, select the custom platform event.

  • To publish event messages with flows, add a Create Records element to the appropriate flow. Where you'd usually pick an object to create, select the custom platform event.

  • To publish event messages with Apex, call the EventBus.publish method. Each EventBus.publish method call is considered a DML statement, and DML limits apply. The below code is taken from the documentation to show how to publish platform events with Apex.
    List<Low_Ink__e> inkEvents = new List<Low_Ink__e>(); 
    inkEvents.add(new Low_Ink__e(Printer_Model__c='XZO-5', Serial_Number__c='12345', Ink_Percentage__c=0.2)); 
    List<Database.SaveResult> results = EventBus.publish(inkEvents); 
    for (Database.SaveResult sr : results) { 
        if (sr.isSuccess()) { 
            System.debug('Successfully published event.'); 
        } else { 
            for(Database.Error err : sr.getErrors()) { 
                System.debug('Error returned: ' + err.getStatusCode() + ' - ' + err.getMessage()); 
            } 
        } 
    }

  • Publish events with Salesforce APIs such as SOAP API, REST API, or Bulk API. To publish a platform event message using REST API, send a POST request to the following endpoint: /services/data/v48.0/sobjects/Event_Name__e/

When publishing an event message, the result that the API returns contains information about whether the operation was successful and the errors encountered. If the success field is true, the event was published for a standard-volume event. For a high-volume event, the publish request is queued in Salesforce and the event message might not be published immediately. If the success field is false, the event publish operation resulted in errors, which are returned in the errors field.
The returned result also contains the Id system field. The Id field value is not included in the event message delivered to subscribers. It is not used to identify an event message, and is not always unique. Subscribers can use the ReplayId system field, which is included in the delivered message, to identify the position of the event in the stream.

Subscribing to Platform Events

  • Both processes and flows can subscribe to platform events and receive event messages published through Apex, APIs, flows, or other processes. Both of them provide an auto subscription mechanism.

  • To subscribe to event notifications with Apex Triggers, write an after insert trigger on the event object type. Only after insert triggers are supported for platform events because event notifications can’t be updated. They’re only inserted (published).
    trigger LowInkTrigger on Low_Ink__e (after insert) {    
        for (Low_Ink__e event : Trigger.New) {
         ...
         ...
        }
    }

    NOTE: In platform event triggers, if you create a Salesforce record that contains an ownerId field, set the ownerId field explicitly to the appropriate user. Platform event triggers run under the Automated Process entity. If you don’t set the ownerId field on records that contain this field, the system sets the default value of Automated Process.

  • Subscribe to platform events with the empApi component in your Lightning web component or Aura component.

  • Use CometD to subscribe to platform events in an external client. The process of subscribing to platform event notifications through CometD is similar to subscribing to PushTopics or generic events. The only difference is the channel name. The platform event channel name is case-sensitive and is in the following format: /event/Event_Name__e. Use this CometD endpoint with the API version appended to it: /cometd/48.0. You can refer the below code to subscribe to a platform event in a Node application.
  • const jsforce = require("jsforce");
    const dotenv = require("dotenv");
    const express = require("express");
    const session = require("express-session");
    
    dotenv.config({
        path: "./config/config.env"
    });
    
    const app = express();
    
    // Configure express-session to store Session Id and Instance URL
    app.use(
        session({ secret: "keyboard cat", resave: true, saveUninitialized: true })
    );
    
    const oauth2 = new jsforce.OAuth2({
        loginUrl: process.env.SF_LOGIN_URL,
        clientId: process.env.SF_CLIENT_ID,
        clientSecret: process.env.SF_CLIENT_SECRET,
        redirectUri: process.env.SF_REDIRECT_URI
    });
    
    app.get("/oauth2/auth", function(req, res) {
        res.redirect(
            oauth2.getAuthorizationUrl({ scope: "api id web refresh_token" })
        );
    });
    
    app.get("/oauth2/callback", function(req, res) {
        var conn = new jsforce.Connection({ oauth2: oauth2 });
        conn.authorize(req.query.code, function(err, userInfo) {
            if (err) {
                return console.error(err);
            }
            console.log(userInfo);
            console.log(conn.accessToken, conn.refreshToken, conn.instanceUrl);
    
            req.session.accessToken = conn.accessToken;
            req.session.instanceUrl = conn.instanceUrl;
    
            res.redirect("/");
        });
    });
    
    app.get("/", function(req, res) {
        if (!req.session.accessToken || !req.session.instanceUrl) {
            res.redirect("/oauth2/auth");
            return;
        }
        // Connect and output query results
        const conn = new jsforce.Connection({
            accessToken: req.session.accessToken,
            instanceUrl: req.session.instanceUrl
        });
        res.send(req.session.instanceUrl);
        subscribeToEvents(conn, res);
    });
    
    function subscribeToEvents(conn, res) {
        conn.streaming.topic("/event/DemoEvent__e").subscribe(function(message) {
            console.log(message);
        });
    }
    
    const PORT = process.env.PORT || 3000;
    
    app.listen(PORT, console.log(`Server running on ${PORT}`));

ReplayId System Field

Each event message is assigned an opaque ID contained in the ReplayId field. The ReplayId field value, which is populated by the system when the event is delivered to subscribers, refers to the position of the event in the event stream. Replay ID values are not guaranteed to be contiguous for consecutive events. A subscriber can store a replay ID value and use it on resubscription to retrieve events that are within the retention window.
You can replay platform events that were sent in the past 24 hours. You can replay platform events through the API (CometD) but not Apex. The process of replaying platform events is the same as for other Streaming API events. You can use workbench to replay the platform events.


Standard Platform Events

Salesforce provides events with predefined fields, called standard platform events. An example of a standard platform event is AssetTokenEvent, which monitors OAuth 2.0 authentication activity. Another example is BatchApexErrorEvent, which reports errors encountered in batch Apex jobs (check the code for force-brf - a batch retry framework, to understand how to handle such event). You can subscribe to a standard platform event stream using the subscription mechanism that the event supports. Check the documentation to go through all the standard platform events.

Limits

Check the documentation to learn about the allocations available for platform event definitions, publishing and subscribing to platform events, and event delivery in CometD clients. The below table provides information about the default allocation for the high-volume events.
Please note the following points:
  1. The maximum event message size that you can publish is 1 MB. If your event object has hundreds of custom fields or many long text area fields, you could hit this limit. In this case, the publishing call gets an error.
  2. Non-CometD clients, including Apex triggers, processes, and flows, don’t count against the event delivery limit.
  3. The empApi Lightning component is a CometD client. As a result, the event delivery allocation applies to the component and it is per channel per unique browser session.
  4. Platform events ARE quite capable when only used “on-platform”. Read this blog to understand in detail.

Some important StackExchange links

Other important links



Share This:    Facebook Twitter

Wednesday, October 9, 2019

Tuesday, October 1, 2019

A basic Salesforce to Salesforce integration using REST API and OAuth

You can use a connected app to request access to Salesforce data on behalf of an external application. For a connected app to request access, it must be integrated with the Salesforce API using the OAuth 2.0 protocol.

1. Create a connected app in one of the Salesforce instances as below:

You will need to replace the callback URL after the completion of step 2.

2. Create an Auth Provider. Replace the consumer key and secret with the values.

Replace the callback URL in the connected app with the callback URL generated while creating this auth provider.

3. Create a named credential

4. Some Apex code
HttpRequest req = new HttpRequest();
req.setEndpoint('callout:Cross_Org_Report/services/data/v45.0/query?q=select+Email,FirstName,LastName+from+contact');
req.setMethod('GET');
Http http = new Http();
HTTPResponse response = http.send(req);
return response.getBody();

Share This:    Facebook Twitter

Sunday, August 18, 2019

LWC: Implementing Service Components


A service component is a component that provides an API for a set of functionalities. Ideally, the service should be specialized, generic and reusable. Also, it does not have a markup, i.e. it is not visible by default.

Creating a custom service simplifies component’s code and help reduce code duplication. This in turns makes the code more robust and facilitates maintenance.

To develop a custom service component for my Account object, I have created an accountService component and exposed the below services:
  • searchAccount: it accepts a search key and returns the list of accounts matching the key
  • getAccounts: this returns a list of 5 accounts

You will notice that I have followed the singleton pattern to define this component, i.e. there can be only one instance of this component. Now to get a reference to these custom services, I have created an accountComponent which is consuming the services like below:

Please see the below repo for the code:
https://github.com/iamsonal/lwc-service

References:
https://developer.salesforce.com/blogs/2018/08/implement-and-use-lightning-service-components.html
Share This:    Facebook Twitter

Total Pageviews

My Social Profiles

View Sonal's profile on LinkedIn

Tags

__proto__ $Browser Access Grants Accessor properties Admin Ajax AllowsCallouts Apex Apex Map Apex Sharing AssignmentRuleHeader AsyncApexJob Asynchronous Auth Provider AWS Callbacks Connected app constructor Cookie CPU Time CSP Trusted Sites CSS Custom settings CustomLabels Data properties Database.Batchable Database.BatchableContext Database.query Describe Result Destructuring Dynamic Apex Dynamic SOQL Einstein Analytics enqueueJob Enterprise Territory Management Enumeration escapeSingleQuotes featured Flows geolocation getGlobalDescribe getOrgDefaults() getPicklistValues getRecordTypeId() getRecordTypeInfosByName() getURLParameters Google Maps Governor Limits hasOwnProperty() Heap Heap Size IIFE Immediately Invoked Function Expression Interview questions isCustom() Javascript Javascript Array jsForce Lightning Lightning Components Lightning Events lightning-record-edit-form lightning:combobox lightning:icon lightning:input lightning:select LockerService Lookup LWC Manual Sharing Map Modal Module Pattern Named Credentials NodeJS OAuth Object.freeze() Object.keys() Object.preventExtensions() Object.seal() Organization Wide Defaults Override PDF Reader Performance performance.now() Permission Sets Picklist Platform events Popup Postman Primitive Types Profiles Promise propertyIsEnumerable() prototype Query Selectivity Queueable Record types Reference Types Regex Regular Expressions Relationships Rest API Rest Operator Revealing Module Pattern Role Hierarchy Salesforce Salesforce Security Schema.DescribeFieldResult Schema.DescribeSObjectResult Schema.PicklistEntry Schema.SObjectField Schema.SObjectType Security Service Components Shadow DOM Sharing Sharing Rules Singleton Slots SOAP API SOAP Web Services SOQL SOQL injection Spread Operator Star Rating stripInaccessible svg svgIcon Synchronous this Token Triggers uiObjectInfoApi Upload Files VSCode Web Services XHR
Scroll To Top