Como lidar com usuários off-line nas suas campanhas do RBM

Um fator importante no tempo de entrega das mensagens do seu agente é se o usuário que você está tentando alcançar tem uma conexão de dados envia uma mensagem. Se o usuário estiver off-line, a plataforma RBM armazenará a mensagem e tenta entregar em até 30 dias. Se a mensagem não puder ser entregue nesse prazo, ele é removido do sistema.

Há muitos motivos e situações em que um usuário pode não ter conectividade quando o agente estiver tentando entrar em contato com eles. Talvez o usuário tenha desativado os dados para economizar no plano de celular, esteja em um avião sem conexão Wi-Fi ou em um metrô em um túnel. Dependendo da urgência com que suas mensagens precisam chegar, o agente precisa lidar usuários off-line revogando as mensagens RBM não entregues e reencaminhando essas mensagens em um canal diferente.

As seções a seguir fornecem detalhes sobre como usar um Google Cloud Datastore para acompanhar as mensagens que você envia e entrega, como usar o cron para revogar não entregues e como redirecionar essas mensagens por SMS.

Acompanhar as mensagens enviadas

Cada mensagem enviada pelo agente de RBM precisa incluir um ID de mensagem exclusivo. Para acompanhar as mensagens enviadas pelo agente, salve o ID, o número de telefone e o carimbo de data/hora de cada mensagem.

É possível usar diversas tecnologias para armazenar essas informações, incluindo no Google Cloud Datastore. O Cloud Datastore é um serviço NoSQL que lida automaticamente com fragmentação e replicação. É uma ótima solução para armazenar dados não relacionais, como as mensagens enviadas por um agente. O Cloud Datastore depende de uma instância ativa do Google App Engine para que você possa usar o App Engine para hospedar seu agente RBM e configurar um trabalho cron.

Há bibliotecas de cliente do Cloud Datastore disponíveis em vários idiomas. Neste exemplo, você pode usar o Node.js e basear o código do agente RBM no exemplo de agente Node.js disponível no site para desenvolvedores do RBM. No início, instalar o Cloud Datastore para meu projeto Node.js executando o seguinte comando:

npm install --save @google-cloud/datastore

No código-fonte do agente, adicione uma referência global ao cliente do Cloud Datastore biblioteca.

// Imports the Google Cloud client library
const Datastore = require('@google-cloud/datastore');

// Creates a client
const datastore = new Datastore({
    projectId: PROJECT_ID,
});

Com o objeto de repositório de dados criado, é possível introduzir uma função para armazenar o estado msisdn, message id, sent time e delivery para cada mensagem.

/**
 *   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);
        });
}

Com essa função em vigor, é necessário chamar esse método sempre que o agente enviar uma mensagem para um usuário. Quando o cliente RBM Node.js biblioteca envia mensagens RBM, a biblioteca fornece um objeto de resposta no callback que contém o messageId para a mensagem que foi enviada ao usuário.

Confira a seguir um exemplo de envio de uma mensagem de texto simples para um usuário e gravação das informações da mensagem após a comunicação com a API RBM.

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

Depois de executar o código, é possível inspecionar o Datastore no console do Google Cloud na visualização Entidades do Datastore.

Datastore

Atualizar o estado de entrega das mensagens

Agora que seu agente armazena as solicitações de mensagens enviadas no Datastore, atualize o o status de entrega após a mensagem ser entregue ao dispositivo do usuário.

Usuários os dispositivos enviam eventos DELIVERED, READ e IS_TYPING para agentes do RBM pelo Cloud Pub/Sub. No gerenciador do Pub/Sub, verifique se há eventos entregues e atualize a configuração do Datastore da flag entregue como "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
    }
}

O agente salva as mensagens enviadas no Datastore e atualiza os dados quando recebe uma notificação de entrega. Na próxima seção, veja como configurar um cron no App Engine do Google seja executada a cada 10 minutos para monitorar dados não entregues mensagens.

Cron no App Engine do Google

É possível usar cron jobs para agendar tarefas em diferentes intervalos. No app do Google Engine, um cron job é configurado com uma descrição, um URL e um intervalo.

Em apps Node.js, você configura isso em um arquivo cron.yaml, que pode ser implantado no App Engine usando o SDK do Google Cloud. Leia sobre outras configurações de idioma em Como programar jobs com cron.yaml.

Como a tarefa do cron precisa de um URL, é necessário adicionar um endpoint de URL ao roteador de app expresso para que ele seja chamado pelo cron. Esse webhook é responsável por consultar Datastore de mensagens antigas, excluindo-as da plataforma RBM e enviando para o usuário por SMS.

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

Confira a seguir a configuração do arquivo cron.yaml para executar esse endpoint a cada 10 minutos.

cron:
-   description: "Processing expired RBM messages"
  url: /expireMessages
  schedule: every 10 mins

Para implantar as tarefas cron no App Engine, execute o seguinte comando:

gcloud app deploy cron.yaml

Após a implantação, o App Engine configura automaticamente a tarefa cron, que pode ser visualizada em App Engine > Cron jobs.

cron jobs

Consultar o Datastore para mensagens não entregues

No webhook do trabalho cron que você configurou na seção anterior, é necessário adicionar lógica para procurar todas as mensagens enviadas que tenham um estado delivered igual a "false" e que tenham um tempo lastUpdated mais antigo do que um tempo limite predefinido que faça sentido para nosso caso de uso. Neste exemplo, as mensagens com mais de uma hora são expiradas.

Para oferecer suporte a uma consulta composta como essa, o Datastore precisa ter um índice composto contendo as propriedades delivered e lastUpdated. Para faça isso, você pode criar um arquivo em seu projeto chamado index.yaml com o seguintes informações:

indexes:
-   kind: Message
  properties:
  -   name: delivered
    direction: asc
  -   name: lastUpdated
    direction: desc

Assim como na implantação da tarefa cron definida anteriormente, use o SDK do Google Cloud para implantar o índice composto definido com o seguinte comando:

gcloud datastore create-indexes index.yaml

Após a implantação, o App Engine configura automaticamente o índice é mostrado em Datastore > Índices.

Índices do Datastore

Com o índice definido, é possível voltar ao webhook criado para o cron job e conclua a lógica de expiração da mensagem:

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

O RBM não oferece suporte nativo ao fallback de SMS. Portanto, você precisa implementar a lógica para enviar mensagens não entregues por SMS.

Encerramento e resumo

Para lidar com usuários off-line, crie uma lógica de revogação para RBM não entregue mensagens. O tempo que você usa antes de expirar a mensagem depende a importância do tempo das informações transmitidas. Com sistema de gerenciamento informações, o tempo limite recomendado é menos de duas horas.

Este exemplo usa o Cloud Datastore e o Google App Engine para gerenciar o armazenamento, a consulta e o processo de revogação, mas qualquer mecanismo de armazenamento para acompanhar as mensagens enviadas e entregues deve funcionar.

Boa sorte e divirta-se programando!