利用TwilioEvent Streams流化Twilio StudioFlow的执行

424 阅读7分钟

在这篇文章中,你将学习如何用TwilioEvent Streams来流化Twilio StudioFlow的执行。随着Studio事件在事件流中得到完全支持,你现在可以利用webhooks来触发外部工作流,或在Studio中执行流程时实时记录步骤。

在Studio支持事件流之前,你有两种方法来实现这一点。

  1. 在整个流程中添加HTTP请求部件,将事件推送给外部应用程序 - 这增加了流程的复杂性,而且主要是一个手动过程。
  2. 轮询API的 "执行 "和 "步骤 "端点,为报告检索完整的日志--这需要按计划运行批处理作业来翻阅所有的记录,是一个很麻烦的过程。

那么,为什么这个有用呢?

  • 它为你提供了额外的选择,以触发单一的webhook端点之外的程序化行动
  • 它消除了你的服务和Twilio API结果/响应之间的同步依赖。
  • 它提供了比标准webhook响应更好的重试和交付保证。
  • 它是现代微服务架构的一种整合方法,因为它允许各自的系统独立运行。

需要什么

这个应用程序有四个主要部分。

  • 在你的Twilio账户上配置的一个汇流目的地
  • 一个监听Twilio账户事件的Node.js后端
  • 一个到本地后端服务器的ngrok隧道
  • 一个基本的前端来渲染来自Twilio账户的事件

构建

创建一个Webhook Sink

汇是指在订阅中选择的事件将被传递到的目的地。Twilio Event Streams支持Amazon Kinesis和webhook汇。我们将在本博客中使用webhook汇。在创建webhook sink时,我们需要提供一个可公开访问的URL来配置webhook服务。请看Phil Nash关于如何使用ngrok设置的帖子

从你的命令提示符或终端运行以下命令。

ngrok http 3000

Tunnel details for ngrok

现在你有了自己的可公开访问的URL(我的在上面的红框内突出显示),是时候在一个新的终端会话中创建一个webhook sink。

twilio api:events:v1:sinks:create --description webhook-studio-sink \
--sink-configuration '{"destination":"<your publicly accessible URL>/studio","method":"POST","batch_events":false}' \
--sink-type webhook

在你的终端上运行上述命令时,记得用你的实际URL替换<你的可公开访问的URL>。一旦你运行了你的命令,你会看到一个带有你的汇的SID的响应。请确保你保存你的水槽SID!

Sink Detais

你也可以在Twilio控制台的事件流页面上验证你的汇已经被创建。Sink Details on Twilio's Console

请注意,在生产应用中,你会在一个在线托管的专用服务器上设置一个webhook,但为了测试,你将使用一个带有ngrok隧道的本地服务器。此外,如果你使用的是ngrok的免费版本,你将需要在本博客的其余步骤中保持这个隧道会话的开放。这是因为在免费版本中,每个会话都会产生一个新的公共URL,它将不再是与我们水槽的目标URL相同的URL。

订阅基于工作室的事件

我们现在将使用Subscriptions API来订阅特定的Studio事件。

Studio事件流有3种我们可以订阅的事件类型。

  1. 执行开始: 在每次执行开始时触发
  2. **步骤结束:**在一个执行过程中,每次完成一个步骤都会发生。
  3. **执行结束:**在每个执行过程结束时触发。

让我们来订阅所有这3个程序吧

在一个新的终端会话中(记住不要关闭步骤1中的ngrok会话),运行以下命令。

twilio api:events:v1:subscriptions:create \
  --description "Studio Webhook Subscriptions" \
  --sink-sid <Your sink SID from Step 1> \
  --types '{"type":"com.twilio.studio.flow.execution.started","schema_version":1}' \
  --types '{"type":"com.twilio.studio.flow.execution.ended","schema_version":1}' \
  --types '{"type":"com.twilio.studio.flow.step.ended","schema_version":1}'

再次,在运行上述命令时,确保用你在步骤1中创建的实际水槽SID替换<你的水槽SID>。

设置一个后端服务器来监听基于工作室的事件

现在是时候使用Express设置我们的后端服务器了,它将监听以HTTP请求形式出现的事件流的水槽目标地址。

在你的电脑上创建一个名为event-streams的文件夹。这将是你项目的根目录,并将容纳你的前端和后端文件夹。

mkdir event-streams
cd event-streams
mkdir src
cd src

在src目录下创建一个文件,称为app.js,并在该文件中添加以下脚本。

const path = require('path')
const http = require('http');
const express = require('express');
const bodyParser = require('body-parser');
var io = require('socket.io');
const app = express();
const publicDirectoryPath = path.join(__dirname, '../public')
app.use(bodyParser.json());
app.use(express.static(publicDirectoryPath));

const server = http.createServer(app).listen(3000, () => {
    console.log('Express server listening on port 3000')
})

io = io(server);
app.use(function(req, res, next) {
  req.io = io;
  next();
});

io.on('connection', function(socket) {
    console.log('socket.io connection made');
});

app.post('/studio', (req, res) => {
    console.log(req.body);
    if (req.body[0].type == 'com.twilio.studio.flow.execution.started') {
        req.io.send(JSON.stringify(req.body[0]));
        console.log('started')
    } else if (req.body[0].type == 'com.twilio.studio.flow.execution.ended') {
        req.io.send(JSON.stringify(req.body[0]));
        console.log('ended')
    } else {
        req.io.send(JSON.stringify(req.body[0]));
        console.log(`${req.body[0].data.execution_sid} - ${req.body[0].data.name} - progress`)
    }
});

上述脚本作为你的后端,监听传递到/studio端点的事件,我们在第1步中指定了我们的水槽目的地。

连接前端

回到你的命令提示符,浏览你的项目的根目录_(event-streams)_,并运行以下命令来创建公共目录,我们将在那里为前端添加我们的html、css和javascript文件。

mkdir public
cd public

在_event-streams/public_文件夹中创建一个名为index.html的文件,并在该文件中添加以下HTML脚本。

<!DOCTYPE html>

<html>

<head>
    <link rel="stylesheet" href="./styles.css">
    <title>Studio Event Streams</title>
</head>

<body>
    <script src="/socket.io/socket.io.js"></script>
    <script>const socket = io();</script>
    <h1>Studio Event Streams</h1>

    <p id="message-1"></p>
    <script src='./app.js'></script>
</body>

</html>

接下来,创建一个css文件,命名为style.css。在这个文件中添加以下的样式定义。

body {
    color: #333333;
    font-family: arial;
}

h1 {
    font-size: 64px;
    margin-bottom: 16px;
}

div[id^=event] {
      margin-bottom: 20px;
  }

最后,我们创建一个javascript文件,该文件使用socket.io库来实现浏览器和我们的后台服务器之间的实时、双向和基于事件的通信,以渲染我们的Studio事件。

var idMap = new Map();
var executionMap = new Map();

socket.on("connect", () => {
  console.log('connected');
});

socket.on("message", data => {
  let parsedResponse = JSON.parse(data);
  let parsedData = parsedResponse.data;
  let eventType = parsedResponse.type;

  let currentKey = `${parsedResponse.id}-${eventType}`;

  if (!idMap.has(currentKey)) {
    if (executionMap.has(parsedData.execution_sid)) {
      let flowParentDiv = document.querySelector(`#event_${parsedData.execution_sid}`);
      let flowChildDiv = document.createElement('div');
      flowChildDiv.setAttribute("class", `step_${parsedData.execution_sid}`);
      renderEvent(flowParentDiv, flowChildDiv, eventType, parsedData);
    }
    else {
      let flowParentDiv = document.createElement('div');
      flowParentDiv.setAttribute("id", `event_${parsedData.execution_sid}`);
      document.body.append(flowParentDiv);
      let flowChildDiv = document.createElement('div');
      flowChildDiv.setAttribute("class", `step_${parsedData.execution_sid}`);
      executionMap.set(parsedData.execution_sid, true);
      renderEvent(flowParentDiv, flowChildDiv, eventType, parsedData);
    }
    idMap.set(currentKey, true);
  }

});

function renderEvent(flowParentDiv, flowChildDiv, eventType, parsedData) {
  let eventName = parsedData.name
  if (!eventName) {
    eventName = "Flow Start/End"
  }
  const childContent = `Flow: ${parsedData.execution_sid} | Event Created Time: ${parsedData.date_created} | Event Type: ${eventType} | <b>Event Name: ${eventName}</b>`
  flowChildDiv.innerHTML = childContent;
  flowParentDiv.append(flowChildDiv);
}

测试你的应用程序

现在你的后端和前端文件已经建立起来了,是时候测试一下了!

在这一点上,你应该已经准备好启动你的服务器并运行你的应用程序了在你的终端,重定向到你的项目目录,并输入以下命令。

node src/app.js

这将在3000端口启动一个本地服务器,你将能够在http://localhost:3000,查看你的应用程序。

它将看起来类似于这样。

Event Streams Dashboard

现在是时候从你的账户中执行一个Studio Flow了,你可以打电话或发短信给与你的Studio Flow相关的Twilio电话号码。你也可以通过API调用来触发一个Studio Flow。

下面是事件开始实时渲染到你的前端时的快速外观。

Event Streams Dashboard While Streaming Events

总结

本教程提供了一个使用Twilio事件流与Studio的小窗口。这是一系列博客中的第一篇。在第二篇博客中,我将说明你如何轻松地创建一个Studio流程的可视化地图。除了渲染事件,你还可以创建实时的可视化,消费这些事件流并将其汇总到图表中。也许,你可以创建一个仪表盘,显示用户在与建立在Studio上的IVR解决方案互动时如何做出决定的指标。

我迫不及待地想看到你所建立的东西!

Shashwat Johari是Twilio的一名解决方案工程师,也是一名终身的技术爱好者,目前生活在Twilio的API世界里。你可以通过sjohari [at] twilio.com找到Shashwat。