概要
OpenFeature の Provider の使い方を以下のチュートリアルに沿って実現してみます。
Provider には flagd を使います。
環境
- Go v1.24.0
- open-feature/go-sdk v1.14.1
- flagd v0.11.1
事前準備
まず何もフィーチャーフラグ管理サービスが入っていない状態のWebサーバを用意します。
package main import ( "github.com/gin-gonic/gin" "net/http" ) const defaultMessage = "Hello!" func main() { // Initialize Go Gin engine := gin.Default() // Setup a simple endpoint engine.GET("/hello", func(c *gin.Context) { c.JSON(http.StatusOK, defaultMessage) }) engine.Run() }
このサーバにOpenFeatureを追加実装して行きます。
OpenFeatureの導入
Provider 無しの実装
まずは Provider を入れない状態の実装です。
package main import ( "context" "net/http" "github.com/gin-gonic/gin" "github.com/open-feature/go-sdk/openfeature" ) const defaultMessage = "Hello!" const newWelcomeMessage = "Hello, welcome to this OpenFeature-enabled website!" func main() { // Iinitialize the OpenFeature client with domain name client := openfeature.NewClient("my-domain") engine := gin.Default() engine.GET("/hello", func(c *gin.Context) { // Evaluate welcome-message feature flag welcomeMessage, _ := client.BooleanValue( context.Background(), "welcome-message", false, openfeature.EvaluationContext{}, ) if welcomeMessage { c.JSON(http.StatusOK, newWelcomeMessage) return } else { c.JSON(http.StatusOK, defaultMessage) return } }) engine.Run() }
ポイントとしては以下です。
- NewClient()でクライアントの初期化
- 今回のドメイン名(Provider識別子)は
my-domain
- 今回のドメイン名(Provider識別子)は
- BooleanValue()でフラグ評価
- 今回の flag key は
welcome-message - デフォルトバリアントは
false
- 今回の flag key は
- if文で結果をハンドリング
APIを呼び出すと当然ながらデフォルトメッセージが返ります。
$ curl localhost:8080/hello "Hello!"
flagd Provider を導入
次に flagd という Provider を導入してみます。
flagd とは
flagd はフラグ管理バックエンドシステムで、以下の機能を持っています。
- リアルタイムでフラグを変更可能
- 様々なタイプのフラグを定義可能 -ブーリアン、文字列、数値、JSON
- 特定のユーザーやユーザーの特徴をターゲットにするために、文脈依存のルールを使用可能
- Fractional Evaluation
- 新機能のためのプログレッシブ・ロールアウト
- 複数のソースからフラグ定義を集約
- 集約されたフラグをgRPCストリームとして公開し、インプロセス・プロバイダで使用可能
- 設定されたフラグに対してOFREPサービスを公開
UIは提供されていないですが、パフォーマンス面では毎秒数千リクエスト捌けるレベルなので本番でも利用可能です。
Provider 環境の用意
フラグファイル
flagd はJSONリクエストやJSONファイルでフラグを管理できるので、JSONファイルを用意します。
先ほど welcome-message という flag key で扱っていたので、そのkey名でフラグファイルを管理します。
{ "flags": { "welcome-message": { "variants": { "on": true, "off": false }, "state": "ENABLED", "defaultVariant": "off" } } }
OpenFeature の構成要素やデータモデル - Carpe Diem
を見れば上記JSONのデータモデルのイメージは付くと思います。
docker-compose
flagd サーバを立ち上げるための準備です。
先ほどのJSONファイルを./flags/flagd.jsonに用意します。
それを読み込むようにflagdサーバのdocker-compose.yamlを用意します。
version: '3.8' services: flagd: image: ghcr.io/open-feature/flagd:latest command: start --uri file:/etc/flags/flagd.json ports: - "8013:8013" volumes: - ./flags:/etc/flags/
立ち上げます。
$ docker compose up
実装の修正
実装は簡単で、以下の様にProviderの設定を追記するだけです。
package main import ( "context" "log" "net/http" "github.com/gin-gonic/gin" flagd "github.com/open-feature/go-sdk-contrib/providers/flagd/pkg" "github.com/open-feature/go-sdk/openfeature" ) func main() { err := openfeature.SetNamedProviderAndWait("my-domain", flagd.NewProvider()) if err != nil { log.Fatalf("Failed to set the OpenFeature provider: %v", err) } // Iinitialize the OpenFeature client with domain name client := openfeature.NewClient("my-domain")
ポイントとしては
- Provider 識別子であるドメイン名を設定する
- 今回だと
my-domain
- 今回だと
くらいです。
動作確認
では Provider の動作確認をします。
defaultVariant: offの場合
以前と同様の結果です。
$ curl localhost:8080/hello "Hello!"
defaultVariant: onの場合
JSONファイルを変更します。
{ "flags": { "welcome-message": { "variants": { "on": true, "off": false }, "state": "ENABLED", "defaultVariant": "on" } } }
flagd はリアルタイムに変更を検知します。
flagd-1 | 2025-02-16T19:40:39.515Z info file/filepath_sync.go:108 filepath event: /etc/flags/flagd.json WRITE {"component": "sync", "sync": "fileinfo"}
APIを呼び出すと、フラグが変更されてメッセージも変わりました。
$ curl localhost:8080/hello "Hello, welcome to this OpenFeature-enabled website!
その他
サンプルコード
今回のサンプルコードはこちらです。
Q&A
リアルタイム変更が検知されているということは都度flagdで評価?
はい、現状の設定ではそのように評価されます。
なので可用性やパフォーマンス面を考慮すると、flagd は軽量なのでサイドカーとして使うのが良いでしょう。
もしくは flagd はin-process評価、つまりフラグ管理システム側での中央集権的な評価でなく、サーバ内での評価(local evaluation)もサポートしているので、それを使うことでネットワーク遅延を発生させず高いパフォーマンスを発揮することが可能です。
まとめ
OpenFeature で Provider を使ったサンプルコードを実装してみました。
今回は flagd を使いましたが、OpenFeature をサポートしていればSaaSやOSSなどどれも使えるので、ベンダーロックインを避けることが可能です。