إنشاء تطبيق أوّلي

يوضّح هذا المستند كيفية إنشاء إجراء تفعيل يتيح لتطبيقك أو خدمتك إرسال إشعار إلى Google Workspace Studio عند وقوع حدث وبدء تنفيذ تدفّق. في واجهة برمجة التطبيقات، يُطلق على هذه الحزم اسم workflowTriggers.

يبدأ المشغّل سير العمل، بينما الخطوة هي مهمة واحدة في تسلسل المهام التي يتضمّنها سير العمل. من خلال إنشاء إجراء تفعيل، يمكنك السماح للمستخدمين بإعداد مسارات مبرمَجة تستجيب للأحداث في الوقت الفعلي من تطبيقك أو خدمتك.

يتضمّن إنشاء أداة بدء تحديد الأداة في ملف بيان الإضافة وتنفيذ عمليات معاودة الاتصال بدورة الحياة في "برمجة تطبيقات Google"، أو تشغيل الأداة من خلال نشر حمولات إلى نقطة نهاية Google Workspace Studio API.

المتطلبات الأساسية وتفويض OAuth

للتواصل مع نقطة نهاية واجهة برمجة تطبيقات الاستوديو في Workspace Studio، يجب أن يصادق تطبيقك أو خدمتك باستخدام OAuth 2.0. يجب أن يطلب التطبيق من المستخدمين نطاق OAuth المخصّص التالي أثناء منح الإذن:

https://www.googleapis.com/auth/workspace.studio.trigger

يمنح هذا النطاق التطبيق الإذن باستدعاء واجهة برمجة التطبيقات Workspace Studio API وتشغيل المسارات التي أعدّها المستخدم لهذا التطبيق.

التشغيل بلا إنترنت والرموز المميزة لإعادة التحميل

بما أنّ المشغّلات تُعلِم Workspace Studio بشكل غير متزامن عند حدوث حدث في الخدمة الخارجية، وهو ما قد يحدث بعد ساعات أو أيام أو أشهر من إعداد المستخدم لسير عمل، يجب أن توفّر خدمتك رمز دخول صالحًا إلى OAuth 2.0 عند طلب نقطة نهاية واجهة برمجة التطبيقات.

إنّ رمز الدخول الذي تقدّمه Google في عنصر حدث الإضافة (مثل أثناء إعدادات التفعيل أو طلبات الاستدعاء في إحدى مراحل النشاط) يكون صالحًا لمدة قصيرة، أي ساعة واحدة فقط. وهي غير كافية لتفعيل أحداث بدء التشغيل بشكل غير متزامن في المستقبل. لاستخدام Workspace Studio API بشكل متكرر، تتطلّب خدمتك رمزًا مميّزًا لإعادة التحميل غير متصل بالإنترنت من أجل إنشاء رموز دخول جديدة عند الطلب.

تعتمد طريقة التعامل مع التفويض والحصول على رمز مميّز لإعادة التحميل على وقت تشغيل الإضافة:

  • إضافات HTTP (أوقات تشغيل بديلة): بالنسبة إلى إضافات HTTP، يجب أن تنفّذ خدمة الخلفية مسار تفويض منفصلاً باستخدام OAuth 2.0 بشكل مستقل عن تفويض الإضافة المضمّن لطلب الوصول بلا إنترنت (access_type=offline) وتلقّي رمز مميّز لإعادة التحميل.

    يمكنك أن تطلب من المستخدمين السماح بهذا الربط من خلال عرض بطاقة تسجيل الدخول أو بطاقة التفويض عندما يضبط المستخدم أداة التشغيل في Workspace Studio. لمزيد من المعلومات حول عرض بطاقات التفويض والتعامل مع مسار OAuth، يُرجى الاطّلاع على ربط إضافة Google Workspace بخدمة خارجية (معاملة Google Workspace على أنّه الخدمة الخارجية التي يتم الربط بها).

    يجب أن تخزّن خدمة الخلفية الرمز المميّز لإعادة التحميل بشكل آمن (مثلاً، في قاعدة بيانات خدمتك بجانب triggerId) وأن تستخدمه لاسترداد رمز دخول جديد كلما وقع حدث قبل إرسال الطلبات إلى نقطة نهاية واجهة برمجة التطبيقات notifyUri أو triggers.fire الخاصة بالخدمة.

  • إضافات "برمجة تطبيقات Google": يمكن للإضافات المستندة إلى "برمجة تطبيقات Google" والتي تستخدم مشغّلات مجدولة (تستند إلى الوقت) للبحث عن الأحداث أن تتخطى تنفيذ مسار OAuth مستقل. بما أنّ المشغّلات المجدوَلة تعمل مباشرةً ضمن بيئة وقت التشغيل في برمجة تطبيقات Google، تتولّى برمجة تطبيقات Google تلقائيًا إدارة رموز OAuth المميزة وإعادة تحميلها باستخدام النطاقات المحدّدة في ملف البيان.

تحديد التطبيق الأولي في ملف البيان

لتحديد إجراء تفعيل، أضِفه إلى ملف بيان الإضافة (appsscript.json) ضمن كتلة addOns.studio.flows.workflowElements. هذا الإعداد مطلوب لكل من بيئات تشغيل برمجة تطبيقات وHTTP (بيئات التشغيل البديلة). اضبط العنصر على أنّه workflowTrigger بدلاً من workflowAction (الذي يُستخدَم عند تحديد خطوة). لمزيد من المعلومات، يُرجى الاطّلاع على بنية ملف البيان لإضافات Google Workspace.

داخل كتلة workflowTrigger، حدِّد ما يلي:

  • inputs: المتغيرات التي يضبطها المستخدم في بطاقة الإعداد (مثل اسم المشروع وفلتر الموارد وما إلى ذلك).
  • outputs: المتغيّرات التي يمكن أن تعرضها الخطوة الأولية للخطوات اللاحقة في سير العمل.
  • onConfigFunction: اسم دالة ردّ الاتصال التي تعرض واجهة إعدادات المستخدم.
  • onManageFunction: اسم دالة ردّ الاتصال التي تستدعيها Google للتعامل مع إنشاء الاشتراكات التجريبية وحذفها.

يوضّح نموذج الرمز التالي مثالاً على تعريف بيان حدث بادئ:

JSON

{
  "timeZone": "America/Los_Angeles",
  "exceptionLogging": "STACKDRIVER",
  "runtimeVersion": "V8",
  "addOns": {
    "common": {
      "name": "Trigger App",
      "logoUrl": "https://fonts.gstatic.com/s/i/short-term/release/googlesymbols/start/default/24px.svg",
      "useLocaleFromApp": true
    },
    "studio": {
      "flows": {
        "workflowElements": [
          {
            "id": "triggerDemo",
            "state": "ACTIVE",
            "name": "Event Trigger",
            "description": "Fires when a event occurs in the app.",
            "workflowTrigger": {
              "inputs": [
                {
                  "id": "projectId",
                  "description": "The project identifier to watch.",
                  "cardinality": "SINGLE",
                  "dataType": {
                    "basicType": "STRING"
                  }
                }
              ],
              "outputs": [
                {
                  "id": "eventName",
                  "description": "The name of the triggered event.",
                  "cardinality": "SINGLE",
                  "dataType": {
                    "basicType": "STRING"
                  }
                },
                {
                  "id": "eventMessage",
                  "description": "Detailed event message description.",
                  "cardinality": "SINGLE",
                  "dataType": {
                    "basicType": "STRING"
                  }
                }
              ],
              "onConfigFunction": "onConfigTrigger",
              "onManageFunction": "onManageTrigger"
            }
          }
        ]
      }
    }
  }
}

التعامل مع مراحل اشتراك التطبيق المبدئي

عندما يضبط المستخدم مسارًا ويفعّله ويتضمّن هذا المسار تطبيقك المصغّر، أو إذا تم إيقاف المسار أو حذفه، تستدعي Google تطبيقك المصغّر باستخدام دالة معاودة الاتصال onManageFunction المُعرَّفة في ملف البيان.

عنصر حدث يتم في مراحل النشاط

تتلقّى دالة ردّ الاتصال عنصر WorkflowEventObject يحتوي على سياق الإجراء. تشمل هذه الميزات ما يلي:

  • إنشاء مشغّل (event.workflow.triggerCreation): يتم تشغيله عند نشر المسار أو تفعيله.

    • triggerId: سلسلة UUID فريدة تحدّد مثيل التسجيل الأوّلي هذا.

    • notifyUri: عنوان URL الفريد لنقطة نهاية REST API المرتبط بعملية التسجيل التجريبية هذه (على سبيل المثال، https://workspacestudio.googleapis.com/v1/triggers/YOUR_TRIGGER_ID:fire).

    • inputs: إدخالات المتغيّرات التي يضبطها المستخدم من البطاقة.

  • حذف المشغّل (event.workflow.triggerDeletion): يتم تنشيطه عند إزالة المشغّل من المسار أو عند إيقاف المسار بأكمله أو حذفه.

    • triggerId: سلسلة المعرّف الفريد العالمي (UUID) الفريد لمثيل الاشتراك الذي سيتم تنظيفه.

دورة حياة اشتراك Alternate Runtimes (HTTP API)

بالنسبة إلى الإضافات التي تم إنشاؤها باستخدام أوقات تشغيل بديلة، يتم إرسال الإشعارات المتعلقة بدورة حياة الاشتراك باستخدام طلبات HTTP POST إلى عنوان URL لنقطة نهاية HTTP التي تم ضبطها في الإضافة مع اسم الإجراء المحدّد بواسطة دالّة رد الاتصال onManageFunction. تتطابق الحمولة مع تمثيل JSON الخاص بـ WorkflowEventObject.

لمزيد من المعلومات عن أوقات التشغيل البديلة، يُرجى الاطّلاع على إنشاء إضافة في Google Workspace باستخدام نقاط نهاية HTTP.

تنفيذ عمليات الاستدعاء في إحدى مراحل النشاط في برمجة تطبيقات

يوضّح مثال Apps Script التالي كيفية ضبط بطاقة واجهة المستخدم، والتعامل مع أحداث مراحل نشاط الاشتراك باستخدام onManageTrigger، وإرسال طلب بدء التشغيل إلى Google عند وقوع حدث.

برمجة التطبيقات

/**
 * Generates and returns the user configuration card to collect inputs.
 */
function onConfigTrigger() {
  const projectInput = CardService.newTextInput()
    .setFieldName("projectId")
    .setTitle("Project ID")
    .setHint("Enter the project identifier to watch");

  const section = CardService.newCardSection()
    .setHeader("Configure Event Trigger")
    .addWidget(projectInput);

  const card = CardService.newCardBuilder()
    .addSection(section)
    .build();

  return card;
}

/**
 * Handles subscription lifecycle events sent from Google Workspace Studio.
 *
 * @param {Object} event The Workspace Studio event object.
 */
function onManageTrigger(event) {
  const triggerCreation = event.workflow.triggerCreation;
  const triggerDeletion = event.workflow.triggerDeletion;

  if (triggerCreation) {
    const triggerId = triggerCreation.triggerId;
    const notifyUri = triggerCreation.notifyUri;
    const inputs = triggerCreation.inputs;

    // Extract input values configured by the user.
    const projectId = inputs["projectId"].stringValues[0];

    // TODO: Save triggerId, notifyUri, and projectId in your database/service.
    // Your backend service listens for events related to 'projectId'
    // and calls notifyUri when those events occur.
    console.log("Trigger subscription created: " + triggerId +
                ", Notify URI: " + notifyUri +
                ", Match Project: " + projectId);

  } else if (triggerDeletion) {
    const triggerId = triggerDeletion.triggerId;

    // TODO: Remove references to triggerId from your database and stop
    // sending future event notifications to the associated notifyUri.
    console.log("Trigger subscription deleted: " + triggerId);
  }
}

/**
 * Mock function showing how your backend service fires the trigger.
 * This logic runs on your service when a watched event occurs.
 *
 * @param {string} notifyUri The stored notifyUri associated with the trigger.
 * @param {string} triggerId The stored triggerId.
 * @param {string} userAccessToken The OAuth 2.0 access token for the user
 *     (obtained using your stored refresh token).
 */
function simulateEventFire(notifyUri, triggerId, userAccessToken) {
  // A unique UUID version 4 is recommended as the requestId for idempotency.
  const requestId = Utilities.getUuid();

  const payload = {
    "name": "triggers/" + triggerId,
    "outputs": {
      "eventName": { "stringValues": ["EventOccurred"] },
      "eventMessage": { "stringValues": ["Hello from the service!"] }
    },
    "requestId": requestId
  };

  const options = {
    "method": "POST",
    "contentType": "application/json",
    "headers": {
      "Authorization": "Bearer " + userAccessToken
    },
    "payload": JSON.stringify(payload),
    "muteHttpExceptions": true
  };

  const response = UrlFetchApp.fetch(notifyUri, options);
  const responseCode = response.getResponseCode();

  if (responseCode === 200) {
    console.log("Trigger successfully fired!");
  } else if (responseCode === 404) {
    // 404 means the trigger registration is invalid or deleted.
    console.log("Trigger not found. Stop sending events for this trigger.");
    // TODO: Clean up the trigger from your backend database.
  } else if (responseCode === 429 || responseCode >= 500) {
    console.log("Temporary error (" + responseCode + "). Retry using exponential backoff.");
  } else {
    console.log("Failed to fire trigger. HTTP Code: " + responseCode + " - " + response.getContentText());
  }
}

استخدام Workspace Studio API

يمكنك استخدام واجهة برمجة التطبيقات Workspace Studio (workspacestudio.googleapis.com) لإرسال إشعارات آليًا إلى Google بشأن أحداث البدء.

تقع نقاط النهاية ضمن المسار الأساسي: https://workspacestudio.googleapis.com/v1.

إرسال إشعار بحدث بدء

ينشِّط إجراء التفعيل باستخدام الطريقة triggers.fire لبدء تنفيذ تدفّق.

  • طريقة HTTP: POST
  • المسار: /v1/triggers/{triggerId}:fire (حيث {triggerId} هو المعرّف الفريد الذي تم استرداده أثناء إنشاء اشتراك المشغّل)
  • نطاق OAuth: https://www.googleapis.com/auth/workspace.studio.trigger

يوضّح عينة التعليمات البرمجية التالية كيفية تنشيط إجراء التفعيل في الطلب.

الطلب

{
  "name": "triggers/TRIGGER_ID",
  "outputs": {
    "eventName": {
      "stringValues": [
        "EventOccurred"
      ]
    },
    "eventMessage": {
      "stringValues": [
        "Hello from the service!"
      ]
    }
  },
  "log": {
    "textFormatElements": [
      {
        "text": "An event occurred in the app."
      }
    ]
  },
  "requestId": "UNIQUE_REQUEST_ID"
}
  • name (سلسلة، مطلوبة): اسم المورِد الخاص بالبرنامج التجريبي، بالتنسيق triggers/{triggerId}
  • outputs (خريطة، اختياري): خريطة لمتغيرات الإخراج الأولية التي تمثّل بيانات الحدث. كل قيمة هي عنصر VariableData يتوافق مع القوائم المكتوبة (مثل stringValues وbooleanValues وintegerValues).
  • log (كائن، اختياري): تمثيل ترميز TextFormat معروض في سجلّات أنشطة التنفيذ في Workspace Studio.
  • requestId (سلسلة، اختياري): معرّف فريد (يُنصح باستخدام UUID الإصدار 4) يتضمّن ما يصل إلى 36 حرفًا من أحرف ASCII لضمان تكرار واجهة برمجة التطبيقات عند إعادة المحاولة.

الردّ

يعرض الردّ كائن JSON فارغًا {} عند النجاح.

حصص واجهة برمجة تطبيقات الاستوديو في Workspace Studio

يتم حصر حركة البيانات المرسَلة إلى خدمة workspacestudio.googleapis.com لمنع التحميل الزائد على النظام وتشجيع الاستخدام العادل للموارد وحماية الأداء العام لـ Google Workspace.

يتم فرض الحصص التالية:

نوع الحصة الحصة
في الدقيقة الواحدة لكل مشروع 1,000 طلب بدء محادثة
في الدقيقة الواحدة لكل مستخدم ‫100 طلب بدء محادثة

أنواع الحصص هي:

  • في الدقيقة الواحدة لكل مشروع على السحابة الإلكترونية: يحدّ هذا الخيار من العدد التراكمي لأحداث التطبيقات التجريبية التي يتم تشغيلها من مشروع واحد على Google Cloud خاص بمطوّر واحد إلى 1,000 طلب في الدقيقة الواحدة على مستوى جميع المستخدمين الذين يشغّلون تطبيقاته التجريبية.
  • في الدقيقة الواحدة لكل مستخدم: يفرض هذا الحدّ على أي مستخدم نهائي واحد ألا يتجاوز إجمالي عدد استدعاءات إجراء التفعيل التي يرسلها في مشروع على السحابة الإلكترونية معيّن 100 طلب في الدقيقة الواحدة.

التعامل مع أخطاء الحصة المستندة إلى الوقت

في حال تجاوزت هذه الحصص، ستعرض واجهة برمجة التطبيقات رمز خطأ HTTP 429 Too Many Requests (أو 429 Resource Exhausted) يشير إلى أنّه تم تجاوز حصة المعدّل.

لحلّ هذه الأخطاء، يجب أن يرصد الرمز البرمجي الاستثناء ويستخدم استراتيجية "التراجع الدليلي" المقتطعة. تعذّر إعادة محاولة تنفيذ الطلبات باستخدام خوارزمية الرقود الأسي الثنائي، التي تستخدم حالات تأخير أطول تدريجيًا بين المحاولات، بما في ذلك التأخير العشوائي (إعادة احتساب التأخير العشوائي في كل تكرار) لمنع العديد من العملاء من المزامنة وإعادة المحاولة في الوقت نفسه:

  1. إرسال طلب إلى Workspace Studio API
  2. إذا تعذّر تنفيذ الطلب وظهر الخطأ 429، يُرجى الانتظار لمدة 1 second + random_number_milliseconds وإعادة المحاولة.
  3. إذا تعذّر ذلك مرة أخرى، انتظِر 2 seconds + random_number_milliseconds وأعِد المحاولة.
  4. إذا تعذّر ذلك مرة أخرى، انتظِر 4 seconds + random_number_milliseconds وأعِد المحاولة.
  5. واصِل هذه العملية، مع مضاعفة مدة التأخير إلى أن تصل إلى حد maximum_backoff (عادةً 32 أو 64 ثانية).
  6. بعد بلوغ الحد الأقصى لمدة التراجع، أعِد المحاولة باستخدام هذا التأخير الثابت إلى أن يتم بلوغ الحد الأقصى لعدد المحاولات، ثم توقّف وسجِّل الخطأ.

أفضل الممارسات

عند تصميم وتنفيذ تطبيق نموذجي، ننصحك باتّباع أفضل الممارسات التالية:

إرسال أحداث فردية بدلاً من قوائم مجمّعة

صمِّم تطبيقك المبدئي لإصدار حدث فردي لكل حالة مميزة (مثل تعديل سجلّ واحد أو نشر رسالة جديدة أو تعيين مهمة)، بدلاً من إصدار حدث واحد يحتوي على دفعة أو قائمة عناصر:

  • التوافق مع أدوات البدء المضمّنة: في Workspace Studio، يتم تشغيل أدوات البدء المضمّنة في Google Workspace (مثل تلقّي رسالة إلكترونية في Gmail أو انضمام مستخدم إلى مساحة في Google Chat) عند حدوث حدث واحد. يتوافق إصدار أحداث عنصر واحد مع هذا السلوك، كما يوفّر تجربة متسقة يمكن التنبؤ بها للمستخدمين في جميع التطبيقات النموذجية.
  • إعداد أسهل لسير العمل: تعالج الخطوات اللاحقة في سير العمل عادةً عنصرًا واحدًا في كل مرة. يتيح إصدار أحداث تتضمّن عنصرًا واحدًا للمستخدمين ربط المتغيّرات مباشرةً بدون إضافة خطوات معقّدة لتكرار المصفوفات أو تحليل القوائم.
  • التعامل مع عمليات الاقتراع والتغييرات المجمّعة بشكل فردي: إذا كانت خدمة الخلفية تستطلع واجهة برمجة تطبيقات خارجية ورصدت عدة عناصر تم تغييرها خلال فترة استطلاع واحدة، أرسِل حدث بدء فردي لكل عنصر بدلاً من تجميعها في حدث مجمّع واحد.
  • إدارة معدّل الأحداث والحصص: بما أنّ إطلاق أحداث فردية لعناصر متعدّدة تم تغييرها يمكن أن يؤدي إلى زيادة مفاجئة في الطلبات، احرص على أن تلتزم خدمتك بحصص Workspace Studio API (مثل الحدّ الأقصى البالغ 100 طلب في الدقيقة لكل مستخدم). إذا نتج عن دورة استطلاع عدد كبير من العناصر (على سبيل المثال، أكثر من 100 سجلّ تم تغييره)، يجب تحديد وتيرة إرسال الأحداث أو تقييدها بمرور الوقت لتجنُّب أخطاء 429 Too Many Requests.

السلوكيات الأساسية والحالات الهامشية

عند دمج التطبيقات التجريبية، على المطوّرين التعامل مع سلوكيات الأخطاء وميزات وقت التشغيل المحدّدة:

  • عدم توفّر ميزة "التشغيل التجريبي": لا يتيح Workspace Studio ميزة "التشغيل التجريبي" للمبتدئين.
  • التكرار ومنع إعادة التشغيل: على الرغم من أنّ ذلك ليس مطلوبًا بشكل صارم، عليك تضمين requestId فريد (مثل معرّف فريد عالمي) في حمولة HTTP أو Apps Script. يضمن توفير requestId عدم تغيّر النتيجة عند تكرار عملية الإرسال، وذلك من خلال السماح لواجهة برمجة التطبيقات برصد الإشعارات المكرّرة وتجاهلها، ما يمنع تنفيذ سير العمل عدة مرات لحدث واحد.
  • المسارات التي تم إيقافها وإعادة تفعيلها: عندما يتم إيقاف مسار يحتوي على المشغّل في Workspace Studio، ترسل Google حدث يتم في مراحل النشاط triggerDeletion إلى دالة الاستدعاء onManageFunction. بالإضافة إلى ذلك، ستعرض أي طلبات يتم إجراؤها على الطريقة المرتبطة FireTrigger رمز خطأ 404 Not Found (Requested entity was not found.). يجب أن تتفاعل خدمتك مع أخطاء 404 من خلال إيقاف عمليات تسليم الإشعارات المستقبلية بالأحداث لمعرّف مثيل المشغّل هذا.

    إذا أعاد المستخدم تفعيل مسار الاشتراك لاحقًا، ستبدأ Google دورة اشتراك جديدة من خلال استدعاء دالة onManageFunction للردّ مع حدث triggerCreation جديد يحتوي على triggerId وnotifyUri جديدَين. تم إيقاف triggerId السابق نهائيًا ولن تتم إعادة تفعيله، لذا يجب ألا تستطلع خدمتك أو تتحقّق مما إذا تمت إعادة تفعيل مثيل مشغّل قديم. لمزيد من المعلومات، يُرجى الاطّلاع على التعامل مع مراحل نشاط الاشتراك التجريبي.

  • حذف الاشتراكات بشكل متكرر: يجب أن تتعامل دالة معاودة الاتصال onManageFunction مع طلبات حذف الاشتراكات من Google بشكل متكرر. إذا اتصلت Google بخطاف الحذف عدة مرات للرمز triggerId نفسه (على سبيل المثال، أثناء عمليات إعادة المحاولة بسبب فقدان الاتصال مؤقتًا)، يجب أن تعرض الدالة نتيجة ناجحة.

  • حصص المسارات: بالإضافة إلى حصص واجهة برمجة التطبيقات في Workspace Studio، تخضع مسارات المستخدمين لعناصر تحكّم داخلية إضافية في الحصص. قد تؤدي الحلقات المتكررة أو العدد الكبير من الأحداث إلى تجاوز حدود الأمان، ما يؤدي إلى إيقاف المسار تلقائيًا.