שימוש בדגלי תכונות של App Lifecycle Manager עם Java

במדריך הזה מוסבר איך לשלב את האפליקציות שלכם ב-Java עם דגלי התכונות של App Lifecycle Manager. במאמר הזה נסביר איך להשתמש ב-OpenFeature SDK עם ספק flagd כדי להעריך דגלים שמנוהלים על ידי App Lifecycle Manager. כך תוכלו לשלוט באופן דינמי בזמינות של תכונות ובהתנהגות שלהן בשירותי Java.

במדריך הזה אנחנו יוצאים מנקודת הנחה שכבר הגדרתם את המשאבים הדרושים ב-App Lifecycle Manager (כמו מוצרי SaaS, סוגי יחידות, יחידות, דגלים והשקות) על ידי השלמת אחד מהמדריכים הבאים להפעלה מהירה:

דרישות מוקדמות

לפני שמתחילים, חשוב לוודא שיש לכם:

  1. ‫Java installed: JDK 17 or later.
  2. השלמתם את המדריך למתחילים בנושא דגלים של תכונות ב-App Lifecycle Manager:
    • השלמתם בהצלחה את ההתחלה המהירה של דגלי התכונות המשולבים או של דגלי התכונות העצמאיים כדי להקצות את יחידת היעד.
    • צריכים להיות לכם משתני סביבה או ערכים מהמדריך לתחילת העבודה, כמו PROJECT_ID,‏ LOCATION_1 (האזור של היחידה שלכם), UNIT_ID ו-FLAG_KEY.
  3. מאומת gcloud עבור Application Default Credentials ‏ (ADC): אפליקציית Java משתמשת ב-ADC כדי לבצע אימות לשירותי Google Cloud . מוודאים שביצעתם אימות בסביבה שלכם:

    gcloud auth application-default login
    
  4. הרשאות IAM: לזהות שמריצה את אפליקציית Java צריך להיות תפקיד roles/saasconfig.viewer בממשק לניהול זהויות והרשאות גישה (IAM) בפרויקט Google Cloud כדי לקרוא את ההגדרות של הדגלים:

    gcloud projects add-iam-policy-binding YOUR_PROJECT_ID \
        --member="user:YOUR_EMAIL_ADDRESS" \
        --role="roles/saasconfig.viewer"
    

    מחליפים את YOUR_PROJECT_ID ואת YOUR_EMAIL_ADDRESS בהתאם.

הסבר על משתני סביבה מרכזיים

אפליקציית Java שלכם מסתמכת על משתני סביבה כדי להתחבר להגדרת הדגל הנכונה.

  • FLAGD_SOURCE_PROVIDER_ID: מציין איזו הגדרה של feature flag צריך לאחזר משירות App Lifecycle Manager. זה צריך להיות שם המשאב המלא של FeatureFlagConfig שמשויך ליחידה.
    • פורמט: projects/PROJECT_ID/locations/LOCATION/featureFlagsConfigs/UNIT_ID
    • דוגמה: projects/my-gcp-project/locations/us-central1/featureFlagsConfigs/my-app-instance-01

הגדרת פרויקט Java

כדי להריץ את האפליקציה, צריך לאתחל את הפרויקט ולהגדיר את התלות הדרושה.

  1. יוצרים ספריית פרויקט:

    mkdir java-featureflag-app
    cd java-featureflag-app
    
  2. הוספת יחסי תלות: מגדירים את מערכת ה-build ‏ (Maven או Gradle) כך שתכלול את הספריות הבאות. כדי להבטיח תאימות, צריך להשתמש בגרסאות שגבוהות מ-OpenFeature 1.14.1, מ-flagd 0.11.5 ומ-gRPC 1.71.0.

    • dev.openfeature:javasdk:1.14.1+
    • dev.openfeature.contrib.providers:flagd:0.11.5+
    • io.grpc:grpc-netty-shaded:1.71.0+
    • io.grpc:grpc-auth:1.71.0+
    • com.google.auth:google-auth-library-oauth2-http
  3. יוצרים את קוד האתחול: מוסיפים קובץ בשם FeatureManagement.java עם התוכן הבא. המחלקות האלה מגדירות interceptors של gRPC כדי לצרף כותרות של ADC ושל ניתוב אזורי, ומבצעות אתחול של FlagdProvider באמצעות רזולוציה בתוך התהליך.

    import com.google.auth.oauth2.GoogleCredentials;
    import dev.openfeature.contrib.providers.flagd.Config;
    import dev.openfeature.contrib.providers.flagd.FlagdOptions;
    import dev.openfeature.contrib.providers.flagd.FlagdProvider;
    import dev.openfeature.sdk.OpenFeatureAPI;
    import io.grpc.*;
    import io.grpc.auth.MoreCallCredentials;
    import java.util.ArrayList;
    import java.util.List;
    
    public class FeatureManagement {
        public static void initialize() throws Exception {
            // Read the full Unit resource name
            String flagConfigId = System.getenv("FLAGD_SOURCE_PROVIDER_ID");
            if (flagConfigId == null || flagConfigId.isEmpty()) {
                throw new IllegalStateException("FLAGD_SOURCE_PROVIDER_ID environment variable is not set.");
            }
    
            // Configure gRPC Security and Routing
            GoogleCredentials credentials = GoogleCredentials.getApplicationDefault();
            CallCredentials callCredentials = MoreCallCredentials.from(credentials);
    
            List<ClientInterceptor> interceptors = new ArrayList<>();
    
            // Interceptor to inject the Unit name into headers for regional routing
            interceptors.add(new ClientInterceptor() {
                @Override
                public <ReqT, RespT> ClientCall<ReqT, RespT> interceptCall(MethodDescriptor<ReqT, RespT> method, CallOptions callOptions, Channel next) {
                    return new ForwardingClientCall.SimpleForwardingClientCall<ReqT, RespT>(next.newCall(method, callOptions)) {
                        @Override
                        public void start(Listener<RespT> responseListener, Metadata headers) {
                            headers.put(Metadata.Key.of("x-goog-request-params", Metadata.ASCII_STRING_MARSHALLER), "name=" + flagConfigId);
                            super.start(responseListener, headers);
                        }
                    };
                }
            });
    
            // Interceptor to attach ADC to the gRPC calls
            interceptors.add(new ClientInterceptor() {
                @Override
                public <ReqT, RespT> ClientCall<ReqT, RespT> interceptCall(MethodDescriptor<ReqT, RespT> method, CallOptions callOptions, Channel next) {
                    return next.newCall(method, callOptions.withCallCredentials(callCredentials));
                }
            });
    
            // Initialize the flagd provider with In-Process resolution
            FlagdProvider provider = new FlagdProvider(
                FlagdOptions.builder()
                    .resolverType(Config.Resolver.IN_PROCESS)
                    .host("saasconfig.googleapis.com").port(443)
                    .tls(true)
                    .providerId(flagConfigId)
                    .clientInterceptors(interceptors)
                    .syncMetadataDisabled(true)
                    .deadline(10000)
                    .build()
            );
    
            // Set the global provider
            OpenFeatureAPI.getInstance().setProviderAndWait(provider);
        }
    }
    
  4. יוצרים את הלוגיקה של האפליקציה: מוסיפים קובץ בשם Main.java עם התוכן הבא כדי להריץ את הערכת הדגל.

    import dev.openfeature.sdk.OpenFeatureAPI;
    import dev.openfeature.sdk.MutableContext;
    
    public class Main {
        public static void main(String[] args) throws Exception {
    
        // 1. Get Client
        var client = OpenFeatureAPI.getInstance().getClient("simple-api");
    
        // 2. Create Evaluation Context 
        var context = new dev.openfeature.sdk.MutableContext();
    
        // 3. Evaluate Flag
        // Default to false if evaluation fails or service is unreachable
        boolean isEnhanced = client.getBooleanValue("enhanced-search", false, context);
    
        // 4. Execute business logic based on result
        if (isEnhanced) {
            System.out.println("Executing enhanced search algorithm...");
        } else {
            System.out.println("Standard search algorithm...");
        }
    
        }
    }
    

הרצת אפליקציית Java

אפשר להריץ את האפליקציה באופן מקומי באמצעות ההגדרה העצמאית שלכם, או לפרוס אותה כקונטיינר.

הפעלה עצמאית (באופן מקומי)

  1. הגדרה של משתני סביבה:

    export PROJECT_ID="your-gcp-project-id"
    export LOCATION_1="us-central1"
    export UNIT_ID="my-app-instance-01"
    export FLAGD_SOURCE_PROVIDER_ID="projects/${PROJECT_ID}/locations/${LOCATION_1}/featureFlagsConfigs/${UNIT_ID}"
    
  2. מריצים את האפליקציה: מריצים את הפרויקט באמצעות הפקודה של כלי הבנייה המועדף (לדוגמה, mvn compile exec:java או ./gradlew run).

הפעלה משולבת (בקונטיינר)

  1. יוצרים קובץ Dockerfile: מגדירים build של קונטיינר שכולל את הקובץ הבינארי של Java.

    FROM maven:3.9-eclipse-temurin-17 AS builder
    WORKDIR /app
    COPY pom.xml .
    COPY src ./src
    RUN mvn clean package
    
    FROM eclipse-temurin:17-jre
    WORKDIR /app
    COPY --from=builder /app/target/java-featureflag-app.jar app.jar
    ENTRYPOINT ["java", "-jar", "app.jar"]
    
  2. יוצרים את קובץ האימג' ושולחים אותו:

    export PROJECT_ID="your-gcp-project-id"
    docker build -t gcr.io/${PROJECT_ID}/my-java-app:latest .
    docker push gcr.io/${PROJECT_ID}/my-java-app:latest
    
  3. פריסת השירות: מעדכנים את התוכנית של היחידה כדי להפנות אל gcr.io/${PROJECT_ID}/my-java-app:latest ופורסים את הגרסה החדשה באמצעות השקה של App Lifecycle Manager.

אימות שינויים בדגלים

אחרי שהאפליקציה פועלת, צריך לוודא שהיא מעריכה את ההגדרות של התכונות בצורה נכונה.

  1. בודקים את הערך הראשוני: מוודאים שערך ההערכה שמתאים למצב ההגדרה הראשוני מתועד בפלט של המסוף.
  2. עדכון הדגל ב-App Lifecycle Manager: משנים את מטען הנתונים של הדגל או את כללי הטירגוט באמצעות Google Cloud console או gcloud.
  3. בודקים את הערך המעודכן: מריצים מחדש את הביצוע המקומי או בודקים את יומני הנתונים של מאגר התגים כדי לוודא שהסטטוס החדש הוערך.

המאמרים הבאים