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

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

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

في هذه المقالة، سأوضّح لك كيفية استخدام مخزن بيانات Google Cloud لتتبُّع الرسائل التي ترسلها وتسلمها، وكيفية استخدام cron revoke الرسائل غير المُستلَمة، وكيفية إعادة توجيه هذه الرسائل عبر الرسائل القصيرة SMS.

تتبع الرسائل المرسلة

يجب أن تتضمّن كل رسالة يرسلها وكيل RBM معرِّف رسالة فريد. لتتبُّع الرسائل التي يرسلها وكيلك، عليك حفظ معرّف الرسالة ورقم الهاتف والطابع الزمني لكلّ رسالة.

يمكنك استخدام مجموعة متنوعة من التقنيات لتخزين هذه المعلومات، ولكن في هذه المقالة أستخدم مخزن بيانات Google Cloud. مخزن البيانات في السحابة الإلكترونية هو قاعدة بيانات NoSQL قابلة للتطوير بشكل كبير تعالج تلقائيًا عملية التقسيم والنسخ المماثل. إنه حل رائع لتخزين البيانات غير العلائقية مثل الرسائل التي يرسلها الوكيل. يعتمد تخزين البيانات في السحابة الإلكترونية على توفُّر مثيل Google App Engine نشط، لذلك أستخدم App Engine لاستضافة وكيل RBM وإعداد مهمة cron.

تتوفّر مكتبات برامج لخدمة "تخزين البيانات في السحابة الإلكترونية" بعدة لغات. في هذا المثال، أستخدم Node.js وأضع رمز وكيل RBM على نموذج Node.js الأول للوكيل المتاح على الموقع الإلكتروني لمطوّر برامج RBM. أول شيء أفعله هو تثبيت Cloud Datastore لمشروع Node.js الخاص بي عن طريق تشغيل الأمر التالي:

npm install --save @google-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);
});

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

Datastore

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

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

ترسِل أجهزة المستخدمين أحداث DELIVERED وREAD وIS_TYPING إلى وكلاء RBM من خلال Cloud Pub/Sub. في معالج النشر/الاشتراك، تحقق من الأحداث التي تم تسليمها وحدِّث إعداد "مخزن البيانات" للعلامة التي تم تسليمها إلى "صحيح".

/**
 *   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 في Google App Engine لتشغيلها كل 10 دقائق لمراقبة الرسائل التي لم يتم تسليمها.

كرون في App Engine من Google

يمكنك استخدام مهام cron لجدولة المهام على فترات مختلفة. في App Engine من Google، تتم تهيئة مهمة cron باستخدام وصف وعنوان URL وفاصل زمني.

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

نظرًا لأن مهمة cron تحتاج إلى عنوان URL، فأنت بحاجة إلى إضافة نقطة نهاية عنوان URL إلى جهاز توجيه التطبيق السريع ليتم استدعاؤه بواسطة cron. يكون هذا الرد التلقائي مسؤولاً عن الاستعلام عن الرسائل القديمة في مخزن البيانات، وحذفها من نظام ميزة "مراسلة الأنشطة التجارية من خلال خدمات الاتصالات التفاعلية (RCS)"، وإرسالها إلى المستخدم عبر الرسائل القصيرة 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

الاستعلام عن رسائل في مخزن البيانات لم يتم تسليمها

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

لإتاحة استعلام مركب مثل هذا، يجب أن يتوفر في "مخزن البيانات" فهرس مركّب يحتوي على السمتَين delivered وlastUpdated. للقيام بذلك، يمكنك إنشاء ملف في مشروعك يسمى index.yaml باستخدام المعلومات التالية:

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

على غرار نشر مهمة cron التي حددتها سابقًا، استخدِم حزمة تطوير البرامج (SDK) في Google Cloud لنشر الفهرس المركّب الذي حدّدته باستخدام الأمر التالي:

gcloud datastore create-indexes index.yaml

بعد النشر، يضبط App Engine تلقائيًا الفهرس، ويمكن عرض الفهرس ضمن مخزن البيانات > الفهارس.

فهارس مخزن البيانات

من خلال تحديد الفهرس، يمكننا الرجوع إلى الرد التلقائي على الويب الذي أنشأته لمهمة 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();
});

لا تدعم ميزة "مراسلة الأنشطة التجارية من خلال خدمات الاتصالات التفاعلية (RCS)" في الأساس الإجراء الاحتياطي للرسائل القصيرة SMS، لذا ستحتاج إلى تنفيذ المنطق لإرسال الرسائل التي لم يتم تسليمها عبر الرسائل القصيرة SMS.

الملخص والنص المختصر (TL;DR)

للتعامل مع المستخدمين غير المتصلين بالإنترنت، يمكنك إنشاء منطق الإبطال لرسائل RBM التي لم يتم تسليمها. تعتمد المدة الزمنية قبل انتهاء صلاحية الرسالة على مدى حساسية المعلومات التي ترسلها. أما بالنسبة إلى المعلومات الحساسة للوقت، فننصح بأن تكون المهلة أقل من ساعتين.

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

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