نحوه مدیریت کاربران آفلاین در کمپین های 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 را بر اساس First Agent Node.js Sample موجود در وب سایت توسعه دهنده 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,
});

با ایجاد شی datastore، تابعی را برای ذخیره 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 Console در نمای Datastore Entities بررسی کنید.

فروشگاه داده

به روز رسانی وضعیت تحویل پیام ها

اکنون که نماینده شما درخواست‌های پیام ارسالی را در Datastore ذخیره می‌کند، پس از تحویل موفقیت‌آمیز پیام به دستگاه کاربر، باید وضعیت تحویل را به‌روزرسانی کنیم.

دستگاه‌های کاربران رویدادهای DELIVERED ، READ و IS_TYPING را از طریق Cloud Pub/Sub به نمایندگان RBM ارسال می‌کنند. در کنترلر برای 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
    }
}

نماینده پیام‌های خروجی را در Datastore ذخیره می‌کند و هنگام دریافت اعلان تحویل، داده‌ها را به‌روزرسانی می‌کند. در بخش بعدی، یک cron job را در موتور برنامه Google تنظیم کردیم تا هر 10 دقیقه یک بار برای نظارت بر پیام‌های تحویل‌نشده اجرا شود.

Cron در موتور برنامه گوگل

می توانید از cron jobs برای زمان بندی وظایف در فواصل زمانی مختلف استفاده کنید. در موتور برنامه گوگل، یک کار cron با یک توضیح، یک URL و یک فاصله پیکربندی شده است.

در برنامه‌های Node.js، اینها را در یک فایل cron.yaml پیکربندی می‌کنید که می‌توانید با استفاده از Google Cloud SDK آن را در App Engine اجرا کنید. در مورد سایر تنظیمات پیکربندی زبان در زمان‌بندی کارهای با cron.yaml بخوانید.

از آنجایی که وظیفه cron به یک URL نیاز دارد، باید یک نقطه پایانی URL را به روتر app express اضافه کنید تا توسط cron فراخوانی شود. این وب هوک وظیفه پرس و جو از Datastore برای پیام های قدیمی، حذف آنها از پلتفرم 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 jobs قابل مشاهده است.

مشاغل 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 job که قبلاً تعریف کرده‌اید، از Google Cloud SDK برای استقرار فهرست ترکیبی که با دستور زیر تعریف کرده‌اید استفاده کنید:

gcloud datastore create-indexes index.yaml

پس از استقرار، موتور برنامه به طور خودکار ایندکس را پیکربندی می کند و ایندکس در زیر Datastore > Indexes قابل مشاهده است.

شاخص های ذخیره اطلاعات

با تعریف ایندکس، می‌توانیم به وب هوکی که برای کار 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 پیاده سازی کنید.

جمع بندی و TL;DR

برای رسیدگی به کاربران آفلاین، می‌توانید منطق ابطال پیام‌های RBM تحویل‌نشده ایجاد کنید. مدت زمانی که قبل از انقضای پیام استفاده می کنید بستگی به این دارد که اطلاعاتی که ارسال می کنید چقدر حساس به زمان است. با توجه به اطلاعات حساس به زمان، ما فاصله زمانی کمتر از دو ساعت را توصیه می کنیم.

این مثال از Cloud Datastore و Google App Engine برای مدیریت فضای ذخیره‌سازی، پرس و جو و فرآیند لغو استفاده می‌کند، اما هر مکانیزم ذخیره‌سازی برای پیگیری پیام‌های ارسالی و ارسالی شما باید کار کند.

موفق باشید، و کد نویسی مبارک!