Un facteur important dans le délai de distribution des messages de votre agent est de savoir si l'utilisateur que vous tentez de joindre dispose d'une connexion de données au moment où votre agent envoie un message. Si l'utilisateur est hors connexion, la plate-forme RBM stocke le message et tente de le distribuer pendant 30 jours maximum. Si le message ne peut pas être distribué d’ici là, il est supprimé du système.
Il existe de nombreuses raisons et situations où un utilisateur peut ne pas être connecté à Internet lorsque votre agent tente de le contacter. Ils ont peut-être désactivé les données pour économiser de l'argent sur leur forfait mobile, être en avion sans connexion Wi-Fi ou se trouver dans le métro dans un tunnel. En fonction de l'urgence avec laquelle vos messages doivent arriver, votre agent doit gérer de façon optimale les utilisateurs hors connexion en révoquant les messages RBM non distribués et en les réacheminant via un autre canal.
Dans cet article, je vais vous expliquer comment utiliser Google Cloud Datastore pour suivre les messages que vous envoyez et distribuez, comment utiliser Cron pour revoke les messages non distribués et comment réacheminer ces messages par SMS.
Suivre les messages envoyés
Chaque message envoyé par votre agent RBM doit inclure un ID de message unique. Pour suivre les messages que votre agent envoie, vous devez enregistrer l'ID, le numéro de téléphone et l'horodatage de chaque message.
Vous pouvez utiliser diverses technologies pour stocker ces informations, mais dans cet article, j'utilise Google Cloud Datastore. Cloud Datastore est une base de données NoSQL hautement évolutive qui gère automatiquement le partitionnement et la réplication. Il s'agit d'une excellente solution pour stocker des données non relationnelles telles que les messages envoyés par un agent. Cloud Datastore nécessite une instance Google App Engine active. J'utilise donc App Engine pour héberger mon agent RBM et configurer une tâche Cron.
Des bibliothèques clientes pour Cloud Datastore sont disponibles dans de nombreux langages. Pour cet exemple, j'utilise Node.js et je base le code de l'agent RBM sur le premier exemple d'agent Node.js, disponible sur le site Web pour les développeurs RBM. Tout d'abord, j'installe Cloud Datastore pour mon projet Node.js en exécutant la commande suivante:
npm install --save @google-cloud/datastore
Dans le code source de mon agent, j'ajoute une référence globale à la bibliothèque cliente Cloud Datastore.
// Imports the Google Cloud client library
const Datastore = require('@google-cloud/datastore');
// Creates a client
const datastore = new Datastore({
projectId: PROJECT_ID,
});
Une fois l'objet datastore créé, j'introduis une fonction permettant de stocker l'état msisdn
, message id
, sent time
et delivery
de chaque message.
/**
* 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);
});
}
Une fois cette fonction en place, vous devez l'appeler chaque fois que votre agent envoie un message à un utilisateur. Lorsque la bibliothèque cliente Node.js RBM envoie des messages RBM, elle fournit un objet de réponse dans la méthode de rappel, qui contient le messageId
pour le message envoyé à l'utilisateur.
Vous trouverez ci-dessous un exemple d'envoi d'un message en texte brut à un utilisateur et d'enregistrement des informations du message après la communication réussie avec l'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);
});
Après avoir exécuté le code ci-dessus, vous pouvez inspecter le datastore à partir de la console Google Cloud dans la vue Entités Datastore.
Modifier l'état de distribution des messages
Maintenant que votre agent stocke les requêtes de message envoyées dans le datastore, nous devons mettre à jour l'état de distribution une fois le message distribué sur l'appareil de l'utilisateur.
Les appareils des utilisateurs envoient les événements DELIVERED
, READ
et IS_TYPING
aux agents RBM via Cloud Pub/Sub. Dans le gestionnaire de Pub/Sub, recherchez les événements diffusés et définissez le paramètre Datastore de l'indicateur distribué sur "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
}
}
L'agent enregistre les messages sortants dans le datastore et met à jour les données lorsqu'il reçoit une notification de distribution. Dans la section suivante, nous allons configurer une tâche Cron sur App Engine de Google pour qu'elle s'exécute toutes les 10 minutes afin de surveiller les messages non distribués.
Cron sur Google App Engine
Vous pouvez utiliser des tâches Cron pour planifier des tâches à différents intervalles. Dans Google App Engine, une tâche Cron est configurée avec une description, une URL et un intervalle.
Dans les applications Node.js, vous les configurez dans un fichier cron.yaml
, que vous pouvez déployer sur App Engine à l'aide du SDK Google Cloud. Pour en savoir plus sur les autres configurations de configuration de langage, consultez la page Planifier des tâches avec cron.yaml.
Étant donné que la tâche Cron nécessite une URL, vous devez ajouter un point de terminaison d'URL au routeur d'application express pour qu'il soit appelé par Cron. Ce webhook est chargé d'interroger le datastore pour récupérer les anciens messages, de les supprimer de la plate-forme RBM et de les envoyer à l'utilisateur par 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();
});
Vous trouverez ci-dessous la configuration du fichier cron.yaml permettant d'exécuter ce point de terminaison toutes les 10 minutes.
cron:
- description: "Processing expired RBM messages"
url: /expireMessages
schedule: every 10 mins
Pour déployer les tâches Cron sur App Engine, exécutez la commande suivante:
gcloud app deploy cron.yaml
Après le déploiement, App Engine configure automatiquement la tâche Cron et celle-ci est visible sous App Engine > Jobs Cron.
Interroger le datastore pour rechercher les messages non distribués
Dans le webhook de la tâche Cron que vous avez configurée dans la section précédente, vous devez ajouter une logique pour rechercher tous les messages envoyés dont l'état delivered
est égal à "false" et dont l'état lastUpdated
est antérieur à un délai d'expiration prédéfini qui est pertinent pour notre cas d'utilisation. Dans cet exemple, les messages de plus d'une heure font expirer.
Pour accepter une requête composite de ce type, le datastore doit disposer d'un index composite contenant les propriétés delivered
et lastUpdated
. Pour ce faire, vous pouvez créer dans votre projet un fichier nommé index.yaml contenant les informations suivantes:
indexes:
- kind: Message
properties:
- name: delivered
direction: asc
- name: lastUpdated
direction: desc
Comme pour le déploiement de la tâche Cron que vous avez définie précédemment, utilisez le SDK Google Cloud pour déployer l'index composite que vous avez défini à l'aide de la commande suivante:
gcloud datastore create-indexes index.yaml
Après le déploiement, App Engine configure automatiquement l'index, qui peut être affiché sous Datastore > Indexes (Datastore > Index).
Une fois l'index défini, nous pouvons revenir au webhook que vous avez créé pour la tâche Cron et terminer la logique d'expiration du message:
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 n'est pas compatible de manière native avec les SMS de remplacement. Vous devez donc implémenter la logique pour envoyer vos messages non distribués par SMS.
Conclusion et résumé
Pour gérer les utilisateurs hors connexion, vous pouvez créer une logique de révocation pour les messages RBM non distribués. Le délai d'expiration du message dépend du degré de sensibilité des informations que vous transmettez. Pour les informations urgentes, nous vous recommandons de définir un délai avant expiration inférieur à deux heures.
Cet exemple utilise Cloud Datastore et Google App Engine pour gérer le processus de stockage, de requête et de révocation, mais tout mécanisme de stockage permettant d'effectuer le suivi des messages envoyés et distribués devrait fonctionner.
Bonne chance et bon codage !