如何处理 RBM 广告系列中的离线用户

影响代理消息递送时间的一个主要因素是, 您尝试联系的用户在您的代理时已有数据连接 发送消息。如果用户处于离线状态,RBM 平台会存储消息和 最多尝试投放 30 天。如果届时仍然无法发送邮件 也会将其从系统中移除

导致用户无法连接的原因和情况有很多 。他们可能关闭了数据流量 在没有 Wi-Fi 的飞机上 也可能是在地铁里的隧道中根据紧急程度 您的代理需要妥善处理 通过撤消未发送的 RBM 消息并重新传送这些消息来离线用户 其他渠道

在本文中,我将向您介绍如何使用 Google Cloud Datastore 来跟踪 如何发送和传递的消息,如何使用 Cron 撤消 未递送的邮件,以及如何通过短信重新递送这些邮件。

跟踪发送的邮件

RBM 代理发送的每条消息都必须包含唯一的消息 ID。 要跟踪代理发送的消息,您需要保存消息 ID、 电话号码和时间戳

您可以使用各种技术来存储这些信息, 我使用 Google Cloud DatastoreCloud Datastore 是一种扩容能力极强的 自动处理分片和复制的 NoSQL 数据库。非常棒 解决方案,用于存储非关系型数据,例如代理发送的消息。 Cloud Datastore 依赖于有一个处于活跃状态的 Google 应用 Engine 实例,因此使用 使用 App Engine 托管 RBM 代理并配置 Cron 作业。

Cloud Datastore 的客户端库支持多种语言。对于 在此示例中,我使用 Node.js,并将 RBM 代理代码基于第一个代理 Node.js 示例 RBM 开发者网站上找到。第一个 我要做的就是运行 以下命令:

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,
});

在创建数据存储区对象后,我引入一个函数来存储 每条消息的 msisdnmessage idsent timedelivery 状态。

/**
 *   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

更新消息的传送状态

现在,您的代理将发送的邮件请求存储在数据存储区中,我们需要 在邮件成功发送到 用户的设备

用户的设备向 RBM 代理发送 DELIVEREDREADIS_TYPING 事件 Cloud Pub/Sub 之上在 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
    }
}

代理会将传出消息保存到数据存储区,并在收到消息时更新数据 收到传送通知。在下一部分中,我们将在 Google 的 App Engine 每 10 分钟运行一次,以监控未传递的消息。

Google App Engine 上的 Cron

您可以使用 Cron 作业按不同的时间间隔安排任务。在 Google 的应用中 Cron 作业配置了说明、网址和间隔时间。

在 Node.js 应用中,您可以在 cron.yaml 文件中配置这些内容,然后可以部署 使用 Google Cloud 迁移到 App Engine, SDK。了解其他语言 请参阅使用 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 作业

查询数据存储区中是否有未传送的消息

在上一部分中设置的 Cron 作业的 webhook 中,您需要将 查找 delivered 状态为 false 的所有已发送消息的逻辑 并且超时时间比预定义的超时时间早 lastUpdated, 我们的应用场景。在此示例中,系统会让超过一小时的邮件失效。

为了支持这样的复合查询,数据存储区需要 包含 deliveredlastUpdated 属性的复合索引。接收者 执行上述操作后,您可以在项目中创建一个名为 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 会自动配置索引 可在数据存储区 >索引

数据存储区索引

定义索引后,我们可以返回到您为 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 构建撤消逻辑 消息。消息过期前的具体时间取决于 您传输的信息的时效性。具有时效性 因此我们建议您将超时时间控制在两小时以内。

此示例使用 Cloud Datastore 和 Google App Engine 来管理存储空间 和撤消过程的用时,但用于跟踪 这样,你发送和发送的消息应该就可以了。

祝您好运,编程愉快!