كيفية التعامل مع المستخدمين غير المتصلين بالإنترنت في حملات RBM

يُعدّ ما إذا كان العميل الذي تحاول التواصل معه متصلاً بالإنترنت في الوقت الذي يرسل فيه موظّف الدعم الرسالة أحد العوامل الرئيسية التي تؤثر في وقت تسليم رسائله. إذا كان المستخدم غير متصل بالإنترنت، تُخزِّن منصة RBM الرسالة محاولات التسليم لمدة تصل إلى 30 يومًا. وإذا تعذّر تسليم الرسالة بحلول ذلك الوقت، تتم إزالتها من النظام.

هناك العديد من الأسباب والمواقف التي قد لا يتمكن فيها المستخدم من الاتصال عندما يحاول موظّف الدعم التواصل معه كان من الممكن أن يكون قد أوقف البيانات إلى توفير المال على خطة الجوّال، يمكنهم الصعود على متن طائرة بدون اتصال Wi-Fi أو ربما باستخدام مترو أنفاق في نفق. استنادًا إلى مدى إلحاح وصول رسائلك، على موظّف الدعم التعامل بشكلٍ جيد مع المستخدمين غير المتصلين بالإنترنت من خلال إلغاء رسائل RBM التي لم يتم تسليمها وإعادة توجيه هذه الرسائل من خلال قناة مختلفة.

تقدم الأقسام التالية تفاصيل حول كيفية استخدام خدمة تخزين البيانات في Google Cloud لتتبُّع الرسائل التي ترسلها وتسلمها، وكيفية استخدام 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);
        });
}

مع وجود هذه الدالة، تحتاج إلى استدعاء هذه الطريقة عندما يكون وكيلك إرسال رسالة إلى مستخدم عندما تُرسِل مكتبة برمجة تطبيقات Node.js لعملاء RBM رسائل RBM، توفّر المكتبة عنصر استجابة في messageId messageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageIdmessageId

في ما يلي مثال على إرسال رسالة نصية عادية إلى مستخدم وتسجيل معلومات الرسالة بعد التواصل بنجاح مع واجهة برمجة التطبيقات 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);
});

بعد تشغيل التعليمة البرمجية، يمكنك فحص "مخزن البيانات" من خلال Google Cloud Console ضِمن كيانات تخزين البيانات مشاهدة.

Datastore

تعديل حالة تسليم الرسائل

والآن بعد أن يخزّن الوكيل طلبات الرسائل المرسلة في مخزن البيانات، عليك تحديث حالة التسليم بمجرد تسليم الرسالة بنجاح إلى جهاز المستخدم.

المستخدِمين الأجهزة التي ترسل "DELIVERED" و"READ" و"IS_TYPING" إلى وكلاء RBM عبر Cloud Pub/Sub. في معالِج Pub/Sub، تحقَّق من الأحداث التي تم تسليمها وعدِّل إعداد Datastore للعلامة delivered على 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
    }
}

يحفظ الوكيل الرسائل الصادرة في مخزن البيانات ويحدِّث البيانات عند إشعار تسليم. في القسم التالي، اطّلِع على كيفية إعداد مهمة cron على App Engine من Google لتشغيلها كل 10 دقائق من أجل مراقبة الرسائل التي لم يتم تسليمها.

ملف Cron: App Engine الخاص بـ Google

يمكنك استخدام مهام cron لجدولة المهام على فترات زمنية مختلفة. في تطبيق Google المحرك، مهمة cron يتم ضبطها مع وصف وعنوان URL وفاصل زمني.

في تطبيقات Node.js، يمكنك ضبط هذه الإعدادات في ملف cron.yaml، ويمكنك نشره. إلى App Engine باستخدام حزمة تطوير برامج Google Cloud. اطّلِع على معلومات عن عمليات ضبط اللغة الأخرى في مقالة جدولة المهام باستخدامملف cron.yaml.

بما أنّ مهمة cron تحتاج إلى عنوان URL، عليك إضافة نقطة نهاية عنوان URL إلى جهاز توجيه express app ليتم استدعاؤها من خلال cron. يتولّى برنامج "الردّ التلقائي على الويب" هذا طلب البحث في قاعدة بيانات Datastore عن الرسائل القديمة وحذفها من منصة RBM وإرسالها إلى المستخدم عبر الرسائل القصيرة.

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

طلب البحث في قاعدة البيانات عن الرسائل التي لم يتم إرسالها

في رابط البيانات لوظيفت cron التي أعددتها في القسم السابق، عليك إضافة منطق للبحث عن جميع الرسائل المُرسَلة التي تكون حالةdelivered فيها تساوي false ويكون وقت lastUpdated لها أقدم من مهلة محدّدة مسبقًا ومنطقية بالنسبة إلى حالة الاستخدام. في هذا المثال، تنتهي صلاحية الرسائل الأقدم من ساعة.

لكي يتوافق محرك التخزين مع طلب بحث مركّب مثل هذا، يجب أن يحتوي على ملف فهرس مركّب يحتوي على السمتَين 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

مع تحديد الفهرس، يمكنك الرجوع إلى الرد التلقائي على الويب الذي أنشأته للغة 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 استخدام الرسائل القصيرة كخيار احتياطي تلقائيًا، لذا عليك تنفيذ منطق لإرسال رسائلك التي لم يتم تسليمها عبر الرسائل القصيرة.

الملخّص والخلاصة

للتعامل مع المستخدمين الذين لا يتوفّر لديهم اتصال بالإنترنت، يمكنك إنشاء منطق لإبطال رسائل "الاستجابة لرسائل البريد التسويقي" التي لم يتم تسليمها. تعتمد المدة التي تستغرقها قبل انتهاء صلاحية الرسالة على مدى حساسية المعلومات التي تُرسِلها للوقت. بالنسبة إلى المعلومات الحسّاسة للوقت، يُنصح باستخدام مهلة أقل من ساعتَين.

يستخدم هذا المثال مخزن البيانات السحابية وGoogle App Engine لإدارة التخزين، والاستعلام والإبطال، ولكن أي آلية تخزين لتتبع ينبغي أن تعمل الرسائل المرسلة والمسلمة بشكل سليم.

حظًا سعيدًا، ونتمنى لك ترميزًا سعيدًا!