Slack Alerts for Genesys Cloud Flow Changes
A little while ago I wrote a tool to notify people over Slack when a Genesys Cloud flow was updated. It was a simple tool, but it became very useful for adding explanations to changes, understanding the frequency of updates, and correlating changes to downstream service alerts. Here’s a breakdown of how it works.
The Slack message above shows what is automatically sent when a new version of a flow in Genesys Cloud is published. I included all the details I thought would be useful:
Name of the updated flow
Flow Description
New Version
Who made the change
Link to conversations using the flow
How it works
The solution, diagrammed above is as simple as I could make it. It consists of 3 parts:
Amazon EventBridge Integration used to trigger a Lambda when flows in Genesys Cloud are updated
Triggered Lambda uses details in the event to create a Slack message
Lambda calls Slack Webhook URL to send the message
Let’s go into each point in more detail.
1. Detecting when a flow is updated
Detecting when a flow has been updated is possible by configuring Genesys Cloud’s Amazon EventBridge Integration to publish notifications for the v2.flows.{id} topic.
These notifications are filtered by an EventBridge Rule to only trigger the Lambda when a flow has been successfully published:
{
"detail-type": ["v2.flows.{id}"],
"detail": {
"eventBody": {
"currentOperation": {
"actionStatus": ["SUCCESS"],
"actionName": ["PUBLISH"]
}
}
}
}
2. Create Slack message from event
When I created the tool I made the conscious decision to keep it simple by using only the details in the v2.flow.{id}
notification, and not going off to other Platform API endpoints.
Thankfully the notification contained all the information I needed. The code below is that of the Lambda’s handler, and shows it extracting all the relevant fields:
/* handler.ts */
async function handler(
event: EventBridgeEvent<typeof v2FlowsEventDetailType, v2FlowsEvent>
): Promise<void> {
const flowPublished = transformEvent(event.detail);
await slackClient.sendMessage(
flowUpdatedMessage({
flow: {
name: event.detail.eventBody.name,
description: event.detail.eventBody.description,
version: event.detail.eventBody.publishedVersion.id,
},
editor: {
name: flowPublished.editor.name,
profile: flowPublished.editor.profileUrl,
},
flowInteractionsPage: performanceInteractionLinkBuilder(
event.detail.eventBody.id
),
})
);
}
/* transformEvent.ts */
export function transformEvent(
{ eventBody }: v2FlowsEvent
): FlowUpdatedEvent {
let editor: EditorDetails;
if (eventBody.currentOperation.user) {
const userDetails = eventBody.currentOperation.user;
editor = {
type: "user",
id: userDetails.id,
name: userDetails.name,
profileUrl: profileLinkBuilder(userDetails.id),
};
} else if (eventBody.currentOperation.client) {
const clientDetails = eventBody.currentOperation.client;
editor = {
type: "oauth",
id: clientDetails.id,
name: clientDetails.name,
profileUrl: oauthClientLinkBuilder(clientDetails.id),
};
} else {
editor = {
type: "unknown",
};
}
return {
editor,
flow: {
name: eventBody.name,
description: eventBody.description,
version: eventBody.publishedVersion.id,
},
};
}
3. Sending the Slack message
After the details have been extracted we transform them into a message schema for Slack’s Block Kit UI schema. This schema allows more complex messages than just a block of text.
Once the Block Kit UI’s JSON has been created then it’s simply a case of sending it in the body of a POST request to the preconfigured Webhook URL.
/* flowUpdatedMessage.ts */
export function flowUpdatedMessage({
flow,
editor,
flowInteractionsPage,
}: {
flow: {
name: string;
description: string | undefined;
version: string;
};
editor: { name: string; profile: URL };
flowInteractionsPage: URL;
}): SlackMessage {
return {
build(): string {
return JSON.stringify({
text: `Flow updated: ${flow.name}`,
blocks: [
{
type: "section",
text: {
type: "mrkdwn",
text: "A *flow was updated!*",
},
},
{
type: "section",
fields: [
{
type: "mrkdwn",
text: `*Name:*\n${flow.name}`,
},
...(!flow.description
? []
: [
{
type: "mrkdwn",
text: `*Description:*\n${flow.description}`,
},
]),
{
type: "mrkdwn",
text: `*By:*\n<${editor.profile.href}|${editor.name}>`,
},
{
type: "mrkdwn",
text: `*Version:*\n${flow.version}`,
},
],
},
{
type: "context",
elements: [
{
type: "mrkdwn",
text: `<${flowInteractionsPage.href}|Latest conversations using this flow>`,
},
],
},
],
});
},
};
}
/* AxiosSlackClient.ts */
export class AxiosSlackClient implements SlackClient {
private readonly axiosInstance: AxiosInstance;
public constructor(
webhookUrl: string,
axiosInstanceFactory: Pick<typeof axios, "create"> = axios
) {
this.axiosInstance = axiosInstanceFactory.create({
baseURL: webhookUrl,
headers: {
"Content-Type": "application/json",
},
});
}
public async sendMessage(message: SlackMessage): Promise<void> {
await this.axiosInstance.post(undefined, message.build());
}
}
The result is the message below being published to the Slack Channel configured against the Webhook URL:
What’s next…
I have always seen this tool, whilst useful, as a stepping stone to a much more audacious project: Tracking every flow change in GitHub!
Having changes committed to GitHub would open up the ability to do some pretty cool things:
Lint flow evaluations
Publish notifications to Slack (with patch-sets, change descriptions)
Auto-generate diagrams for living documentation
Easily identify who changed a specific part of a flow (e.g. Git Blame)
Follow me on LinkedIn if you’d like to track my progress on this.
Conclusion
This was a straightforward tool to build but proved very useful. It is also a great project for someone to try out who may not have built anything using Genesys Cloud’s EventBridge Integration before.
If you do build it, or already have then I’d love to hear about your experiences. Just ping me on LinkedIn.