วิธีจัดการผู้ใช้แบบออฟไลน์ในแคมเปญ RBM ของคุณ

ปัจจัยสำคัญของเวลาในการส่งข้อความของตัวแทนคือ ผู้ใช้ที่คุณพยายามติดต่อมีการเชื่อมต่อข้อมูลในขณะที่ตัวแทนส่งข้อความหรือไม่ หากผู้ใช้ออฟไลน์อยู่ แพลตฟอร์ม RBM จะจัดเก็บข้อความดังกล่าวและพยายามส่งเป็นเวลาถึง 30 วัน ถ้าไม่สามารถส่งข้อความได้ ข้อความจะถูกนำออกจากระบบ

มีหลายสาเหตุและสถานการณ์ที่ผู้ใช้อาจไม่มีการเชื่อมต่อเมื่อตัวแทนพยายามติดต่อพวกเขา พวกเขาอาจปิดใช้อินเทอร์เน็ตมือถือ เพื่อประหยัดค่าใช้จ่ายสำหรับแพ็กเกจมือถือ, ไม่ได้นั่งเครื่องบิน โดยไม่ได้เชื่อมต่อ Wi-Fi หรือนั่งรถไฟใต้ดินในอุโมงค์ ตัวแทนของคุณจะต้องจัดการกับผู้ใช้แบบออฟไลน์อย่างค่อยเป็นค่อยไป โดยการเพิกถอนข้อความ RBM ที่ไม่ได้ส่ง และกำหนดเส้นทางข้อความเหล่านั้นใหม่ผ่านช่องทางอื่น ทั้งนี้ขึ้นอยู่กับความเร่งด่วนของข้อความที่คุณต้องการส่ง

ในบทความนี้ เราจะแสดงวิธีใช้ Google Cloud Datastore เพื่อติดตามข้อความที่คุณส่งและส่ง วิธีใช้ cron เพื่อrevokeข้อความที่ยังไม่ได้ส่ง และวิธีเปลี่ยนเส้นทางข้อความเหล่านั้นผ่าน SMS

การติดตามข้อความที่ส่งแล้ว

ทุกข้อความที่ส่งโดยตัวแทน RBM ของคุณต้องมีรหัสข้อความที่ไม่ซ้ำกัน หากต้องการติดตามข้อความที่ตัวแทนส่ง คุณต้องบันทึกรหัสข้อความ หมายเลขโทรศัพท์ และการประทับเวลาของแต่ละข้อความ

คุณสามารถใช้เทคโนโลยีที่หลากหลายในการจัดเก็บข้อมูลนี้ แต่ในบทความนี้ผมใช้ Google Cloud Datastore Cloud Datastore เป็นฐานข้อมูล NoSQL ที่รองรับการปรับขนาดได้สูง ซึ่งจะจัดการชาร์ดดิ้งและการจำลองโดยอัตโนมัติ ซึ่งเป็นวิธีแก้ปัญหาที่ดีเยี่ยมสำหรับการจัดเก็บข้อมูลที่ไม่สัมพันธ์กัน เช่น ข้อความที่ส่งโดยตัวแทน Cloud Datastore ต้องอาศัยอินสแตนซ์ Google App Engine ที่ใช้งานอยู่ ฉันจึงใช้ App Engine เพื่อโฮสต์ Agent RBM และกำหนดค่างาน Cron

มีไลบรารีของไคลเอ็นต์สำหรับ Cloud Datastore ในหลายภาษา สำหรับตัวอย่างนี้ ผมใช้ Node.js และอิงโค้ดตัวแทน RBM ในตัวอย่าง Node.js ของตัวแทนแรกที่มีอยู่บนเว็บไซต์นักพัฒนาซอฟต์แวร์ RBM สิ่งแรกที่ฉันทำคือติดตั้ง Cloud Datastore สำหรับโปรเจ็กต์ Node.js ของฉันโดยเรียกใช้คำสั่งต่อไปนี้

npm install --save @google-cloud/datastore

ในซอร์สโค้ดของ Agent ฉันเพิ่มการอ้างอิงส่วนกลางลงในไลบรารีไคลเอ็นต์ 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);
});

หลังจากเรียกใช้โค้ดข้างต้นแล้ว คุณสามารถตรวจสอบ Datastore จากคอนโซล Google Cloud ภายในมุมมองเอนทิตีพื้นที่เก็บข้อมูล

Datastore

กำลังอัปเดตสถานะการส่งข้อความ

เมื่อตัวแทนจัดเก็บคำขอข้อความที่ส่งแล้วใน Datastore เราจำเป็นต้องอัปเดตสถานะการนำส่งเมื่อส่งข้อความไปยังอุปกรณ์ของผู้ใช้เรียบร้อยแล้ว

อุปกรณ์ของผู้ใช้จะส่งเหตุการณ์ DELIVERED, READ และ IS_TYPING ไปยัง Agent ของ RBM ผ่าน Cloud Pub/Sub ในเครื่องจัดการสำหรับ Pub/Sub ให้ตรวจสอบเหตุการณ์ที่ส่งแล้ว และอัปเดตการตั้งค่า Datastore สำหรับแฟล็กที่ส่งเป็น "จริง"

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

Agent จะบันทึกข้อความขาออกลงใน Datastore และอัปเดตข้อมูลเมื่อได้รับการแจ้งเตือนการนำส่ง ในส่วนถัดไป เราตั้งค่างาน cron บน App Engine ของ Google ให้เรียกใช้ทุก 10 นาทีเพื่อตรวจสอบข้อความที่ยังไม่ได้ส่ง

Cron ใน App Engine ของ Google

คุณสามารถใช้งาน Cron เพื่อกำหนดเวลางานในช่วงเวลาต่างๆ ได้ ใน App Engine ของ Google งาน Cron จะได้รับการกำหนดค่าด้วยคำอธิบาย URL และช่วงเวลา

ในแอป Node.js คุณสามารถกำหนดค่าเหล่านี้ในไฟล์ cron.yaml ซึ่งสามารถทำให้ App Engine ใช้งานได้โดยใช้ Google Cloud SDK อ่านเกี่ยวกับการตั้งค่าการกำหนดค่าภาษาอื่นๆ ได้ในการกำหนดเวลางานด้วย cron.yaml

เนื่องจากงาน Cron จำเป็นต้องใช้ URL คุณจึงต้องเพิ่มปลายทางของ URL ลงในเราเตอร์แอป Express เพื่อให้ cron เรียกใช้ เว็บฮุคนี้มีหน้าที่สืบค้นข้อความเก่าจากพื้นที่เก็บข้อมูล ลบข้อความออกจากแพลตฟอร์ม 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 สำหรับข้อความที่ยังไม่ได้ส่ง

ในเว็บฮุคสำหรับงาน Cron ที่ตั้งค่าไว้ในส่วนก่อนหน้า คุณต้องเพิ่มตรรกะในการค้นหาข้อความที่ส่งแล้วทั้งหมดที่มีสถานะ delivered เท่ากับ "เท็จ" และมีระยะเวลา lastUpdated นานกว่าระยะหมดเวลาที่กำหนดไว้ล่วงหน้าซึ่งเหมาะสมกับกรณีการใช้งานของเรา ในตัวอย่างนี้ ข้อความที่หมดอายุนานกว่า 1 ชั่วโมง

Datastore ต้องมีดัชนีผสมที่มีทั้งพร็อพเพอร์ตี้ delivered และ lastUpdated จึงจะรองรับการค้นหาแบบผสมนี้ได้ วิธีการคือสร้างไฟล์ในโปรเจ็กต์ชื่อ index.yaml ที่มีข้อมูลต่อไปนี้

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

ใช้ Google Cloud SDK เพื่อทำให้ดัชนีผสมที่คุณกำหนดด้วยคำสั่งต่อไปนี้ใช้งานได้ คล้ายกับการทำให้งาน Cron ใช้งานได้ที่คุณกำหนดไว้ก่อนหน้านี้

gcloud datastore create-indexes index.yaml

หลังจากทำให้ใช้งานได้ App Engine จะกำหนดค่าดัชนีโดยอัตโนมัติ และคุณดูดัชนีได้ในส่วน Datastore > ดัชนี

ดัชนีพื้นที่เก็บข้อมูล

เมื่อกำหนดดัชนีแล้ว เราสามารถกลับไปที่เว็บฮุคที่คุณสร้างขึ้นสำหรับงาน 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 ที่ไม่ได้ส่งได้ ระยะเวลาที่คุณใช้ก่อนที่ข้อความจะหมดอายุนั้นขึ้นอยู่กับเวลาของข้อมูลที่คุณส่ง สำหรับข้อมูลที่อิงตามเวลา เราขอแนะนำให้เผื่อเวลาไว้ไม่เกิน 2 ชั่วโมง

ตัวอย่างนี้ใช้ Cloud Datastore และ Google App Engine เพื่อจัดการพื้นที่เก็บข้อมูล การค้นหา และกระบวนการเพิกถอน แต่กลไกพื้นที่เก็บข้อมูลสำหรับการติดตามข้อความที่ส่งและนำส่งควรทำงานได้

ขอให้โชคดีและขอให้สนุกกับการเขียนโค้ด