共用方式為


JavaScript 功能管理

feature-management-npm-package

JavaScript 功能管理程式庫可讓您根據功能旗標來開發和公開應用程式功能。 一旦開發新功能之後,許多應用程式都有特殊需求,例如何時應該啟用此功能,以及要在哪些情況下啟用此功能。 此程式庫提供一種方式來定義這些關聯性,並整合至常見的 JavaScript 程式碼模式,讓公開這些功能成為可能。

功能旗標提供 JavaScript 應用程式動態開啟或關閉功能的方式。 開發人員可以在簡單的使用案例 (例如,條件陳述式) 中使用功能旗標。

以下是使用 JavaScript 功能管理程式庫的一些優點:

  • 功能管理的常見慣例
  • 進入門檻較低
    • 同時支援 JSON 物件和對應型功能旗標來源
    • 支援在 Node.js 和瀏覽器環境中使用
  • 使用 Azure 應用程式組態進行功能旗標存留期管理
    • 組態值可以即時變更
  • 涵蓋簡單至複雜的案例
    • 透過宣告式組態檔切換開啟/關閉功能
    • 根據對伺服器的呼叫動態評估功能的狀態

JavaScript 功能管理程式庫是開放原始碼。 如需詳細資訊,請造訪 GitHub 存放庫

附註

建議搭配 Azure 應用程式組態使用功能管理程式庫。 Azure 應用程式組態提供集中管理應用程式設定和功能旗標的解決方案。 如需詳細資訊,請參閱本章節

功能旗標

功能旗標是由兩個部分所組成,一個名稱和一份用來開啟功能的功能篩選清單。

功能篩選

功能篩選會定義何時應啟用功能的案例。 評估功能是否開啟或關閉時,會周遊其功能篩選清單,直到其中一個篩選條件決定應啟用功能為止。 此時,功能會被視為已啟用且周遊功能篩選會停止。 如果沒有功能篩選指出應該啟用功能,則會將其視為已停用。

例如,可以設計 Microsoft Edge 瀏覽器功能篩選。 只要 HTTP 要求來自 Microsoft Edge,此功能篩選就會啟用其所附加的任何功能。

功能旗標組態

在 JavaScript 中,開發人員通常會使用物件或對應作為主要資料結構來表示組態。 JavaScript 功能管理程式庫支援這兩種設定方法,讓開發人員有彈性地選擇最符合其需求的選項。 FeatureManager 可以使用內建 ConfigurationObjectFeatureFlagProviderConfigurationMapFeatureFlagProvider 讀取不同類型設定中的功能旗標。

const config = new Map([
    ["feature_management", {
        "feature_flags": [
            {
                "id": "FeatureT",
                "enabled": true
            },
            {
                "id": "FeatureU",
                "enabled": false
            }
        ]
    }],
    ["some other configuration", " some value"]
]);

import { ConfigurationMapFeatureFlagProvider, FeatureManager } from "@microsoft/feature-management";
const featureProvider = new ConfigurationMapFeatureFlagProvider(config);
const featureManager = new FeatureManager(featureProvider);

使用來自 Azure 應用程式組態的功能旗標

建議您不要將功能旗標程式碼寫入應用程式,而是將其保留在應用程式外部並個別管理。 這樣做可讓您隨時修改旗標狀態,並讓那些變更在應用程式中立即生效。 Azure 應用程式設定服務提供用於管理所有功能旗標的專用入口網站 UI。 請參閱教學課程

Azure 應用程式組態服務也會透過其 JavaScript 用戶端程式庫直接傳遞功能旗標給應用程式 @azure/app-configuration-provider。 下列範例示範如何使用程式庫。

應用程式組態 JavaScript 提供者會在 Map 物件中提供功能旗標。 內建 ConfigurationMapFeatureFlagProvider 有助於在此案例中載入功能旗標。

import { DefaultAzureCredential } from "@azure/identity";
import { load } from "@azure/app-configuration-provider";
import { ConfigurationMapFeatureFlagProvider, FeatureManager } from "@microsoft/feature-management";
const appConfig = await load("YOUR_APP-CONFIG-ENDPOINT",
                             new DefaultAzureCredential(), // For more information: https://learn.microsoft.com/javascript/api/overview/azure/identity-readme
                             { featureFlagOptions: { enabled: true } }); // load feature flags from Azure App Configuration service
const featureProvider = new ConfigurationMapFeatureFlagProvider(appConfig);
const featureManager = new FeatureManager(featureProvider);

使用 Azure 應用程式組態動態控制功能旗標的狀態

Azure 應用程式組態不僅是將功能旗標外部化儲存和集中式管理的解決方案,也可讓您動態開啟/關閉功能旗標。

若要啟用功能旗標的動態重新整理,您必須在從 Azure 應用程式組態載入功能旗標時,設定 refreshfeatureFlagOptions 屬性。

const appConfig = await load("YOUR_APP-CONFIG-ENDPOINT",  new DefaultAzureCredential(),  { 
    featureFlagOptions: { 
        enabled: true,
        refresh: {
            enabled: true, // enable the dynamic refresh for feature flags
            refreshIntervalInMs: 30_000
        }
    } 
});

const featureProvider = new ConfigurationMapFeatureFlagProvider(appConfig);
const featureManager = new FeatureManager(featureProvider);

您必須呼叫 refresh 方法來取得最新的功能旗標狀態。

await appConfig.refresh(); // Refresh to get the latest feature flags
const isBetaEnabled = await featureManager.isEnabled("Beta");
console.log(`Beta is enabled: ${isBetaEnabled}`);

附註

如需如何在功能管理程式庫使用 Azure 應用程式組態的詳細資訊,請移至快速入門

功能旗標宣告

下列範例顯示用來在 JSON 檔案中設定功能旗標的格式。

{
    "feature_management": {
        "feature_flags": [
            {
                "id": "FeatureT",
                "enabled": true
            },
            {
                "id": "FeatureU",
                "enabled": false
            },
            {
                "id": "FeatureV",
                "enabled": true,
                "conditions": {
                    "client_filters": [
                        {
                            "name": "Microsoft.TimeWindow",
                            "parameters": {
                                "Start": "Wed, 01 May 2019 13:59:59 GMT",
                                "End": "Mon, 01 Jul 2019 00:00:00 GMT"
                            }
                        }
                    ]
                }
            }
        ]
    }
}

feature_management 區段會由慣例用於載入功能旗標設定。 feature_flags 區段是載入至程式庫的功能旗標清單。 在上一節中,我們看到三個不同的功能。 功能會使用 client_filters 屬性 (而非 conditions) 來定義其功能篩選。 在 FeatureT 的功能篩選中,我們看到 enabledtrue 且未定義任何篩選,因而導致 FeatureT 一律傳回 trueFeatureUFeatureT 相同,但 enabledfalse,導致該功能一律傳回 falseFeatureV 指定名為 Microsoft.TimeWindow 的功能篩選。 FeatureV 是可設定功能篩選的範例。 我們可以在範例中看到篩選條件具有 parameters 屬性。 parameters 屬性可用來設定篩選。 在此情況下,會設定要成為作用中功能的開始和結束時間。

您可以在feature_management找到 區段的詳細結構描述。

進階:功能旗標名稱中禁止使用冒號 ':'。

需求類型

功能旗標的 requirement_type 屬性可用來判斷篩選條件在評估功能的狀態時,是否應該使用 AnyAll 邏輯。 如果未指定 requirement_type,則預設值為 Any

  • Any 表示只有一個篩選條件需要評估為 true,即可啟用此功能。
  • All 表示每個篩選條件都必須評估為 true,才能啟用此功能。

requirement_typeAll 會變更周遊。 首先,如果沒有篩選條件,則會停用此功能。 然後,功能篩選會周遊,直到其中一個篩選條件決定應該停用功能為止。 如果沒有篩選條件表示應該停用功能,系統會將其視為已啟用。

{
    "feature_management": {
        "feature_flags": [
            {
                "id": "FeatureW",
                "enabled": true,
                "conditions": {
                    "requirement_type": "All",
                    "client_filters": [
                        {
                            "name": "Microsoft.TimeWindow",
                            "parameters": {
                                "Start": "Wed, 01 May 2019 13:59:59 GMT",
                                "End": "Mon, 01 Jul 2019 00:00:00 GMT"
                            }
                        },
                        {
                            "name": "Percentage",
                            "parameters": {
                                "Value": "50"
                            }
                        }
                    ]
                }
            },
        ]
    }
}

在上述範例中,FeatureW 指定了 requirement_typeAll,這表示其所有篩選條件都必須評估為 true,才能啟用此功能。 在此情況下,此功能會在指定的時間範圍內針對 50% 的使用者啟用。

使用量

功能管理的基本形式是檢查功能旗標是否已啟用,然後根據結果執行動作。 檢查功能旗標的狀態會透過 FeatureManagerisEnabled 方法來完成。

import { ConfigurationMapFeatureFlagProvider, FeatureManager } from "@microsoft/feature-management";
const featureProvider = new ConfigurationMapFeatureFlagProvider(config);
const featureManager = new FeatureManager(featureProvider);

const isBetaEnabled = await featureManager.isEnabled("Beta");
if (isBetaEnabled) {
    // Do something
}

實作功能篩選

建立功能篩選可讓您根據您定義的準則來啟用功能。 若要實作功能篩選,必須實作 IFeatureFilter 介面。 IFeatureFilter 具有 name 屬性和名為 evaluate 的方法。 name 應用於組態,以參考特徵旗標中的功能篩選。 當功能指定其可以針對功能篩選啟用時,就會呼叫 evaluate 方法。 如果 evaluate 傳回 true,表示應該啟用功能。

interface IFeatureFilter {
    name: string;
    evaluate(context: IFeatureFilterEvaluationContext, appContext?: unknown): boolean | Promise<boolean>;
}

下列程式碼片段示範如何實作名稱為 MyCriteria 的自訂功能篩選。

    class MyCriteriaFilter {
        name = "MyCriteria";
        evaluate(context, appContext) {
            if (satisfyCriteria()) {
                return true;
            }
            else {
                return false;
            }
        }
    }

您需要在傳遞給customFilters建構函式的FeatureManagerOptions物件的FeatureManager屬性下註冊自定義篩選。

const featureManager = new FeatureManager(ffProvider, {
    customFilters: [
        new MyCriteriaFilter() // add custom feature filters under FeatureManagerOptions.customFilters
    ]
});

參數化功能篩選

某些功能篩選需要參數來決定是否應該開啟功能。 例如,瀏覽器功能篩選可能會開啟特定一組瀏覽器的功能。 可能需要 Edge 和 Chrome 瀏覽器啟用功能,而 Firefox 則不需要。 若要這樣做,功能篩選可以設計成預期參數。 這些參數會指定於功能組態,而在程式碼中可透過 IFeatureFilterEvaluationContextIFeatureFilter.Evaluate 參數來存取。

interface IFeatureFilterEvaluationContext {
    featureName: string;
    parameters?: unknown;
}

IFeatureFilterEvaluationContext 具有名為 parameters 的屬性。 這些參數代表功能篩選可用來決定是否應該啟用功能的原始組態。 若要再次使用瀏覽器功能篩選作為範例,篩選條件可使用 parameters 擷取一組針對功能指定的允許瀏覽器,然後檢查要求是否從其中一個瀏覽器傳送。

使用應用程式內容進行功能評估

功能篩選可能需要執行階段應用程式內容來評估功能旗標。 您可以在呼叫 isEnabled 時,將內容作為參數傳入。

featureManager.isEnabled("Beta", { userId : "Sam" })

功能篩選可以利用呼叫 isEnabled 時傳入的內容。 應用程式內容會當作 IFeatureFilter.Evaluate 的第二個參數傳入。

內建功能篩選

套件隨附 FeatureManagement 兩個功能篩選: TimeWindowFilterTargetingFilter。 建構 FeatureManager時,預設會新增所有內建功能篩選。

每個內建功能篩選都有自己的參數。 以下是功能篩選清單以及範例。

Microsoft.TimeWindow

此篩選提供根據時間範圍啟用功能的功能。 如果只指定了 End,則會在該時間之前將功能視為開啟。 如果只指定了 Start,則會在該時間之後的所有時間點將功能視為開啟。

"client_filters": [
    {
        "name": "Microsoft.TimeWindow",
        "parameters": {
            "Start": "Wed, 01 May 2019 13:59:59 GMT",
            "End": "Mon, 01 Jul 2019 00:00:00 GMT"
        }
    }
]     

時間範圍可以設定為定期重複。 這對於可能需要在一天或一周中某些日子的低流量或高流量期間打開功能的場景非常有用。 若要將個別時間範圍擴充至週期性時間範圍,應在參數中 Recurrence 指定週期規則。

附註

Start ,且 End 必須同時指定才能啟用 Recurrence

"client_filters": [
    {
        "name": "Microsoft.TimeWindow",
        "parameters": {
            "Start": "Fri, 22 Mar 2024 20:00:00 GMT",
            "End": "Sat, 23 Mar 2024 02:00:00 GMT",
            "Recurrence": {
                "Pattern": {
                    "Type": "Daily",
                    "Interval": 1
                },
                "Range": {
                    "Type": "NoEnd"
                }
            }
        }
    }
]

設定 Recurrence 由兩部分組成: Pattern (時間範圍重複的頻率)和 Range (週期性模式重複的時間長度)。

定期模式

有兩種可能的週期性模式類型: DailyWeekly。 例如,時間範圍可以重複「每天」、「每三天」、「每週一」或「每隔一個星期五」。

視型別而定,的 Pattern 某些欄位為必填、選用或忽略。

  • Daily

    每日週期模式會導致時間範圍根據每次發生之間的天數重複。

    屬性 相關性 描述
    Type 為必填項目 必須設定為 Daily
    間隔 可選 指定每次出現之間的天數。 預設值為 1。
  • Weekly

    每週定期模式會導致根據每組發生次數之間的週數,在一週的相同一天或幾天重複時間範圍。

    屬性 相關性 描述
    Type 為必填項目 必須設定為 Weekly
    一週的日子 為必填項目 指定事件在一週中的哪幾天發生。
    間隔 可選 指定每組發生次數之間的週數。 預設值為 1。
    星期的第一天 可選 指定哪一天被視為一週的第一天。 預設值為 Sunday

    下列範例每隔一個星期一和星期二重複時間範圍

    "Pattern": {
        "Type": "Weekly",
        "Interval": 2,
        "DaysOfWeek": ["Monday", "Tuesday"]
    }
    

附註

Start 必須是符合週期模式的有效第一次出現。 此外,時間範圍的持續時間不能超過其發生的頻率。 例如,每天重複 25 小時的時間範圍是無效的。

重複範圍

有三種可能的週期範圍類型: NoEndEndDateNumbered

  • NoEnd

    NoEnd 範圍會導致無限期地重複發生。

    屬性 相關性 描述
    Type 為必填項目 必須設定為 NoEnd
  • EndDate

    EndDate 範圍會導致時間範圍發生在符合適用模式的所有日期,直到結束日期為止。

    屬性 相關性 描述
    Type 為必填項目 必須設定為 EndDate
    EndDate 為必填項目 指定停止套用模式的日期時間。 只要最後一次出現的開始時間早於結束日期,就允許該出現項目的結束時間超出該日期。

    下列範例將每天重複時間範圍,直到最後一次發生在 2024 年 4 月 1 日為止。

    "Start": "Fri, 22 Mar 2024 18:00:00 GMT",
    "End": "Fri, 22 Mar 2024 20:00:00 GMT",
    "Recurrence":{
        "Pattern": {
            "Type": "Daily",
            "Interval": 1
        },
        "Range": {
            "Type": "EndDate",
            "EndDate": "Mon, 1 Apr 2024 20:00:00 GMT"
        }
    }
    
  • Numbered

    Numbered 範圍會導致時間窗口以固定次數出現(根據模式)。

    屬性 相關性 描述
    Type 為必填項目 必須設定為 Numbered
    出現次數 為必填項目 指定出現次數。

    下列範例會在星期一和星期二重複時間範圍,直到有三次出現,分別發生在 4 月 1 日 (星期一)、4 月 2 日 (星期二) 和 4 月 8 日 (星期一)。

    "Start": "Mon, 1 Apr 2024 18:00:00 GMT",
    "End": "Mon, 1 Apr 2024 20:00:00 GMT",
    "Recurrence":{
        "Pattern": {
            "Type": "Weekly",
            "Interval": 1,
            "DaysOfWeek": ["Monday", "Tuesday"]
        },
        "Range": {
            "Type": "Numbered",
            "NumberOfOccurrences": 3
        }
    }
    

若要建立週期規則,您必須同時指定 PatternRange。 任何模式類型都可以與任何範圍類型搭配使用。

進階: 屬性的 Start 時區偏移會套用至週期設定。

Microsoft.Targeting

此篩選提供為目標對象啟用功能的功能。 下列目標一節將提供目標設定的深入說明。 篩選參數包含 Audience 物件,描述使用者、群組、排除的使用者/群組,以及應該具有此功能存取權之使用者群的預設百分比。 Groups 區段中所列的每個群組物件也必須指定群組成員應具有存取權的百分比。 如果在 Exclusion 區段中指定了使用者,則無論直接或如果使用者位於排除的群組中,都會停用此功能。 否則,如果直接在 Users 區段中指定使用者,或使用者屬於任何群組推出的內含百分比,或如果使用者落入預設推出百分比,則該使用者就會啟用該功能。

"client_filters": [
    {
        "name": "Microsoft.Targeting",
        "parameters": {
            "Audience": {
                "Users": [
                    "Jeff",
                    "Alicia"
                ],
                "Groups": [
                    {
                        "Name": "Ring0",
                        "RolloutPercentage": 100
                    },
                    {
                        "Name": "Ring1",
                        "RolloutPercentage": 50
                    }
                ],
                "DefaultRolloutPercentage": 20,
                "Exclusion": {
                    "Users": [
                        "Ross"
                    ],
                    "Groups": [
                        "Ring2"
                    ]
                }
            }
        }
    }
]

目標

目標是功能管理策略,可讓開發人員逐漸向使用者群推出新功能。 此策略是建立在以一組稱為目標「對象」的使用者為目標的概念之上。 對象由特定使用者、群組、排除的使用者/群組和整個使用者群的指定百分比所組成。 對象中包含的群組可以進一步細分為其成員總數的百分比。

下列步驟示範新 'Beta' 功能的漸進式推出範例:

  1. 個別使用者 Jeff 和 Alicia 會被授與 Beta 的存取權。
  2. 另一位使用者 Mark 要求加入並包含在內。
  3. Beta 中包含 20% 稱為「Ring1」使用者的群組。
  4. Beta 中包含的「Ring1」使用者數目高達 100%。
  5. Beta 中包含 5% 的使用者群。
  6. 發行百分比高達 100%,且功能已完全推出。

此推出功能的策略是透過內含的 Microsoft.Targeting 功能篩選內建在程式庫中。

根據目標內容鎖定使用者

目標篩選條件依賴於目標內容來評估是否應該開啟功能。 此目標內容包含資訊,例如目前正在評估的使用者,以及使用者所在的群組。 呼叫 isEnabled 時,必須直接傳遞目標內容。

featureManager.isEnabled("Beta", { userId: "Aiden", groups: ["Ring1"] })

目標排除

定義對象時,可以從對象中排除使用者和群組。 向一組使用者推出功能時,排除非常有用,但需要從推出中排除少數使用者或群組。 排除是藉由將使用者和群組清單新增至對象的 Exclusion 屬性來定義。

"Audience": {
    "Users": [
        "Jeff",
        "Alicia"
    ],
    "Groups": [
        {
            "Name": "Ring0",
            "RolloutPercentage": 100
        }
    ],
    "DefaultRolloutPercentage": 0,
    "Exclusion": {
        "Users": [
            "Mark"
        ]
    }
}

在上述範例中,此功能會針對名為 JeffAlicia 的使用者啟用。 它也會針對名為 Ring0 的群組中的使用者啟用。 不過,如果使用者命名為 Mark,則不論使用者是否在群組 Ring0 中,都會停用此功能。 排除項目優先於目標篩選的其餘部分。

Web 應用程式中的目標

範例 專案中提供使用目標功能篩選的範例 Web 應用程式。

在 Web 應用程式中,特別是具有多個元件或層的 Web 應用程式,將目標內容 (userIdgroups) 傳遞至每個功能旗標檢查可能會變得繁瑣且重複。 這種情境稱為「環境定位情境」,其中應用程式內容中已經提供使用者身分識別資訊(例如會話數據或驗證內容),但必須能夠在整個應用程式中存取以進行功能管理評估。

ITargetingContextAccessor

程式庫會透過 ITargetingContextAccessor 模式提供解決方案。

interface ITargetingContext {
    userId?: string;
    groups?: string[];
}

interface ITargetingContextAccessor {
    getTargetingContext: () => ITargetingContext | undefined;
}

您可以提供一個函式,以了解如何從應用程式內容擷取目前使用者的目標資訊,而不是明確地傳遞每個 isEnabledgetVariant 呼叫的目標內容:

import { FeatureManager, ConfigurationObjectFeatureFlagProvider } from "@microsoft/feature-management";

// Create a targeting context accessor that uses your application's auth system
const targetingContextAccessor = {
    getTargetingContext: () => {
        // In a web application, this might access request context or session data
        // This is just an example - implement based on your application's architecture
        return {
            userId: getCurrentUserId(), // Your function to get current user
            groups: getUserGroups()     // Your function to get user groups
        };
    }
};

// Configure the feature manager with the accessor
const featureManager = new FeatureManager(featureProvider, {
    targetingContextAccessor: targetingContextAccessor
});

// Now you can call isEnabled without explicitly providing targeting context
// The feature manager will use the accessor to get the current user context
const isBetaEnabled = await featureManager.isEnabled("Beta");

此模式特別適用於伺服器端 Web 應用程式,該應用程式中用戶內容可能存在於請求範疇;同時也適用於用戶身分識別集中管理的用戶端應用程式。

針對請求上下文使用 AsyncLocalStorage

實作目標內容存取子模式時的一個常見挑戰是,在整個非同步呼叫鏈中維護要求內容。 在 Node.js Web 應用程式中,使用者身分識別資訊通常存在於要求物件中,但一旦進入異步操作,這些資訊將無法存取。

Node.js 提供來自AsyncLocalStorage模組的async_hooks以解決此問題。 它創建了一個可以在相同邏輯「上下文」中跨異步操作持續的存儲區,非常適合在整個請求生命週期中維持請求數據。

以下說明如何在快速應用程式中使用 AsyncLocalStorage 實作目標內容存取子:

import { AsyncLocalStorage } from "async_hooks";
import express from "express";

const requestAccessor = new AsyncLocalStorage();

const app = express();
// Middleware to store request context
app.use((req, res, next) => {
    // Store the request in AsyncLocalStorage for this request chain
    requestAccessor.run(req, () => {
        next();
    });
});

// Create targeting context accessor that retrieves user data from the current request
const targetingContextAccessor = {
    getTargetingContext: () => {
        // Get the current request from AsyncLocalStorage
        const request = requestAccesor.getStore();
        if (!request) {
            return undefined; // Return undefined if there's no current request
        }
        // Extract user data from request (from session, auth token, etc.)
        return {
            userId: request.user?.id,
            groups: request.user?.groups || []
        };
    }
};

變種

將新功能新增至應用程式時,總會發生功能有多個不同的建議設計選項的情況。 決定設計的常見解決方案是某種形式的 A/B 測試,其牽涉到將功能的不同版本提供給不同區塊的使用者群,並根據使用者互動來選擇版本。 在此程式庫中,此功能是藉由代表具有變體之功能的不同組態來啟用。

變體可讓功能旗標變成不只是簡單的開啟/關閉旗標。 變體代表功能旗標的值,可以是字串、數位、布林值,甚至是組態物件。 宣告變體的功能旗標應該在應使用每個變體的情況下定義,這會在配置變體一節中更詳細地說明。

取得具有目標內容的變體

針對每個功能,可以使用 FeatureManagergetVariant 方法來擷取變體。 變體指派取決於目前正在評估的使用者,而該資訊為從您傳入的目標內容上所取得的。 如果您已向 FeatureManager 註冊目標內容存取子,則目標內容會自動從中擷取。 但是,呼叫 getVariant 時,您仍然可以手動傳遞目標內容來覆寫它。

const variant = await featureManager.getVariant("MyVariantFeatureFlag", { userId: "Sam" });

const variantName = variant.name;
const variantConfiguration = variant.configuration;

// Do something with the resulting variant and its configuration

變體功能旗標宣告

相較於一般功能旗標,變體功能旗標多了兩個屬性:variantsallocationvariants 屬性是一個陣列,其中包含為這項功能定義的變體。 allocation 屬性會定義應該如何為功能配置這些變體。 就像宣告一般功能旗標一樣,您可以在 JSON 檔案中設定變體功能旗標。 以下是變體功能旗標的範例。

{
    "feature_management": {
        "feature_flags": [
            {
                "id": "MyVariantFeatureFlag",
                "enabled": true,
                "allocation": {
                    "default_when_enabled": "Small",
                    "group": [
                        {
                            "variant": "Big",
                            "groups": [
                                "Ring1"
                            ]
                        }
                    ]
                },
                "variants": [
                    { 
                        "name": "Big"
                    },  
                    { 
                        "name": "Small"
                    } 
                ]
            }
        ]
    }
}

定義變體

每個變體都有兩個屬性:名稱和組態。 此名稱是用來參考特定變體,而組態是該變體的值。 您可以使用 configuration_value 屬性來設定組態。 configuration_value 是可以是字串、數位、布林值或組態物件的內嵌組態。 如果未指定 configuration_value,所傳回變體的 configuration 屬性是 undefined

所有可能變體的清單都會針對 variants 屬性下的每個功能定義。

{
    "feature_management": {
        "feature_flags": [
            {
                "id": "MyVariantFeatureFlag",
                "variants": [
                    { 
                        "name": "Big", 
                        "configuration_value": {
                            "Size": 500
                        }
                    },  
                    { 
                        "name": "Small", 
                        "configuration_value": {
                            "Size": 300
                        }
                    } 
                ]
            }
        ]
    }
}

配置變體

配置功能變體的程序取決於功能的 allocation 屬性。

"allocation": { 
    "default_when_disabled": "Small",  
    "default_when_enabled": "Small", 
    "user": [ 
        { 
            "variant": "Big", 
            "users": [ 
                "Marsha" 
            ] 
        } 
    ], 
    "group": [ 
        { 
            "variant": "Big", 
            "groups": [ 
                "Ring1" 
            ] 
        } 
    ],
    "percentile": [ 
        { 
            "variant": "Big", 
            "from": 0, 
            "to": 10 
        } 
    ], 
    "seed": "13973240" 
},
"variants": [
    { 
        "name": "Big", 
        "configuration_value": "500px"
    },  
    { 
        "name": "Small", 
        "configuration_value": "300px"
    } 
]

功能的 allocation 設定具有下列屬性:

屬性 描述
default_when_disabled 指定當功能被視為停用且要求變體時,應該使用哪一個變體。
default_when_enabled 指定在功能視為已啟用時要求變體,且未將其他變體指派給使用者時,應該使用哪個變體。
user 指定變數和應為其指派該變體的使用者清單。
group 指定變體和群組清單。 如果使用者至少在其中一個群組內,則會指派變體。
percentile 指定變體和使用者計算百分比必須符合才能指派該變體的百分比範圍。
seed 計算 percentile 百分比依據的值。 如果使用相同的 seed 值,特定使用者的百分比計算在所有功能上都會相同。 如果未指定 seed,則會根據功能名稱建立預設種子。

如果未啟用此功能,功能管理員就會將標示為 default_when_disabled 的變體指派給目前使用者,在此案例中為 Small

如果啟用此功能,功能管理員將依該順序檢查 usergrouppercentile 配置,以指派變體。 在此特定範例中,如果評估的使用者名為 Marsha,則在名為 Ring1 的群組中,或使用者碰巧落在第 0 到 10 個百分位數之間,則會將指定的變異指派給使用者。 在此案例中,所有指派的使用者都會傳回 Big 變體。 如果這些配置都不相符,則會為使用者指派 default_when_enabled 變體,也就是 Small

配置邏輯與 Microsoft.Targeting 功能篩選類似,但目標中有一些參數不在配置中,反之亦然。 目標的結果與配置無關。

使用變體覆寫已啟用狀態

您可以使用變體來覆寫功能旗標的已啟用狀態。 覆寫可讓變體有機會延伸功能旗標的評估。 在具有變體的旗標上呼叫 is_enabled 時,功能管理員會檢查指派至目前使用者的變體是否已設定為覆寫結果。 覆寫會使用選擇性變體屬性 status_override 來完成。 根據預設,這個屬性會設定為 None,這表示變數不會影響旗標是否被視為已啟用或停用。 將 status_override 設定為 Enabled 可讓變數在選擇時覆寫要啟用的旗標。 將 status_override 設定為 Disabled 可提供相反的功能,因此會在選擇變體時停用旗標。 無法覆寫具有 enabledfalse 狀態的功能。

如果您使用具有二進位變體的功能旗標,則 status_override 屬性會很有用。 其可讓您繼續在應用程式中使用類似於 is_enabled 的 API,同時受益於變體隨附的新功能,例如,百分位數配置和種子。

{
    "id": "MyVariantFeatureFlag",
    "enabled": true,
    "allocation": {
        "percentile": [
            {
                "variant": "On",
                "from": 10,
                "to": 20
            }
        ],
        "default_when_enabled":  "Off",
        "seed": "Enhanced-Feature-Group"
    },
    "variants": [
        {
            "name": "On"
        },
        {
            "name": "Off",
            "status_override": "Disabled"
        }
    ]
}

在上述範例中,一律會啟用功能。 如果目前使用者位於 10 到 20 的計算百分位數範圍中,則會傳回 On 變體。 否則會傳回 Off 變體,因為 status_override 等於 Disabled,而功能現在會被視為已停用。

遙測

部署功能旗標變更時,分析其對應用程式的影響通常很重要。 例如,以下是一些可能發生的問題:

  • 我的旗標是否如預期般啟用/停用?
  • 目標使用者是否如預期般可存取特定功能?
  • 特定使用者會看到哪個變體?

這些類型的問題可透過功能旗標評估事件的發出和分析來回答。

啟用遙測

根據預設,功能旗標不會發出遙測。 若要發佈指定功能旗標的遙測,旗標「必須」宣告其已針對遙測發出啟用。

針對 JSON 中定義的功能旗標,啟用會使用 telemetry 屬性來完成。

{
    "feature_management": {
        "feature_flags": [
            {
                "id": "MyFeatureFlag",
                "enabled": true,
                "telemetry": {
                    "enabled": true
                }
            }
        ]
    }
}

上述程式碼片段會定義名為 MyFeatureFlag 的功能旗標且已針對遙測啟用。 telemetry 物件的 enabled 屬性會設定為 trueenabled 屬性的值必須是 true 才能發佈旗標的遙測。

功能旗標的 telemetry 區段具有下列屬性:

屬性 描述
enabled 指定是否應該發佈功能旗標的遙測。
metadata 模型化為字典的索引鍵/值組集合,可用來將功能旗標的相關自訂中繼資料附加至評估事件。

自訂遙測發佈

您可以在建立 onFeatureEvaluated 時註冊回 FeatureManager 回呼函數。 每當評估功能旗標並針對該旗標啟用遙測時,就會呼叫此回呼。 回呼函數會將功能評估結果當作參數。

下列範例示範如何實作自訂回呼函數,以使用從功能評估結果擷取的資訊傳送遙測,並將其註冊至功能管理員。

const sendTelemetry = (evaluationResult) => {
    const featureId = evaluationResult.feature.id;
    const featureEnabled = evaluationResult.enabled;
    const targetingId = evaluationResult.targetingId;
    const variantName = evaluationResult.variant?.name;
    const variantAssignmentReason = evaluationResult.variantAssignmentReason;
    // custom code to send the telemetry
    // ...
}
const featureManager = new FeatureManager(featureProvider, { onFeatureEvaluated :  sendTelemtry});

Application Insights 整合

JavaScript 功能管理程式庫提供與 Application Insights SDK 整合的延伸模組套件。

Application Insights 針對 WebNode.js 案例提供不同的 SDK。 請為您的應用程式選取正確的延伸模組套件。

如果您的應用程式在瀏覽器中執行,請安裝 "@microsoft/feature-management-applicationinsights-browser" 套件。 下列範例示範如何建立內建 Application Insights 遙測發行者,並將其註冊至功能管理員。

import { ApplicationInsights } from "@microsoft/applicationinsights-web"
import { FeatureManager, ConfigurationObjectFeatureFlagProvider } from "@microsoft/feature-management";
import { createTelemetryPublisher, trackEvent } from "@microsoft/feature-management-applicationinsights-browser";

const appInsights = new ApplicationInsights({ config: {
    connectionString: "<APPINSIGHTS_CONNECTION_STRING>"
}});
appInsights.loadAppInsights();

const publishTelemetry = createTelemetryPublisher(appInsights);
const provider = new ConfigurationObjectFeatureFlagProvider(jsonObject);
const featureManager = new FeatureManager(provider, {onFeatureEvaluated: publishTelemetry});

// FeatureEvaluation event will be emitted when a feature flag is evaluated
featureManager.getVariant("TestFeature", {userId : TARGETING_ID}).then((variant) => { /* do something*/ });

// Emit a custom event with targeting id attached.
trackEvent(appInsights, TARGETING_ID, {name: "TestEvent"}, {"Tag": "Some Value"});

當評估已啟用遙測的功能旗標時,遙測發行者會將 FeatureEvaluation 自訂事件傳送至 Application Insights。 自訂事件遵循 FeatureEvaluationEvent 架構。

定位遙測處理器

如果您已實 ITargetingContextAccessor作 ,您可以使用內建的 Application Insights 遙測處理器,藉由呼叫 createTargetingTelemetryProcessor 函式,自動將目標標識符資訊附加至所有遙測。

const appInsights = require("applicationinsights");
appInsights.setup(process.env.APPINSIGHTS_CONNECTION_STRING).start();

const { createTargetingTelemetryProcessor } = require("@microsoft/feature-management-applicationinsights-node");
appInsights.defaultClient.addTelemetryProcessor(
    createTargetingTelemetryProcessor(targetingContextAccessor)
);

這可確保傳送至 Application Insights 的每個遙測專案都包含使用者的目標標識符資訊(userId 和群組),讓您能夠將功能旗標使用方式與分析中的特定使用者或群組相互關聯。

如果您使用目標遙測處理器,而不是呼叫 trackEvent 功能管理套件所提供的方法,您可以直接從 Application Insights SDK 呼叫 trackEvent 方法。 目標識別碼資訊會自動附加至自訂事件遙測的 customDimensions

// Instead of calling trackEvent and passing the app insights client
// trackEvent(appInsights.defaultClient, "<TARGETING_ID>", {name: "TestEvent",  properties: {"Tag": "Some Value"}});

// directly call trackEvent method provided by App Insights SDK
appInsights.defaultClient.trackEvent({ name: "TestEvent" });

後續步驟

若要了解如何在應用程式中使用功能旗標,請繼續進行下列快速入門。

若要了解如何使用功能篩選,請繼續進行下列教學課程。