Cara menangani pengguna offline di kampanye RBM

Faktor utama dalam waktu pengiriman pesan agen adalah apakah pengguna yang Anda coba hubungi memiliki koneksi data pada saat agen mengirim pesan. Jika pengguna sedang offline, platform RBM akan menyimpan pesan dan mencoba mengirimkannya hingga 30 hari. Jika saat itu pesan tidak dapat dikirimkan, pesan akan dihapus dari sistem.

Ada banyak alasan dan situasi saat pengguna mungkin tidak memiliki konektivitas saat agen Anda mencoba menghubungi mereka. Mereka mungkin telah menonaktifkan data untuk menghemat uang pada paket seluler, mungkin berada di pesawat tanpa koneksi Wi-Fi, atau mungkin sedang berada di kereta bawah tanah di dalam terowongan. Bergantung pada urgensi pengiriman pesan Anda, agen Anda perlu menangani pengguna offline dengan baik dengan mencabut pesan RBM yang tidak terkirim dan mengarahkan ulang pesan tersebut melalui saluran yang berbeda.

Dalam artikel ini, saya akan menunjukkan cara menggunakan Google Cloud Datastore untuk melacak pesan yang Anda kirim dan kirimkan, cara menggunakan cron untuk revoke pesan yang tidak terkirim, dan cara mengarahkan ulang pesan tersebut melalui SMS.

Melacak pesan terkirim

Setiap pesan yang dikirim oleh agen RBM harus menyertakan ID pesan unik. Untuk terus melacak pesan yang dikirim agen, Anda perlu menyimpan ID pesan, nomor telepon, dan stempel waktu untuk setiap pesan.

Anda dapat menggunakan berbagai teknologi untuk menyimpan informasi ini, tetapi dalam artikel ini, saya menggunakan Google Cloud Datastore. Cloud Datastore adalah database NoSQL yang sangat skalabel, yang secara otomatis menangani sharding dan replikasi. Ini adalah solusi bagus untuk menyimpan data non-relasional seperti pesan yang dikirim oleh agen. Cloud Datastore bergantung pada keberadaan instance Google App Engine yang aktif. Jadi, saya menggunakan App Engine untuk menghosting agen RBM dan mengonfigurasi cron job.

Ada library klien untuk Cloud Datastore yang tersedia dalam banyak bahasa. Untuk contoh ini, saya menggunakan Node.js dan mendasarkan kode agen RBM pada Contoh Node.js Agen Pertama yang tersedia di Situs Developer RBM. Hal pertama yang saya lakukan adalah menginstal Cloud Datastore untuk project Node.js saya dengan menjalankan perintah berikut:

npm install --save @google-cloud/datastore

Dalam kode sumber agen, saya menambahkan referensi global ke library klien Cloud Datastore.

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

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

Setelah objek datastore dibuat, saya memperkenalkan fungsi untuk menyimpan status msisdn, message id, sent time, dan delivery untuk setiap pesan.

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

Setelah fungsi ini diterapkan, Anda perlu memanggil metode ini setiap kali agen Anda mengirim pesan kepada pengguna. Saat library klien RBM Node.js mengirim pesan RBM, library akan menyediakan objek respons dalam metode callback yang berisi messageId untuk pesan yang telah dikirim ke pengguna.

Di bawah ini adalah contoh pengiriman pesan teks biasa kepada pengguna dan perekaman informasi pesan setelah berhasil berkomunikasi dengan 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);
});

Setelah menjalankan kode di atas, Anda dapat memeriksa Datastore dari Konsol Google Cloud dalam tampilan Entity Datastore.

Datastore

Memperbarui status pengiriman pesan

Setelah agen Anda menyimpan permintaan pesan yang terkirim di Datastore, kita perlu memperbarui status pengiriman setelah pesan berhasil dikirim ke perangkat pengguna.

Perangkat pengguna mengirim peristiwa DELIVERED, READ, dan IS_TYPING ke agen RBM melalui Cloud Pub/Sub. Di pengendali Pub/Sub, periksa peristiwa yang dikirim dan perbarui setelan Datastore untuk tanda yang dikirim ke benar (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
    }
}

Agen menyimpan pesan keluar ke Datastore dan memperbarui data saat menerima notifikasi pengiriman. Di bagian selanjutnya, kita akan menyiapkan cron job di App Engine Google agar dijalankan setiap 10 menit untuk memantau pesan yang tidak terkirim.

Cron di App Engine Google

Anda dapat menggunakan cron job untuk menjadwalkan tugas pada interval yang berbeda. Di App Engine Google, cron job dikonfigurasi dengan deskripsi, URL, dan interval.

Di aplikasi Node.js, Anda mengonfigurasinya dalam file cron.yaml, yang dapat di-deploy ke App Engine menggunakan Google Cloud SDK. Baca tentang penyiapan konfigurasi bahasa lain di Menjadwalkan tugas dengan cron.yaml.

Karena tugas cron memerlukan URL, Anda perlu menambahkan endpoint URL ke router aplikasi ekspres agar dipanggil oleh cron. Webhook ini bertanggung jawab untuk mengkueri Datastore tentang pesan lama, menghapusnya dari platform RBM, dan mengirimkannya kepada pengguna melalui 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();
});

Berikut adalah konfigurasi file cron.yaml untuk menjalankan endpoint ini setiap 10 menit.

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

Untuk men-deploy tugas cron ke App Engine, jalankan perintah berikut:

gcloud app deploy cron.yaml

Setelah deployment, App engine akan otomatis mengonfigurasi tugas cron, dan tugas dapat dilihat di bagian App Engine > Cron jobs.

cron job

Membuat kueri Datastore untuk pesan yang tidak terkirim

Di webhook untuk cron job yang Anda siapkan di bagian sebelumnya, Anda perlu menambahkan logika untuk mencari semua pesan terkirim yang memiliki status delivered sama dengan false dan memiliki waktu lastUpdated lebih lama dari waktu tunggu yang telah ditentukan yang sesuai untuk kasus penggunaan kita. Dalam contoh ini, masa berlaku pesan berakhir lebih dari satu jam.

Untuk mendukung kueri komposit seperti ini, Datastore harus memiliki indeks komposit yang berisi properti delivered dan lastUpdated. Untuk melakukannya, Anda dapat membuat file di project bernama index.yaml dengan informasi berikut:

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

Serupa dengan men-deploy cron job yang Anda tentukan sebelumnya, gunakan Google Cloud SDK untuk men-deploy indeks komposit yang Anda tentukan dengan perintah berikut:

gcloud datastore create-indexes index.yaml

Setelah deployment, App engine akan otomatis mengonfigurasi indeks, dan indeks dapat dilihat di bagian Datastore > Indexes.

Indeks Datastore

Setelah indeks ditentukan, kita dapat kembali ke webhook yang Anda buat untuk cron job dan menyelesaikan logika masa berlaku pesan:

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 tidak mendukung penggantian SMS secara native, sehingga Anda harus menerapkan logika untuk mengirim pesan yang tidak terkirim melalui SMS.

Akhir kata & TL;DR

Untuk menangani pengguna offline, Anda dapat mem-build logika pencabutan untuk pesan RBM yang tidak dikirim. Jumlah waktu yang Anda gunakan sebelum masa berlaku pesan habis bergantung pada seberapa sensitif informasi yang Anda kirim dengan waktu. Dengan informasi yang sensitif waktu, sebaiknya waktu tunggu kurang dari dua jam.

Contoh ini menggunakan Cloud Datastore dan Google App Engine untuk mengelola proses penyimpanan, kueri, dan pencabutan, tetapi mekanisme penyimpanan apa pun untuk melacak pesan yang terkirim dan terkirim seharusnya berfungsi.

Semoga berhasil, dan selamat {i>coding<i}!