影响代理消息递送时间的一个主要因素是, 您尝试联系的用户在您的代理时已有数据连接 发送消息。如果用户处于离线状态,RBM 平台会存储消息和 最多尝试投放 30 天。如果消息在此之前无法传送,系统会将其从系统中移除。
在很多情况下,当客服人员尝试与用户联系时,用户可能无法连接。他们可能关闭了移动流量以节省移动流量费用,也可能在没有 Wi-Fi 连接的飞机上,或者在隧道中的地铁上。根据消息需要送达的紧急程度,代理需要通过撤消未送达的 RBM 消息并通过其他渠道重新路由这些消息,以妥善处理离线用户。
以下部分详细介绍了如何使用 Google Cloud Datastore 跟踪您发送和传送的消息、如何使用 cron 撤消未传送的消息,以及如何通过短信重新路由这些消息。
跟踪发送的邮件
RBM 代理发送的每条消息都必须包含唯一的消息 ID。如需跟踪客服人员发送的消息,您需要保存每条消息的消息 ID、电话号码和时间戳。
您可以使用各种技术来存储此类信息,包括 Google Cloud Datastore。Cloud Datastore 是一个可扩缩性极强的 NoSQL 数据库,可自动处理分片和复制操作。非常棒 解决方案,用于存储非关系型数据,例如代理发送的消息。 Cloud Datastore 依赖于 Google App Engine 实例,这样您就可以 使用 App Engine 托管 RBM 代理并配置 Cron 作业。
Cloud Datastore 客户端库支持多种语言。在本例中,您可以使用 Node.js,并根据 RBM 开发者网站上提供的第一个代理 Node.js 示例编写 RBM 代理代码。首先,运行以下命令为我的 Node.js 项目安装 Cloud Datastore:
npm install --save @google-cloud/datastore
在代理源代码中,添加对 Cloud Datastore 客户端的全局引用 库。
// Imports the Google Cloud client library
const Datastore = require('@google-cloud/datastore');
// Creates a client
const datastore = new Datastore({
projectId: PROJECT_ID,
});
创建数据存储区对象后,您可以引入一个函数来存储
每条消息的 msisdn、message id、sent time 和 delivery 状态。
/**
* Records an entry in the Cloud Datastore to keep track of the
* messageIds sent to users and the delivery state.
*
* @property {string} msisdn The user's phone number in E.164 format.
* @property {string} messageId The unique message identifier.
* @property {boolean} delivered True if message has been delivered.
*/
function saveMessage(msisdn, messageId, delivered) {
const messageKey = datastore.key(['Message', messageId]);
const dataForMessage = {
key: messageKey,
data: {
id: messageId,
msisdn: msisdn,
lastUpdated: new Date().getTime(),
delivered: delivered
},
};
// Record that the message was sent.
datastore
.save(dataForMessage)
.then(function() {
console.log('saved message successfully');
})
.catch((err) => {
console.error('ERROR:', err);
});
}
设置此函数后,每当您的客服人员向用户发送消息时,您都需要调用此方法。使用 RBM Node.js 客户端时
库
发送 RBM 消息,则库在回调中提供响应对象
方法,包含已发送到messageId
用户。
以下示例展示了如何在成功与 RBM API 通信后向用户发送纯文本消息并记录消息信息。
let params = {
messageText: 'Hello, World!',
msisdn:'+12223334444',
};
// Send "Hello, World!" to the user.
rbmApiHelper.sendMessage(params,
function(response) {
// Extract the message ID from the response
let messageId = response.config.params.messageId;
// Store the sent state in the Datastore
saveMessage(phoneNumber, messageId, false);
});
运行代码后,您可以在 Google Cloud 控制台的 Datastore 实体视图中检查 Datastore。
更新邮件的递送状态
现在,您的代理会将已发送的消息请求存储在 Datastore 中,因此请在消息成功传送到用户设备后更新传送状态。
用户的设备通过 Cloud Pub/Sub 将 DELIVERED、READ 和 IS_TYPING 事件发送到 RBM 代理。在 Pub/Sub 的处理程序中,检查传送的事件
并将已传送标志的 Datastore 设置更新为 true。
/**
* Uses the event received by the Pub/Sub subscription to send a
* response to the client's device.
* @param {object} userEvent The JSON object of a message
* received by the subscription.
*/
function handleMessage(userEvent) {
if (userEvent.senderPhoneNumber != undefined) {
let msisdn = userEvent.senderPhoneNumber;
let messageId = userEvent.messageId;
let eventType = userEvent.eventType;
if(eventType === 'DELIVERED') {
saveMessage(msisdn, messageId, true);
}
// TODO: Process message and create RBM response
}
}
代理会将外发邮件保存到 Datastore,并在收到传送通知时更新数据。在下一部分,了解如何设置 Cron 在 Google App Engine 上每 10 分钟运行一次作业,以监控未传送的 消息。
Google App Engine 上的 Cron
您可以使用 Cron 作业按不同的时间间隔安排任务。在 Google 的 App Engine 中,Cron 作业是通过说明、网址和间隔时间进行配置的。
在 Node.js 应用中,您可以在 cron.yaml 文件中进行配置,然后使用 Google Cloud SDK 将该文件部署到 App Engine。如需了解其他语言配置设置,请参阅使用 cron.yaml 安排作业。
由于 Cron 任务需要网址,因此您需要向 Express 由 Cron 调用的应用路由器。此网络钩子负责查询数据存储区中的旧消息,将其从 RBM 平台中删除,并通过短信将其发送给用户。
router.get('/expireMessages', function(req, res, next) {
// TOOD: Query the Datastore for undelivered messages,
// remove them from the RBM platform, and send them over SMS
res.status(200).send();
});
以下是每 10 分钟执行此端点的 cron.yaml 文件配置。
cron:
- description: "Processing expired RBM messages"
url: /expireMessages
schedule: every 10 mins
如需将 Cron 任务部署到 App Engine,请运行以下命令:
gcloud app deploy cron.yaml
部署后,App Engine 会自动配置 Cron 任务,您可以在 App Engine > Cron 作业下查看该任务。
查询数据存储区中是否有未传送的消息
在您在前面部分设置的 cron 作业的 webhook 中,您需要添加逻辑来查找所有已发送的消息,这些消息的 delivered 状态均为 false,并且 lastUpdated 时间大于适用于我们的用例的预定义超时时间。在此示例中,系统会让超过一小时的邮件失效。
为了支持这样的复合查询,数据存储区需要包含同时包含 delivered 和 lastUpdated 属性的复合索引。为此,您可以在项目中创建一个名为 index.yaml 的文件,并在其中添加以下信息:
indexes:
- kind: Message
properties:
- name: delivered
direction: asc
- name: lastUpdated
direction: desc
与部署您之前定义的 Cron 作业类似,您可以使用 Google Cloud SDK 部署您使用以下命令定义的复合索引:
gcloud datastore create-indexes index.yaml
部署后,App Engine 会自动配置索引 显示在 Datastore >索引。
定义索引后,您可以返回为 Cron 作业创建的 webhook,并完成消息过期逻辑:
router.get('/expireMessages', function(req, res, next) {
// Milliseconds in an hour
const TIMEOUT = 3600000;
// Threshold is current time minus one hour
const OLD_MESSAGE_THRESHOLD = new Date().getTime() - TIMEOUT;
// Create a query to find old undelivered messages
const query = datastore
.createQuery('Message')
.filter('delivered', '=', false)
.filter('lastUpdated', '<', OLD_MESSAGE_THRESHOLD);
// Execute the query
datastore.runQuery(query).then((results) => {
for(var i = 0; i < results[0].length; i++) {
let msisdn = results[0][i].msisdn;
let messageId = results[0][i].id;
// Stop the message from being sent
rbmApiHelper.revokeMessage(msisdn, messageId);
// Remove the message from the Datastore
datastore.delete(results[0][i][datastore.KEY]);
// TODO: Send the user the message as SMS
}
});
res.status(200).send();
});
RBM 本身不支持短信回退,因此您需要实现相应逻辑,以便通过短信发送未递送的消息。
总结和总结
为处理线下用户,您可以为未提交的 RBM 构建撤消逻辑 消息。消息过期前所用的时间取决于您传输的信息时效性。对于时效性较高的信息,建议的超时时间少于 2 小时。
此示例使用 Cloud Datastore 和 Google App Engine 来管理存储空间 和撤消过程的用时,但用于跟踪 这样,你发送和发送的消息应该就可以了。
祝您好运,编程愉快!