איך לטפל במשתמשים אופליין בקמפיינים של RBM

אחד הגורמים העיקריים לזמן האספקה של ההודעות של הנציג הוא אם למשתמש שאתם מנסים ליצור איתו קשר יש חיבור נתונים בזמן שהנציג שולח הודעה. אם המשתמש נמצא במצב אופליין, פלטפורמת RBM שומרת את ההודעה ומנסה לשלוח אותה למשך עד 30 יום. אם ההודעה לא תימסר עד אז, היא תוסר מהמערכת.

יש הרבה סיבות ומצבים שבהם יכול להיות שלמשתמש לא תהיה קישוריות כשהנציג שלכם ינסה ליצור איתו קשר. יכול להיות שהם השביתו את חבילת הגלישה כדי לחסוך כסף בחבילת הסלולר, יכול להיות שהם במטוס ללא חיבור Wi-Fi או אולי הם ברכבת התחתית במנהרה. בהתאם בדחיפות שאליו ההודעות צריכות להגיע, הנציג צריך לטפל בהן למשתמשים במצב אופליין על ידי ביטול הודעות RBM שלא נמסרו וניתוב מחדש של ההודעות האלה דרך ערוץ אחר.

בקטעים הבאים מוסבר איך להשתמש ב-Google Cloud Datastore כדי לעקוב אחרי ההודעות שאתם שולחים ומעבירים, איך להשתמש ב-cron כדי לבטל הודעות שלא נשלחו ואיך לנתב מחדש את ההודעות האלה באמצעות SMS.

מעקב אחר הודעות שנשלחו

כל הודעה שנשלחת על ידי נציג RBM חייבת לכלול מזהה הודעה ייחודי. כדי לעקוב אחרי ההודעות שהנציג שולח, עליכם לשמור את מזהה ההודעה. מספר הטלפון וחותמת הזמן של כל הודעה.

אפשר להשתמש במגוון טכנולוגיות כדי לאחסן את המידע הזה, כולל Google Cloud Datastore. Cloud Datastore הוא NoSQL עם יכולת התאמה רחבה מסד נתונים שמטפל באופן אוטומטי בפיצול וברפליקציות. זהו פתרון מצוין לאחסון נתונים לא יחסיים, כמו הודעות שנשלחות על ידי נציג. כדי להשתמש ב-Cloud Datastore, צריך מכונה פעילה של Google App Engine. לכן אפשר להשתמש ב-App Engine כדי לארח את סוכן ה-RBM ולהגדיר משימה ב-cron.

יש ספריות לקוח ל-Cloud Datastore שזמינות בשפות רבות. בדוגמה הזו אפשר להשתמש ב-Node.js ולהסתמך על קוד הנציג של RBM לפי הדוגמה הראשונה ל-Node.js של נציג שזמינה באתר למפתחי RBM. קודם כל, כדי להתקין את Cloud Datastore לפרויקט Node.js שלי על ידי הרצת הפקודה הבאה:

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, הספרייה מספקת אובייקט תגובה בשיטת ה-callback שמכיל את 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);
});

לאחר הרצת הקוד, תוכלו לבדוק את ה-Datastore בעזרת Google מסוף Cloud בתוך ישויות של מאגר הנתונים צפייה.

Datastore

עדכון מצב המסירה של הודעות

עכשיו, כשהנציג מאחסן בקשות להודעות שנשלחו במאגר הנתונים, תוכלו לעדכן את סטטוס המסירה ברגע שההודעה תימסר למכשיר של המשתמש.

המכשירים של המשתמשים שולחים אירועים מסוג DELIVERED,‏ READ ו-IS_TYPING לנציגי RBM דרך Cloud Pub/Sub. ב-handler של 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 ב-App Engine של Google שתופעל כל 10 דקות כדי לעקוב אחרי הודעות שלא נשלחו.

Cron ב-App Engine של Google

אפשר להשתמש במשימות cron כדי לתזמן משימות במרווחי זמן שונים. באפליקציית Google מנוע, משימת cron מוגדרת עם תיאור, כתובת URL ומרווח.

באפליקציות של Node.js, צריך להגדיר אותן בקובץ cron.yaml, ואז אפשר לפרוס אותו. ל-App Engine באמצעות Google Cloud SDK. מידע על הגדרות אחרות של שפה במאמר תזמון משימות עם cron.yaml.

צריך להוסיף למשימת cron כתובת URL, לכן צריך להוסיף נקודת קצה של כתובת URL לרשימת האקספרס כדי שהנתב של האפליקציה יקרא cron. ה-webhook הזה אחראי לשליחת שאילתות לגבי מאגר נתונים של הודעות ישנות, מחיקתן מהפלטפורמה של RBM ושליחה אותן למשתמש באמצעות 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();
});

בהמשך מוצגת התצורה של קובץ cron.yaml להפעלת נקודת הקצה הזו בכל 10 דקות.

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

שליחת שאילתות ל-Datastore כדי למצוא הודעות שלא נמסרו

ב-webhook של משימה ה-cron שהגדרתם בקטע הקודם, צריך להוסיף לוגיקה לחיפוש כל ההודעות שנשלחו שהמצב שלהן ב-delivered שווה ל-false ושזמן ה-lastUpdated שלהן ישן יותר ממועד תפוגה מוגדר מראש שסביר לשימוש שלנו. בדוגמה הזו, התוקף של הודעות פג לפני יותר משעה.

כדי לתמוך בשאילתה מורכבת כזו, ב-Datastore צריך להיות אינדקס מורכב שמכיל גם את המאפיינים 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 > מדדים.

אינדקסים של Datastore

כשהאינדקס מוגדר, אפשר לחזור ל-webhook שיצרתם בשביל ה-cron ולהשלים את הלוגיקה של תפוגת ההודעה:

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 לא תומכת באופן מובנה באפשרות חלופית לשליחת הודעות ב-SMS, לכן תצטרכו להטמיע את הלוגיקה לשליחת ההודעות שלא נמסרו ב-SMS.

סיכום וסיכום

כדי לטפל במשתמשים אופליין, אפשר ליצור לוגיקת ביטול של RBM שלא נמסרה. הודעות. משך הזמן שינוצל לפני שתוקף ההודעה יפוג תלוי ב- מידת הרגישות של המידע שאתם מעבירים. עם לוח זמנים תלוי-זמן מידע, הזמן הקצוב לתפוגה מומלץ הוא פחות משעתיים.

בדוגמה הזו נעשה שימוש ב-Cloud Datastore וב-Google App Engine לניהול האחסון, השאילתות ותהליך הביטול, אבל כל מנגנון אחסון שעוזר לעקוב אחרי ההודעות שנשלחו ונמסרו יכול לשמש לצורך זה.

בהצלחה ושיהיה לכם קוד מהנה!