Platform Events

Що це таке і де використовується

Всім привіт. В цій статті я би хотів розказати вам про Platform events (якщо дозволите, я не перекладатиму подібні терміни). Ми спробуємо на прикладі розібрати, що це таке, а також я додам декілька слів про те, де я зустрічав цей функціонал на власній практиці.
Platform events є частиною Salesforce-платформи з обміну повідомленнями. Якщо ви колись чули про event-driven-підхід в архітектурі, то це якраз воно.
Platform events дозволяють обмінюватись інформацією як всередині Salesforce, так і з зовнішніми сервісами.
Такий підхід значно полегшує обмін повідомленнями, особливо в розгалужених системах. До того ж не потребує написання комплексної логіки.
Platform events можна реалізувати суто декларативним підходом (без написання коду) - для когось, можливо, це теж буде плюсом.

Загальна структура

Event-driven-архітектура складається з того, хто публікує event message (Event Publisher), каналу, куди публікується message (Event Bus) та з того, хто підписаний (слухає) на канал (Event Listener):
Прикладом event може бути зміна якихось показників/замірів/тощо, а event message - саме повідомлення, що містить деталі замірів, будь-яку додаткову інформацію.

Platform events можуть бути стандартними і кастомними. Salesforce публікує стандартні events на певні події або, коли рапортує про помилки в системі. Окремо я би виділив Change Data Capture Events - публікуються на create/edit/delete/undelete записів стандартних і кастомних об’єктів (саме об’єктів, а не events).

Кастомний event дуже схожий на кастомний об’єкт в Salesforce. В API Name __e в кінці замість __c. Він теж може містити кастомні поля різних типів. Щоб підписати або опублікувати кастомний event, його спершу треба створити.

Наразі, опублікувати event можливо наступними способами:

  • Process Builder - через стандартний Create Record action. Треба тільки обрати кастомний event, як об’єкт і заповнити значення кастомних полів.
  • Flow - аналогічно, теж за допомогою стандартного Create Record елемента, обравши в якості об’єкта кастомний event.
  • Apex - треба ініціалізувати екземпляр кастомного event і опублікувати його:
    // Create event
Event_Name__e event = new Event_Name__e();
// Set field values
event.Field_Name1__c = 'value';
// Publish event (inspect publishing result for each event if needed)
Database.SaveResult results = EventBus.publish(event);
  • API (REST, SOAP, Bulk) - наприклад, для публікації через REST API треба зробити POST запит на /services/data/v58.0/sobjects/Event_Name__e/ ендпоінт, а в тілі запита вказати
    { "Field_Name1__c" : "value" }.

Публікувати можна до 100.000 event на годину.
Зберігаються до 72 годин в Message Bus (старі версії - до 24 годин).

Підписатись на Platform Events можна за допомогою:

  • Flow - тут можна або стартувати флоу по якомусь event (обрати Platform Event - Triggered Flow, а в Start елементі обрати потрібний event, який буде запускати флоу) або гальмувати флоу за допомогою Pause елемента і для продовження роботи обирати умову по event (A Platform Event Message is Received):
    Як бачите, підписатись можливо і на стандартні events.

  • Process Builder - треба обрати A platform event message is received причиною запуска.

  • Apex Trigger - просто створити after insert тригер на event по аналогії з кастомним об’єктом.

  • LWC - треба імпортувати і використовувати відповідний метод з lightning/empApi модуля:
    import { subscribe } from 'lightning/empApi;

  • Aura Component - треба використовувати lightning:empApi компонент.

  • Pub/Sub API - цей підхід, зазвичай, використовується для інтеграції Salesforce з зовнішніми системами. Сам я не мав досвіда роботи з цією API. При необхідності, в офіційній документації все детально описано.

  • CometD - штука, схожа на попередню, так само, більш детально можна ознайомитись в документації.

Приклад використання

Давайте розглянемо приклад публікації Platform Event за допомогою Apex та слухатимо його за допомогою FLOW. Результатом FLOW для наочностi буде сповіщення юзера у “дзвіночок” (Notifications) кожного разу, коли публікується меседж у Platform Event.

Першим кроком створюємо Platform Event.

Setup → Quick Find → Platform Event

Заповнюємо стандартний набір полів, а також обираємо Publish Behavior.

Publish Behavior може бути двох типів Publish After Commit, Publish Immediately

Publish After Commit - повідомлення публікується лише після успішної фіксації транзакції. Якщо транзакція не пройде, то повідомлення не буде запаблішенно.

Publish Immediately - повідомлення публікується коли виконується виклик публікації, незалежно від успішності транзакції. Слухач отримує повідомлення про подію до того як дані будуть зафіксовані.

Для нашого прикладу оберемо Publish Immediately.

Наступним кроком ми створюємо кастомні поля для Platform Event. Для прикладу нам достатньо одного поля Message із типом Text

У такі нескладні кроки ми створили новий Platform Event - Notification__e

Apex Publisher

Створюємо новий класс NotificationEvent, який буде публікувати повідомлення у щойно створенний Platform Event.

public class NotificationEvent {

  public static void publishMessage (String msg) {
    Notification__e event = new Notification__e();
    event.Message__c = msg;
    Database.SaveResult results = EventBus.publish(event);
  }

}

Flow Subscription

Попередньо створимо Custom Notification

Створюємо нове Flow, обираємо Platform Event—Triggered Flow

Обираємо Platform Event

Створюємо змінну RecipientIDs

Та додаємо до неї ID потрібного нам юзера (в прикладі я використовую ID свого юзера)

Додаємо Get Records елемент. Обираємо Custom Notification Type об’єкт та додаємо фільтр DeveloperName = Platform_Event_Massage

Далі створюємо CustomNotification

Також для відпрацьовування Send Custom Notification потрібно вказати Target ID або Target Reference Page, це той запис або пейджа куди буде редіректити при натисканні на це повідомлення. У прикладі я використовував Target ID з додаванням статичної ID від Opportunity, бо налаштування Send Custom Notification не є частиною цієї статті.

В результаті в нас вийде наступне FLOW

Зберігаємо його та активуємо.

Тепер можемо подивитись як відпрацьовує Platform Event.

Викликаємо Apex клас за допомогою Anonymous Window

NotificationEvent.publishMessage('Hello world');

В результаті ми отримуємо сповіщення у “дзвіночок”

Як бонус додам приклад як ми можемо запаблішити message за допомогою REST.

За допомогою Workbench.com відкриваємо REST explorer та робимо наступний запит

Type: POST

URL: /services/data/v58.0/sobjects/Notification__e

Request Body:
{
  "Message__c" : "My REST Notification"
}

Отримуємо такий самий результат, сповіщення у “дзвіночок”

Висновки

В цій статті я хотів показати, наскільки гнучким і зручним у використанні інструментом можуть бути Platform Events.

Я вперше познайомився з Platform Events на проекті з B2B Lightning.

Також мені довелося працювати з Nebula Logger - потужним рішенням для логування, побудованим якраз на Platform Events. Якщо коротко, то логування відбувається не напряму в кастомний лог-об’єкт, а через публікацію кастомних events. Це дозволяє, наприклад, уникнути помилки, коли би ми мали DML-операцію перед колаутом в тій самій транзакції (You have uncommitted work pending. Please commit or rollback before calling out).

6 Вподобань

Доброго дня. Дякую за змістовну статтю. Підкажіть, будь ласка, чи можна за допомогою Platform Events реалізувати пошук сторінки користувача та відкриття окремої вкладки в SalesForce? Вважаємо що агент вже залогінився в SalesForce і в браузері є відкрита сторінка, також, у агента є всі права для пошуку та перегляду даних користувачів.

Ситуація така: з чату на стороні бекенда приходить email користувача. Я хочу відправити цей email до SalesForce через REST API, використовуючи Platform Events, і щоб у відповідь в режимі реального часу відкривалася SalesForce сторінка цього користувача в окремій вкладці, знайдена за email.

Чи можливо це реалізувати за допомогою Platform Events у SalesForce? Завчасно дякую.

Вітаю, Євгене. Інтеграція з цим бекендом, скоріше за все, налаштована буде через Connected App. Навіть, якщо на момент відправки платформ івента в СФ буде залогінений юзер, ця інтеграція матиме свою окрему сесію і окремий контекст. Як варіант, ви можете передати в повідомленні ел. пошту і RecipientID (якщо бекенд його знає). Або через SOQL витягнути ID залогіненого юзера (а їх може бути декілька одночасно?). Тоді для цього юзера в СФ вискочить нотифікація (як в статті), з якої можна перейти на відповідну сторінку

Дуже дякую за відповідь. Скажіть будь ласка, використання Connected app дозволяє змінювати вміст вкладки SalesForce або відкривати нову вкладку без взаємодії з юзером, лише “смикаючи” ендпоінти з 3rd party app? Тобто, наприклад, якщо я відкрив 2 вікна браузера поряд, в одному з яких 3rd party app, а в іншому SalesForce, то виконуючи запити в 3rd party app, я в режимі реального часу буду бачити у вікні з SalesForce оновлення сторінки, або відкриття нових вкладок без прямої взаємодії з SalesForce вікном, ніби “воно само робиться”?

якщо ми будемо робити запити з СФ назовні, то ConnApp (на СФ стороні) не знадобиться. Можна просто зробити LWC компонент, який буде робити реквест, парсити респонс і показувати актуальні дані. Якщо треба, можна з цього ж LWC відкрити нову сторінку (вкладку).

В цьому випадку ми будемо в тому самому контексті → можливостей набагато більше.

Можна використовувати Salesforce Connect або інші аналогічні підходи. Тут вже дуже багато можливостей, залежить від умов, бізнес-моделі тощо

Ще питання: LWC компонент вміє приймати запити зі стороннього аппу, а не тільки слати їх назовні?

в СФ є стандартний REST API, можна створити кастомний. LWC може використовувати їх. Або ж LWC може підписатись на Platform Event і реагувати в режимі реального часу