使用者定義函式 (UDF) 簡介

JavaScript User-Defined Function (UDF) 是一種 Single Message Transform (SMT)。使用者定義函式提供彈性的方式,可在 Pub/Sub 中實作自訂轉換邏輯,類似於 BigQuery JavaScript 使用者定義函式

UDF 會接受單一訊息做為輸入內容,對輸入內容執行定義的動作,並傳回處理結果。

UDF 具有下列重要屬性:

  • 程式碼:定義轉換邏輯的 JavaScript 程式碼。

  • 函式名稱:Pub/Sub 會將提供的程式碼套用至訊息,這個欄位是程式碼中的 JavaScript 函式名稱。

建立 JavaScript 函式

UDF 程式碼必須包含具有下列簽章的函式:

  /**
  * Transforms a Pub/Sub message.
  * @return {(Object<string, (string | Object<string, string>)>|* null)} - To
  * filter a message, return `null`. To transform a message, return a map with
  * the following keys:
  *   - (required) 'data' : {string}
  *   - (optional) 'attributes' : {Object<string, string>}
  * Returning empty `attributes` will remove all attributes from the message.
  *
  * @param  {(Object<string, (string | Object<string, string>)>} - Pub/Sub
  * message. Keys:
  *   - (required) 'data' : {string}
  *   - (required) 'attributes' : {Object<string, string>}
  *
  * @param  {Object<string, any>} metadata - Pub/Sub message metadata.
  * Keys:
  *   - (optional) 'message_id'  : {string}
  *   - (optional) 'publish_time': {string} YYYY-MM-DDTHH:MM:SSZ format
  *   - (optional) 'ordering_key': {string}
  */
  function <function_name>(message, metadata) {
    // Perform custom transformation logic
    return message; // to filter a message instead, return `null`
  }

輸入內容

這個函式會採用下列輸入內容:

  • message 引數:代表 Pub/Sub 訊息的 JavaScript 物件。其中包含下列屬性:

    • data:(String,必要) 訊息酬載。

    • attributes:(Object<String, String>,選用) 代表訊息屬性的鍵值對應地圖。

  • metadata 引數:包含 Pub/Sub 訊息不可變更中繼資料的 JavaScript 物件:

    • message_id:(String,選用) 訊息的專屬 ID。

    • publish_time:(String,選用) 訊息的發布時間,格式為 RFC 3339 (YYYY-MM-DDTHH:mm:ssZ)。

    • ordering_key:(String,選用) 訊息的排序鍵 (如適用)。

輸出內容

這個函式必須傳回下列其中一項:

  • 如要轉換訊息,請編輯 message.datamessage.attributes 的內容,並傳回變更後的 message 物件。

  • 如要篩選訊息,請傳回 null

輸入 / 輸出內容規定

  • 如果 UDF 會轉換訊息酬載,則酬載輸入和輸出內容必須是 UTF-8 編碼的字串。
  • 如果 UDF 未轉換訊息酬載,酬載可使用任何編碼。
  • 屬性鍵/值組合必須是 UTF-8 編碼的字串。

UDF 如何轉換訊息

在郵件上執行 UDF 的結果可能是下列其中之一:

  • UDF 會轉換訊息。

  • UDF 會傳回 null

    • 主題 SMT:Pub/Sub 會向發布者傳回成功訊息,並在篩選後訊息的回應中加入訊息 ID。Pub/Sub 不會儲存訊息,也不會傳送給任何訂閱端。

    • 訂閱項目 SMT:Pub/Sub 會確認訊息已傳送,但不會將訊息傳送給訂閱者。

  • UDF 擲回錯誤。

    • 主題 SMT:Pub/Sub 會將錯誤傳回給發布者,且不會發布任何訊息。

    • 訂閱項目 SMT:Pub/Sub 會對訊息發出否定確認。

建立 UDF SMT

您可以在 Pub/Sub 主題或訂閱項目上設定 SMT。

  • 主題 SMT 會在 Pub/Sub 儲存訊息前執行,且所有訂閱者都能取得結果。
  • 訂閱項目 SMT 會在郵件傳送前執行,且結果只適用於該訂閱項目。

控制台

  1. 前往 Google Cloud 控制台的 Pub/Sub「主題」頁面。

    前往「主題」

  2. 建立主題或訂閱項目。

    • 如要建立主題,請按一下「建立主題」。「建立主題」頁面隨即開啟。

    • 如要建立訂閱:

      1. 按一下要建立訂閱項目的主題名稱。

      2. 按一下「建立訂閱項目」。「將訂閱項目新增至主題」頁面隨即開啟。

  3. 在「轉換」下方,按一下「新增轉換」

  4. 在「轉換類型」部分,選取「JavaScript UDF」

  5. 在「函式名稱」欄位中,輸入 SMT 呼叫的 JavaScript 函式名稱。範例:redactSSN

  6. 在文字區域中輸入 UDF 的程式碼。範例:

    function redactSSN(message, metadata) {
      const data = JSON.parse(message.data);
      delete data['ssn'];
      message.data = JSON.stringify(data);
      return message;
    }
    

    程式碼必須包含名稱與「函式名稱」欄位相符的函式。

  7. 如不想立即啟用 SMT,請選取「停用轉換」。選取這個選項後,系統會使用主題建立 SMT,但不會對內送郵件執行 SMT。建立主題後,您可以編輯主題來啟用 SMT。

  8. 如要建立主題或訂閱項目,請按一下「建立」

gcloud

建立定義檔

建立定義 UDF SMT 的 YAML 或 JSON 檔案。

YAML

- javascriptUdf:
    code: { FUNCTION_CODE }
    functionName: FUNCTION_NAME

JSON

{
  "javascriptUdf": {
    "code": {
      FUNCTION_CODE
    }
    "functionName": FUNCTION_NAME
  }
}

更改下列內容:

  • FUNCTION_CODE:UDF 的 JavaScript 程式碼。程式碼必須包含名稱與 functionName 欄位相符的函式。範例:

    function redactSSN(message, metadata) {
      const data = JSON.parse(message.data);
      delete data['ssn'];
      message.data = JSON.stringify(data);
      return message;
    }
    
  • FUNCTION_NAME:SMT 呼叫的 JavaScript 函式名稱。範例:redactSSN

建立主題或訂閱項目

如要建立主題,請執行 gcloud pubsub topics create 指令。

gcloud pubsub topics create TOPIC_ID \
  --message-transforms-file=TRANSFORMS_FILE

更改下列內容:

  • TOPIC_ID:要建立的主題 ID 或名稱。
  • TRANSFORMS_FILE:定義檔案的路徑。

如要建立訂閱項目,請執行 gcloud pubsub subscriptions create 指令。

gcloud pubsub subscriptions create SUBSCRIPTION_ID \
  --topic=projects/PROJECT_ID/topics/TOPIC_ID \
  --message-transforms-file=TRANSFORMS_FILE

更改下列內容:

  • SUBSCRIPTION_ID:要建立的訂閱項目 ID 或名稱。

  • PROJECT_ID:包含主題的專案 ID。

  • TOPIC_ID:要訂閱的主題 ID。

  • TRANSFORMS_FILE:定義檔案的路徑。

你也可以先驗證及測試 SMT,再建立 SMT。詳情請參閱下列頁面:

限制

Pub/Sub 會對 UDF 執行資源限制,確保轉換作業的效率。限制包括:

  • 每個 UDF 的程式碼上限為 20 KB
  • 每則訊息的執行時間上限為 500 毫秒
  • 僅支援 ECMAScript 標準內建函式
  • 不呼叫外部 API
  • 不匯入外部程式庫

UDF 範例

以下列舉一些發布及訂閱的 UDF 範例。您可以在UDF 程式庫中找到其他範例。

函式:將星期幾的整數轉換為對應的字串

將下列 UDF 新增至主題或訂閱項目時,系統會在發布或傳送訊息期間進行下列變更:

  1. Pub/Sub 會將函式套用至訊息。如果訊息沒有 JSON 酬載,UDF 會擲回錯誤。

  2. 使用者定義函式會尋找名為 dayOfWeek 的欄位,如果這個欄位的值是介於 0 到 6 之間的數字,就會轉換為對應的星期幾,例如 Monday。如果該欄位不存在,或數字不在 0 到 6 的範圍內,程式碼會將 dayOfWeek 欄位設為 Unknown

  3. UDF 會將修改後的酬載序列化回訊息。

  4. Pub/Sub 會將更新後的訊息傳遞至管道的下一個步驟。

function intToString(message, metadata) {
  const data = JSON.parse(message.data);
  switch(`data["dayOfWeek"]`) {
    case 0:
      data["dayOfWeek"] = "Sunday";
      break;
    case 1:
      data["dayOfWeek"] = "Monday";
      break;
    case 2:
      data["dayOfWeek"] = "Tuesday";
      break;
    case 3:
      data["dayOfWeek"] = "Wednesday";
      break;
    case 4:
      data["dayOfWeek"] = "Thursday";
      break;
    case 5:
      data["dayOfWeek"] = "Friday";
      break;
    case 6:
      data["dayOfWeek"] = "Saturday";
      break;
    default:
      data["dayOfWeek"] = "Unknown";
  }
  message.data = JSON.stringify(data);
  return message;
}

功能:遮蓋身分證字號

將下列 UDF 新增至主題或訂閱項目時,系統會在發布或傳送訊息期間進行下列變更:

  1. Pub/Sub 會將函式套用至訊息。如果訊息沒有 JSON 酬載,UDF 會擲回錯誤。

  2. UDF 會從訊息酬載中移除欄位 ssn (如果存在)。

  3. UDF 會將修改後的酬載序列化回訊息。

  4. Pub/Sub 會將更新後的訊息傳遞至管道的下一個步驟。

function redactSSN(message, metadata) {
  const data = JSON.parse(message.data);
  delete data['ssn'];
  message.data = JSON.stringify(data);
  return message;
}

功能:篩除特定訊息並自動確認

將下列 UDF 新增至主題或訂閱項目時,系統會在發布或傳送訊息期間進行下列變更:

  1. Pub/Sub 會將函式套用至訊息。如果訊息沒有 JSON 酬載,UDF 會擲回錯誤。

  2. UDF 會檢查酬載是否包含名為 region 的欄位。

  3. 如果 region 欄位的值不是 US,函式會傳回空值,導致 Pub/Sub 篩除訊息。

  4. 如果 region 欄位的值為 US,Pub/Sub 會將原始訊息傳遞至管道的下一個步驟。

function filterForUSRegion(message, metadata) {
  const data = JSON.parse(message.data);
  if (data["region"] !== "US") {
    return null;
  }
  return message;
}

函式:驗證訊息內容,確保金額不超過 100

將下列 UDF 新增至主題或訂閱項目時,系統會在發布或傳送訊息期間進行下列變更:

  1. Pub/Sub 會將函式套用至訊息。如果訊息沒有 JSON 酬載,UDF 會擲回錯誤。

  2. 這項 UDF 會檢查訊息是否包含名為 amount 的欄位。

  3. 如果 amount 欄位的值大於 100,函式會擲回錯誤。

  4. 如果 amount 欄位的值不大於 100,函式會傳回原始訊息。

  5. Pub/Sub 接著會將訊息標示為失敗,或將原始訊息傳遞至管道中的下一個步驟。

function validateAmount(message, metadata) {
  const data = JSON.parse(message.data);
  if (data["amount"] > 100) {
    throw new Error("Amount is invalid");
  }
  return message;
}

後續步驟