Udostępnij za pomocą


Zarządzanie funkcjami języka JavaScript

feature-management-npm-package

Biblioteka zarządzania funkcjami języka JavaScript umożliwia opracowywanie i uwidacznianie funkcji aplikacji na podstawie flag funkcji. Po utworzeniu nowej funkcji wiele aplikacji ma specjalne wymagania, takie jak kiedy funkcja powinna być włączona i pod jakimi warunkami. Ta biblioteka umożliwia zdefiniowanie tych relacji, a także integruje się z typowymi wzorcami kodu JavaScript, aby uwidocznić te funkcje.

Flagi funkcji umożliwiają aplikacjom JavaScript dynamiczne włączanie lub wyłączanie funkcji. Deweloperzy mogą używać flag funkcji w prostych przypadkach użycia, takich jak instrukcje warunkowe.

Poniżej przedstawiono niektóre korzyści wynikające z używania biblioteki zarządzania funkcjami języka JavaScript:

  • Wspólna konwencja zarządzania funkcjami
  • Niska bariera wejścia
    • Obsługuje zarówno obiekty JSON, jak i źródła flag funkcji oparte na mapie
    • Obsługuje użycie w środowiskach Node.js i przeglądarki
  • Zarządzanie cyklem życia flag funkcji przy użyciu Azure App Configuration
    • Wartości konfiguracji mogą ulec zmianie w czasie rzeczywistym
  • Scenariusze proste i złożone
    • Przełączanie/wyłączanie funkcji za pomocą deklaratywnego pliku konfiguracji
    • Dynamiczne ocenianie stanu funkcji na podstawie wywołania do serwera

Biblioteka zarządzania funkcjami języka JavaScript jest typu open source. Aby uzyskać więcej informacji, odwiedź repozytorium GitHub.

Uwaga

Zaleca się korzystanie z biblioteki zarządzania funkcjami razem z konfiguracją aplikacji Azure. aplikacja systemu Azure Configuration udostępnia rozwiązanie do centralnego zarządzania ustawieniami aplikacji i flagami funkcji. Aby uzyskać więcej informacji, zapoznaj się z tą sekcją.

Przełączniki funkcji

Flagi funkcji składają się z dwóch części, nazwy i listy filtrów funkcji, które są używane do włączania funkcji.

Filtry funkcji

Filtry funkcji definiują scenariusz włączania funkcji. Gdy funkcja jest oceniana pod kątem tego, czy jest włączona, czy wyłączona, jej lista filtrów funkcji jest przechodzina do momentu, aż jeden z filtrów zdecyduje, że funkcja powinna zostać włączona. W tym momencie funkcja jest uznawana za włączoną i zatrzymywane jest przeszukiwanie filtrów funkcji. Jeśli żaden filtr funkcji nie wskazuje, że funkcja powinna być włączona, jest uważana za wyłączoną.

Na przykład można zaprojektować filtr funkcji przeglądarki Microsoft Edge. Ten filtr funkcji aktywuje wszystkie dołączone do niego funkcje, o ile żądanie HTTP pochodzi z przeglądarki Microsoft Edge.

Konfiguracja flagi funkcji

W języku JavaScript deweloperzy często używają obiektów lub map jako podstawowych struktur danych do reprezentowania konfiguracji. Biblioteka zarządzania funkcjami języka JavaScript obsługuje obie metody konfiguracji, zapewniając deweloperom elastyczność wyboru opcji, która najlepiej odpowiada ich potrzebom. Komponent FeatureManager może odczytywać flagi funkcji z różnych typów konfiguracji przy użyciu wbudowanych elementów ConfigurationObjectFeatureFlagProvider i ConfigurationMapFeatureFlagProvider.

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);

Używanie flagi funkcjonalności z Konfiguracji Aplikacji Azure

Zamiast kodować flagi funkcji w aplikacji, zalecamy, aby flagi funkcji były przechowywane poza aplikacją i zarządzać nimi oddzielnie. Dzięki temu można w dowolnym momencie modyfikować stany flagi i od razu wprowadzać te zmiany w aplikacji. Usługa Azure App Configuration udostępnia dedykowany portalowy interfejs użytkownika do zarządzania wszystkimi flagami funkcji. Zobacz samouczek.

Usługa Azure App Configuration dostarcza również flagi funkcji bezpośrednio do aplikacji za pośrednictwem biblioteki klienta JavaScript @azure/app-configuration-provider. W poniższym przykładzie pokazano, jak używać biblioteki.

Dostawca JavaScript usługi App Configuration udostępnia flagi funkcji w obiekcie Map. Wbudowany element ConfigurationMapFeatureFlagProvider ułatwia ładowanie flag funkcji w tym przypadku.

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);

Używanie usługi Azure App Configuration do dynamicznego kontrolowania stanu flagi funkcji

Usługa Azure App Configuration to nie tylko rozwiązanie do zewnętrznego przechowywania i scentralizowanego zarządzania flagami funkcji, ale także umożliwia dynamiczne włączanie/wyłączanie flag funkcji.

Aby włączyć dynamiczne odświeżanie flag funkcji, należy skonfigurować właściwość refreshfeatureFlagOptions podczas ładowania flag funkcji z Azure App Configuration.

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);

Aby uzyskać najnowszy stan flagi funkcji, należy wywołać metodę refresh .

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

Uwaga

Aby uzyskać więcej informacji na temat korzystania z biblioteki zarządzania funkcjami w usłudze Azure App Configuration, przejdź do szybkiego startu.

Deklaracja przełącznika funkcji

W poniższym przykładzie pokazano format używany do konfigurowania flag funkcji w pliku 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"
                            }
                        }
                    ]
                }
            }
        ]
    }
}

Sekcja feature_management jest używana zgodnie z konwencją do ładowania ustawień flag funkcji. Sekcja feature_flags to lista flag funkcji załadowanych do biblioteki. W powyższej sekcji przedstawiono trzy różne funkcje. Cechy definiują swoje filtry za pomocą właściwości client_filters, w ramach conditions. W filtrach funkcji dla FeatureT widzimy, że enabled jest true bez żadnych zdefiniowanych filtrów, co powoduje, że FeatureT zawsze zwraca true. FeatureU jest tym samym co FeatureT, z tym że enabled jest false, co powoduje, że funkcja zawsze zwraca false. FeatureV określa filtr funkcji o nazwie Microsoft.TimeWindow. FeatureV to przykład konfigurowalnego filtru funkcji. Możemy zobaczyć na przykładzie, że filtr ma parameters właściwość. Właściwość parameters służy do konfigurowania filtru. W takim przypadku konfigurowane są czasy rozpoczęcia i zakończenia dla funkcji, która ma być aktywna.

Szczegółowy schemat feature_management sekcji można znaleźć tutaj.

Zaawansowane: Użycie dwukropka ":" jest zabronione w nazwach flag funkcji.

Typ wymagania

Właściwość requirement_type flagi funkcji służy do określania, czy filtry powinny stosować Any czy All logiki podczas oceniania stanu funkcji. Jeśli requirement_type nie zostanie określony, wartość domyślna to Any.

  • Any oznacza, że tylko jeden filtr musi mieć wartość true, aby funkcja została włączona.
  • All oznacza, że każdy filtr musi mieć wartość true, aby funkcja została włączona.

Zmiana requirement_type w All zmienia sposób przechodzenia. Po pierwsze, jeśli nie ma filtrów, funkcja jest wyłączona. Następnie filtry funkcji są przechodzine do momentu, aż jeden z filtrów zdecyduje, że funkcja powinna zostać wyłączona. Jeśli żaden filtr nie wskazuje, że funkcja powinna być wyłączona, jest uważana za włączoną.

{
    "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"
                            }
                        }
                    ]
                }
            },
        ]
    }
}

W powyższym przykładzie FeatureW określa requirement_typeAll, co oznacza, że wszystkie jego filtry muszą mieć wartość true, aby funkcja została włączona. W takim przypadku funkcja jest włączona dla 50% użytkowników w określonym przedziale czasu.

Zużycie

Podstawową formą zarządzania funkcjami jest sprawdzenie, czy flaga funkcji jest włączona, a następnie wykonuje akcje na podstawie wyniku. Sprawdzanie stanu flagi funkcji odbywa się za pomocą metody 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
}

Implementowanie filtru funkcji

Tworzenie filtru funkcji umożliwia włączanie funkcji na podstawie zdefiniowanych kryteriów. Aby zaimplementować filtr cech, trzeba zaimplementować interfejs IFeatureFilter. IFeatureFilter name ma właściwość i metodę o nazwie evaluate. Element name powinien być używany w konfiguracji do odwołowania się do filtru funkcji w ramach flagi funkcji. Kiedy funkcja wskazuje, że można ją włączyć jako filtr funkcji, wywoływana jest metoda evaluate. Jeśli evaluate zwraca wartość true, oznacza to, że funkcja powinna być włączona.

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

Poniższy fragment kodu pokazuje, jak zaimplementować dostosowany filtr funkcji o nazwie MyCriteria.

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

Należy zarejestrować filtr niestandardowy w ramach właściwości customFilters obiektu FeatureManagerOptions przekazanego do konstruktora FeatureManager.

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

Filtry funkcji sparametryzowanych

Niektóre filtry funkcji wymagają parametrów, aby zdecydować, czy funkcja powinna być włączona, czy nie. Na przykład filtr funkcji przeglądarki może włączyć funkcję dla określonego zestawu przeglądarek. Może być pożądane, aby przeglądarki Edge i Chrome włączały funkcję, a Przeglądarka Firefox nie. W tym celu można zaprojektować filtr funkcji, aby oczekiwać parametrów. Te parametry byłyby określone w konfiguracji funkcji, a w kodzie byłyby dostępne za pośrednictwem parametru IFeatureFilterEvaluationContextIFeatureFilter.Evaluate.

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

IFeatureFilterEvaluationContext ma właściwość o nazwie parameters. Te parametry reprezentują konfigurację nieprzetworzonej, której filtr funkcji może użyć, aby zdecydować, jak ocenić, czy funkcja powinna być włączona, czy nie. Aby ponownie użyć filtru funkcji przeglądarki jako przykładu, filtr może użyć parameters do wyodrębnienia zestawu dozwolonych przeglądarek, które zostaną określone dla tej funkcji, a następnie sprawdź, czy żądanie jest wysyłane z jednej z tych przeglądarek.

Używanie kontekstu aplikacji do oceny funkcji

Filtr funkcji może wymagać kontekstu aplikacji środowiska uruchomieniowego, aby ocenić flagę funkcji. Kontekst można przekazać jako parametr podczas wywoływania metody isEnabled.

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

Filtr funkcji może korzystać z kontekstu, który jest przekazywany, gdy isEnabled jest wywoływany. Kontekst aplikacji zostanie przekazany jako drugi parametr IFeatureFilter.Evaluate.

Filtry funkcji wbudowanych

Istnieją dwa filtry funkcji, które są dostarczane z pakietem FeatureManagement : TimeWindowFilter i TargetingFilter. Wszystkie wbudowane filtry funkcjonalności zostaną domyślnie dodane podczas konstruowania FeatureManagerelementu.

Każdy z wbudowanych filtrów funkcji ma własne parametry. Oto lista filtrów funkcji wraz z przykładami.

Microsoft.TimeWindow

Ten filtr zapewnia możliwość włączenia funkcji na podstawie przedziału czasu. Jeśli tylko End zostaną określone, funkcja jest traktowana jako włączona do tego czasu. Jeśli zostanie określony tylko Start, funkcja jest uwzględniana we wszystkich punktach po tym czasie.

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

Przedział czasu można skonfigurować do okresowego powtarzania. Może to być przydatne w scenariuszach, w których może być konieczne włączenie funkcji w okresie niskiego lub dużego ruchu w ciągu dnia lub w określonych dniach tygodnia. Aby rozwinąć poszczególne przedziały czasu do okresów cyklicznych, reguła cyklu powinna być określona w parametrze Recurrence .

Uwaga

Start i End muszą być określone, aby włączyć 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"
                }
            }
        }
    }
]

Ustawienia Recurrence składają się z dwóch części: Pattern (jak często powtarza się przedział czasu) i Range (jak długo powtarza się wzorzec cyklu).

Wzorzec cyklu

Istnieją dwa możliwe typy wzorców cyklu: Daily i Weekly. Na przykład przedział czasu może powtarzać "codziennie", "co trzy dni", "każdy poniedziałek" lub "co drugi piątek".

W zależności od typu niektóre pola Pattern są wymagane, opcjonalne lub ignorowane.

  • Daily

    Wzorzec cyklu dziennego powoduje powtarzanie przedziału czasu na podstawie liczby dni między poszczególnymi wystąpieniami.

    Własność Znaczenie opis
    Typ Wymagane Musi być ustawione na Daily.
    Interwał Opcjonalnie Określa liczbę dni między poszczególnymi wystąpieniami. Wartość domyślna to 1.
  • Weekly

    Wzorzec cyklu tygodniowego powoduje powtórzenie przedziału czasu w tym samym dniu lub dniach tygodnia na podstawie liczby tygodni między poszczególnymi zestawami wystąpień.

    Własność Znaczenie opis
    Typ Wymagane Musi być ustawione na Weekly.
    DaysOfWeek Wymagane Określa dni tygodnia, w których występuje zdarzenie.
    Interwał Opcjonalnie Określa liczbę tygodni między poszczególnymi zestawami wystąpień. Wartość domyślna to 1.
    FirstDayOfWeek Opcjonalnie Określa, który dzień jest uważany za pierwszy dzień tygodnia. Wartość domyślna to Sunday.

    Poniższy przykład powtarza przedział czasu co drugi poniedziałek i wtorek

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

Uwaga

Start musi być prawidłowym pierwszym wystąpieniem, które pasuje do wzorca cyklu. Ponadto czas trwania przedziału czasu nie może być dłuższy niż częstotliwość jego wystąpienia. Na przykład jest nieprawidłowe, aby codziennie powtarzać 25-godzinne okno czasu.

Zakres powtarzania

Istnieją trzy możliwe typy zakresów cykli: NoEnd, EndDate i Numbered.

  • NoEnd

    Zakres NoEnd powoduje, że cykl występuje w nieskończoność.

    Własność Znaczenie opis
    Typ Wymagane Musi być ustawione na NoEnd.
  • EndDate

    Zakres EndDate powoduje, że przedział czasowy występuje we wszystkie dni zgodne z odpowiednim wzorcem aż do daty zakończenia.

    Własność Znaczenie opis
    Typ Wymagane Musi być ustawione na EndDate.
    Data końcowa Wymagane Określa datę zakończenia stosowania wzorca. O ile godzina rozpoczęcia ostatniego wystąpienia spadnie przed datą zakończenia, czas zakończenia tego wystąpienia może wykraczać poza nią.

    Poniższy przykład będzie powtarzał przedział czasu każdego dnia do czasu ostatniego wystąpienia 1 kwietnia 2024 r.

    "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

    Zakres Numbered powoduje, że przedział czasu występuje stałą liczbę razy (na podstawie wzorca).

    Własność Znaczenie opis
    Typ Wymagane Musi być ustawione na Numbered.
    LiczbaWystąpień Wymagane Określa liczbę wystąpień.

    Poniższy przykład powtórzy okno czasowe w poniedziałek i wtorek, aż do trzech wystąpień, które mają miejsce 1 kwietnia (pon), 2 kwietnia (wt) i 8 kwietnia (pon).

    "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
        }
    }
    

Aby utworzyć regułę powtarzalności, należy określić zarówno Pattern, jak i Range. Dowolny typ wzorca może pracować z dowolnym typem zakresu.

Zaawansowany: Przesunięcie strefy czasowej właściwości Start jest stosowane do ustawień powtarzania.

Microsoft.Targeting

Ten filtr zapewnia możliwość włączenia funkcji dla odbiorców docelowych. Szczegółowe wyjaśnienie określania wartości docelowej zostało wyjaśnione w poniższej sekcji określania wartości docelowej . Parametry filtru obejmują obiekt opisujący Audience użytkowników, grupy, wykluczonych użytkowników/grup oraz domyślny procent bazy użytkowników, który powinien mieć dostęp do funkcji. Każdy obiekt grupy wymieniony w Groups sekcji musi również określić, jaki procent członków grupy powinien mieć dostęp. Jeśli użytkownik jest określony w Exclusion sekcji , bezpośrednio lub jeśli użytkownik znajduje się w wykluczonej grupie, funkcja jest wyłączona. W przeciwnym razie, jeśli użytkownik jest określony bezpośrednio w sekcji Users, lub jeśli użytkownik jest wliczony w procent uwzględniony w dowolnym wdrożeniu grupy, lub jeśli użytkownik mieści się w domyślnym procencie wdrożenia, ten użytkownik będzie miał włączoną funkcję.

"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"
                    ]
                }
            }
        }
    }
]

Celowanie

Określanie wartości docelowej to strategia zarządzania funkcjami, która umożliwia deweloperom stopniowe wdrażanie nowych funkcji w bazie użytkowników. Strategia jest oparta na koncepcji określania celu grupy użytkowników znanej jako docelowa grupa odbiorców. Grupa odbiorców składa się z określonych użytkowników, grup, wykluczonych użytkowników/grup oraz wyznaczonego procentu całej bazy użytkowników. Grupy, które są uwzględnione w grupie odbiorców, można podzielić dalej na wartości procentowe ich całkowitej liczby członków.

W poniższych krokach przedstawiono przykład progresywnego wdrożenia nowej funkcji "Beta":

  1. Indywidualni użytkownicy Jeff i Alicia otrzymują dostęp do wersji beta.
  2. Inny użytkownik, Mark, prosi o zapisanie się i jest uwzględniony.
  3. Dwadzieścia procent grupy znanej jako "Ring1" użytkowników jest uwzględnionych w wersji beta.
  4. Liczba użytkowników "Ring1" uwzględnionych w wersji beta wzrosła do 100 procent.
  5. Pięć procent bazy użytkowników jest uwzględnionych w wersji beta.
  6. Procent wdrożenia jest zwiększony do 100 procent, a funkcja jest całkowicie wdrożona.

Ta strategia wdrażania funkcji jest wbudowana w bibliotekę za pomocą dołączonego filtru funkcji Microsoft.Targeting .

Ukierunkowanie użytkownika z kontekstem targetowania

Filtr selekcji opiera się na kontekście selekcji, aby ocenić, czy funkcja powinna być włączona. Ten kontekst targetowania zawiera informacje, takie jak użytkownik, który jest aktualnie oceniany, oraz grupy, do których należy użytkownik. Kontekst docelowy musi być przekazywany bezpośrednio, gdy isEnabled jest wywoływany.

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

Wykluczanie celów targetowania

Podczas definiowania odbiorców użytkownicy i grupy mogą zostać wykluczeni z odbiorców. Wykluczenia są przydatne, gdy funkcja jest wdrażana w grupie użytkowników, ale kilka użytkowników lub grup musi zostać wykluczonych z wdrożenia. Wykluczenie jest definiowane przez dodanie listy użytkowników i grup do Exclusion właściwości odbiorców.

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

W powyższym przykładzie funkcja jest włączona dla użytkowników o nazwach Jeff i Alicia. Jest ona również włączona dla użytkowników w grupie o nazwie Ring0. Jeśli jednak użytkownik ma nazwę Mark, funkcja jest wyłączona, niezależnie od tego, czy znajdują się w grupie Ring0 , czy nie. Wykluczenia mają priorytet nad resztą filtru określania wartości docelowej.

Określanie wartości docelowej w aplikacji internetowej

Przykładowa aplikacja internetowa korzystająca z filtru funkcji określania wartości docelowej jest dostępna w tym przykładowym projekcie.

W aplikacjach internetowych, zwłaszcza tych z wieloma składnikami lub warstwami, przekazywanie kontekstu docelowego (userId i groups) do każdego sprawdzenia flagi funkcji może stać się kłopotliwe i powtarzalne. Ten scenariusz jest określany jako "kontekst docelowy otoczenia", w którym informacje o tożsamości użytkownika są już dostępne w kontekście aplikacji (na przykład w danych sesji lub kontekście uwierzytelniania), ale muszą być dostępne dla ocen zarządzania funkcjami w całej aplikacji.

Dostęp do kontekstu targetowania

Biblioteka udostępnia rozwiązanie poprzez wzorzec ITargetingContextAccessor.

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

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

Zamiast jawnie przekazywać kontekst targetowania przy każdym wywołaniu isEnabled lub getVariant, możesz podać funkcję, która rozumie, jak pobrać informacje o targetowaniu bieżącego użytkownika z kontekstu Twojej aplikacji.

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");

Ten wzorzec jest szczególnie przydatny w aplikacjach internetowych po stronie serwera, w których kontekst użytkownika może być dostępny w zakresie żądania lub w aplikacjach klienckich, w których tożsamość użytkownika jest zarządzana centralnie.

Używanie AsyncLocalStorage dla kontekstu żądania

Jednym z typowych wyzwań podczas implementacji wzorca dostępu do kontekstu docelowego jest utrzymanie kontekstu żądania w asynchronicznym łańcuchu wywołań. W Node.js aplikacjach internetowych informacje o tożsamości użytkownika są zwykle dostępne w obiekcie żądania, ale stają się niedostępne po wprowadzeniu operacji asynchronicznych.

Node.js zapewnia AsyncLocalStorage z modułu async_hooks, aby rozwiązać ten problem. Tworzy magazyn, który utrzymuje się podczas operacji asynchronicznych w tym samym logicznym "kontekście" — idealnym do zachowywania danych w całym procesie obsługi żądania.

Oto jak zaimplementować dostęp do kontekstu docelowego przy użyciu AsyncLocalStorage w aplikacji Express:

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 || []
        };
    }
};

Warianty

Po dodaniu nowych funkcji do aplikacji może dojść do czasu, gdy funkcja ma wiele różnych proponowanych opcji projektowania. Typowym rozwiązaniem do podejmowania decyzji o projekcie jest pewna forma testowania A/B, która polega na udostępnieniu innej wersji funkcji różnym segmentom bazy użytkowników i wybraniu wersji na podstawie interakcji użytkownika. W tej bibliotece ta funkcja jest włączona przez reprezentowanie różnych konfiguracji funkcji z wariantami.

Warianty przekształcają flagę funkcji w coś więcej niż prostą flagę włącz/wyłącz. Wariant reprezentuje wartość flagi funkcji, która może być ciągiem, liczbą, wartością logiczną, a nawet obiektem konfiguracji. Flaga funkcji, która deklaruje warianty, powinna określać, w jakich okolicznościach należy używać każdego wariantu, co zostało szczegółowo omówione w sekcji Przydzielanie wariantów .

Pobieranie wariantu z kontekstem celu

Dla każdej cechy, wariant można pobrać za pomocą metody FeatureManagergetVariant. Przypisanie wariantu zależy od użytkownika obecnie ocenianego, a informacje te są uzyskiwane z przekazanego kontekstu celowania. Jeśli zarejestrowano dostęp do kontekstu docelowego w FeatureManager, kontekst docelowy zostanie automatycznie pobrany z tego elementu. Nadal można go jednak zastąpić, ręcznie przekazując kontekst określania wartości docelowej podczas wywoływania elementu 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

Deklaracja flagi wariantu функции

W porównaniu z flagami funkcji normalnych flagi funkcji wariantu mają jeszcze dwie właściwości: variants i allocation. Właściwość variants jest tablicą zawierającą warianty zdefiniowane dla tej funkcji. Właściwość allocation definiuje sposób przydzielania tych wariantów dla funkcji. Podobnie jak deklarowanie flag funkcji normalnych, można skonfigurować flagi funkcji wariantu w pliku JSON. Oto przykład flagi funkcji wariantowej.

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

Definiowanie wariantów

Każdy wariant ma dwie właściwości: nazwę i konfigurację. Nazwa jest używana do odwoływania się do określonego wariantu, a konfiguracja jest wartością tego wariantu. Konfigurację można ustawić przy użyciu configuration_value właściwości . configuration_value jest konfiguracją śródliniową, która może być ciągiem, liczbą, wartością logiczną lub obiektem konfiguracji. Jeśli configuration_value nie zostanie określony, zwrócona właściwość wariantu configuration to undefined.

Lista wszystkich możliwych wariantów jest zdefiniowana dla każdej cechy we właściwości variants.

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

Przydzielanie wariantów

Proces przydzielania wariantów funkcji zależy od allocation właściwości funkcji.

"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"
    } 
]

Ustawienie allocation funkcji ma następujące właściwości:

Własność opis
default_when_disabled Wskazuje, który wariant powinien być używany, gdy wariant jest wymagany, a funkcja jest wyłączona.
default_when_enabled Określa, który wariant ma być używany, gdy jest wymagany wariant, gdy funkcja jest uznawana za włączoną i żaden inny wariant nie został przypisany do użytkownika.
user Określa wariant i listę użytkowników, do których należy przypisać ten wariant.
group Określa wariant i listę grup. Wariant jest przypisywany, jeśli użytkownik znajduje się w co najmniej jednej grupie.
percentile Określa wariant i zakres procentowy, do którego ma zostać przypisana wartość procentowa obliczona przez użytkownika.
seed Wartość, na podstawie której obliczane są procenty dla percentile. Obliczanie procentowe dla określonego użytkownika będzie takie samo we wszystkich funkcjach, jeśli jest używana ta sama seed wartość. Jeśli seed nie jest określony, zostanie utworzone domyślne ziarno na podstawie nazwy funkcji.

Jeśli funkcja nie jest włączona, menedżer funkcji przypisuje wariant oznaczony jako default_when_disabled do bieżącego użytkownika, który jest Small w tym przypadku.

Jeśli funkcja jest włączona, menedżer funkcji sprawdza alokacje user, group i percentile w tej kolejności, aby przypisać wariant. W tym konkretnym przykładzie, jeśli oceniany użytkownik ma nazwę Marsha, znajduje się w grupie o nazwie Ring1, lub użytkownik znajduje się między 0 a 10. percentylem, określony wariant zostanie przypisany do użytkownika. W takim przypadku wszyscy przypisani użytkownicy zwróciliby wariant Big. Jeśli żadna z tych alokacji nie pasuje, użytkownikowi przypisywany jest wariant default_when_enabled, który jest Small.

Logika alokacji jest podobna do filtru funkcji Microsoft.Targeting, ale istnieją pewne parametry, które znajdują się w kierowaniu, które nie występują w alokacji i odwrotnie. Wyniki określania wartości docelowej i alokacji nie są powiązane.

Zastępowanie stanu włączonego z wariantem

Można użyć wariantów, aby zastąpić stan włączenia flagi funkcji. Zastępowanie daje wariantom możliwość rozszerzenia oceny flagi funkcjonalności. Podczas wywoływania is_enabled flagi z wariantami menedżer funkcji sprawdzi, czy wariant przypisany do bieżącego użytkownika jest skonfigurowany do zastąpienia wyniku. Zastępowanie odbywa się przy użyciu opcjonalnej właściwości wariantu status_override. Domyślnie ta właściwość jest ustawiona na None, co oznacza, że wariant nie ma wpływu na to, czy flaga jest uznawana za włączoną, czy wyłączoną. Ustawienie status_override na Enabled pozwala wybranemu wariantowi na przesłonięcie flagi, która ma zostać włączona. Ustawienie status_override na Disabled powoduje przeciwną funkcjonalność, dlatego flaga jest wyłączana po wybraniu wariantu. Nie można nadpisać funkcji, która ma stan enabledfalse.

Jeśli używasz flagi funkcji z wariantami binarnymi, właściwość status_override może być przydatna. Umożliwia to kontynuowanie korzystania z interfejsów API, takich jak is_enabled w aplikacji, a jednocześnie korzystanie z nowych funkcji, które towarzyszą wariantom, takich jak alokacja percentylu i seed.

{
    "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"
        }
    ]
}

W powyższym przykładzie funkcja jest zawsze włączona. Jeśli bieżący użytkownik znajduje się w obliczonym zakresie percentylu od 10 do 20, zwracany jest wariant On. W przeciwnym razie, zwracany jest wariant Off, a ponieważ status_override jest równy Disabled, funkcja będzie teraz uznana za wyłączoną.

Telemetria

Po wdrożeniu zmiany flagi funkcji często ważne jest analizowanie jej wpływu na aplikację. Oto na przykład kilka pytań, które mogą wystąpić:

  • Czy moje flagi są włączone/wyłączone zgodnie z oczekiwaniami?
  • Czy docelowi użytkownicy uzyskują dostęp do określonej funkcji zgodnie z oczekiwaniami?
  • Który wariant jest widoczny dla określonego użytkownika?

Odpowiedzi na te typy pytań można uzyskać za pośrednictwem emisji i analizy zdarzeń związanych z oceną flag funkcji.

Włączanie telemetrii

Domyślnie flagi funkcji nie emitują danych telemetrycznych. Aby opublikować dane telemetryczne dla danej flagi funkcji, flaga MUSI zadeklarować, że jest włączona do emisji telemetrii.

W przypadku flag funkcji zdefiniowanych w formacie json włączenie odbywa się przy użyciu telemetry właściwości .

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

Powyższy fragment kodu definiuje flagę funkcji o nazwie MyFeatureFlag , która jest włączona dla telemetrii. Właściwość obiektu telemetry jest ustawiona na enabledtrue. Wartość enabled właściwości musi być true aby opublikować telemetrię dla flagi.

Sekcja telemetry flagi funkcji ma następujące właściwości:

Własność opis
enabled Określa, czy dane telemetryczne mają być publikowane dla flagi funkcji.
metadata Kolekcja par klucz-wartość, modelowana jako słownik, która może być używana do dołączania niestandardowych metadanych dotyczących flagi funkcji do zdarzeń ewaluacyjnych.

Publikowanie niestandardowych danych telemetrycznych

Funkcję wywołania zwrotnego onFeatureEvaluated można zarejestrować podczas tworzenia FeatureManager. To wywołanie zwrotne jest wywoływane za każdym razem, gdy flaga funkcji jest oceniana, a dane telemetryczne są włączone dla tej flagi. Funkcja wywołania zwrotnego pobiera wynik oceny funkcji jako parametr .

W poniższym przykładzie pokazano, jak zaimplementować niestandardową funkcję wywołania zwrotnego w celu wysyłania danych telemetrycznych przy użyciu informacji wyodrębnionych z wyniku oceny funkcji i zarejestrowania jej w menedżerze funkcji.

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});

Integracja z usługą Application Insights

Biblioteka zarządzania funkcjami języka JavaScript udostępnia pakiety rozszerzeń zintegrowane z zestawami SDK usługi Application Insights .

Usługa Application Insights oferuje różne zestawy SDK dla scenariuszy internetowych i Node.js . Wybierz odpowiednie pakiety rozszerzeń dla aplikacji.

Jeśli aplikacja działa w przeglądarce, zainstaluj "@microsoft/feature-management-applicationinsights-browser" pakiet. W poniższym przykładzie pokazano, jak utworzyć wbudowanego wydawcę telemetrii usługi Application Insights i zarejestrować go w menedżerze funkcji.

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"});

Wydawca telemetrii wysyła FeatureEvaluation zdarzenia niestandardowe do Application Insights, gdy flaga funkcji z telemetrią zostanie oceniona. Zdarzenie niestandardowe odpowiada schematowi FeatureEvaluationEvent.

Określanie celu procesora telemetrii

Jeśli zaimplementowałeś ITargetingContextAccessor, możesz użyć wbudowanego procesora telemetrii Application Insights, aby automatycznie dołączyć informacje o identyfikatorze kierowania do całej telemetrii, wywołując funkcję 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)
);

Dzięki temu każdy element telemetrii wysyłany do usługi Application Insights zawiera informacje o identyfikatorze użytkownika docelowego (identyfikator użytkownika i grupy), co umożliwia skorelowanie użycia flag funkcji z określonymi użytkownikami lub grupami w analizach.

Jeśli używasz docelowego procesora telemetrii, zamiast wywoływać metodę dostarczoną przez pakiet zarządzania funkcjami, możesz bezpośrednio wywołać trackEventtrackEvent metodę z zestawu SDK usługi Application Insights. Informacje o identyfikatorze określania wartości docelowej zostaną automatycznie dołączone do telemetrycznych danych customDimensions zdarzenia niestandardowego.

// 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" });

Następne kroki

Aby dowiedzieć się, jak używać flag funkcji w aplikacjach, przejdź do następujących szybkich przewodników.

Aby dowiedzieć się, jak używać filtrów funkcji, przejdź do następujących samouczków.