[Generated by cargo-readme: `cargo readme --no-title --no-license > README.md`]:: # flagd Provider for OpenFeature A Rust implementation of the OpenFeature provider for flagd, enabling dynamic feature flag evaluation in your applications. This provider supports multiple evaluation modes, advanced targeting rules, caching strategies, and connection management. It is designed to work seamlessly with the OpenFeature SDK and the flagd service. ### Core Features - **Multiple Evaluation Modes** - **RPC Resolver (Remote Evaluation):** Uses gRPC to perform flag evaluations remotely at a flagd instance. Supports bi-directional streaming, retry backoff, and custom name resolution (including Envoy support). - **REST Resolver:** Uses the OpenFeature Remote Evaluation Protocol (OFREP) over HTTP to evaluate flags. - **In-Process Resolver:** Performs evaluations locally using an embedded evaluation engine. Flag configurations can be retrieved via gRPC (sync mode). - **File Resolver:** Operates entirely from a flag definition file, updating on file changes in a best-effort manner. - **Advanced Targeting** - **Fractional Rollouts:** Uses consistent hashing (implemented via murmurhash3) to split traffic between flag variants in configurable proportions. - **Semantic Versioning:** Compare values using common operators such as '=', '!=', '<', '<=', '>', '>=', '^', and '~'. - **String Operations:** Custom operators for performing “starts_with” and “ends_with” comparisons. - **Complex Targeting Rules:** Leverages JSONLogic and custom operators to support nested conditions and dynamic evaluation. - **Caching Strategies** - Built-in support for LRU caching as well as an in-memory alternative. Flag evaluation results can be cached and later returned with a “CACHED” reason until the configuration updates. - **Connection Management** - Automatic connection establishment with configurable retries, timeout settings, and custom TLS or Unix-socket options. - Support for upstream name resolution including a custom resolver for Envoy proxy integration. ### Installation Add the dependency in your `Cargo.toml`: ```bash cargo add open-feature-flagd cargo add open-feature ``` ### Cargo Features This crate uses cargo features to allow clients to include only the evaluation modes they need, keeping the dependency footprint minimal. By default, all features are enabled. | Feature | Description | Enabled by Default | |---------|-------------|-------------------| | `rpc` | gRPC-based remote evaluation via flagd service | ✅ | | `rest` | HTTP/OFREP-based remote evaluation | ✅ | | `in-process` | Local evaluation with embedded engine (includes File mode) | ✅ | #### Using Specific Features To include only specific evaluation modes: ```toml # Only RPC evaluation open-feature-flagd = { version = "0.0.8", default-features = false, features = ["rpc"] } # Only REST evaluation (lightweight, no gRPC dependencies) open-feature-flagd = { version = "0.0.8", default-features = false, features = ["rest"] } # Only in-process/file evaluation open-feature-flagd = { version = "0.0.8", default-features = false, features = ["in-process"] } # RPC and REST (no local evaluation engine) open-feature-flagd = { version = "0.0.8", default-features = false, features = ["rpc", "rest"] } ``` Then integrate it into your application: ```rust use open_feature_flagd::{FlagdOptions, FlagdProvider, ResolverType}; use open_feature::provider::FeatureProvider; use open_feature::EvaluationContext; #[tokio::main] async fn main() { // Example using the REST resolver mode. let provider = FlagdProvider::new(FlagdOptions { host: "localhost".to_string(), port: 8016, resolver_type: ResolverType::Rest, ..Default::default() }).await.unwrap(); let context = EvaluationContext::default().with_targeting_key("user-123"); let result = provider.resolve_bool_value("bool-flag", &context).await.unwrap(); println!("Flag value: {}", result.value); } ``` ### Evaluation Modes #### Remote Resolver (RPC) In RPC mode, the provider communicates with flagd via gRPC. It supports features like streaming updates, retry mechanisms, and name resolution (including Envoy). ```rust use open_feature_flagd::{FlagdOptions, FlagdProvider, ResolverType}; use open_feature::provider::FeatureProvider; use open_feature::EvaluationContext; #[tokio::main] async fn main() { let provider = FlagdProvider::new(FlagdOptions { host: "localhost".to_string(), port: 8013, resolver_type: ResolverType::Rpc, ..Default::default() }).await.unwrap(); let context = EvaluationContext::default().with_targeting_key("user-123"); let bool_result = provider.resolve_bool_value("feature-enabled", &context).await.unwrap(); println!("Feature enabled: {}", bool_result.value); } ``` #### REST Resolver In REST mode the provider uses the OpenFeature Remote Evaluation Protocol (OFREP) over HTTP. It is useful when gRPC is not an option. ```rust use open_feature_flagd::{FlagdOptions, FlagdProvider, ResolverType}; use open_feature::provider::FeatureProvider; use open_feature::EvaluationContext; #[tokio::main] async fn main() { let provider = FlagdProvider::new(FlagdOptions { host: "localhost".to_string(), port: 8016, resolver_type: ResolverType::Rest, ..Default::default() }).await.unwrap(); let context = EvaluationContext::default().with_targeting_key("user-456"); let result = provider.resolve_string_value("feature-variant", &context).await.unwrap(); println!("Variant: {}", result.value); } ``` #### In-Process Resolver In-process evaluation is performed locally. Flag configurations are sourced via gRPC sync stream. This mode supports advanced targeting operators (fractional, semver, string comparisons) using the built-in evaluation engine. ```rust use open_feature_flagd::{CacheSettings, FlagdOptions, FlagdProvider, ResolverType}; use open_feature::provider::FeatureProvider; use open_feature::EvaluationContext; #[tokio::main] async fn main() { let provider = FlagdProvider::new(FlagdOptions { host: "localhost".to_string(), port: 8015, resolver_type: ResolverType::InProcess, selector: Some("my-service".to_string()), cache_settings: Some(CacheSettings::default()), ..Default::default() }).await.unwrap(); let context = EvaluationContext::default() .with_targeting_key("user-abc") .with_custom_field("environment", "production") .with_custom_field("semver", "2.1.0"); let dark_mode = provider.resolve_bool_value("dark-mode", &context).await.unwrap(); println!("Dark mode enabled: {}", dark_mode.value); } ``` #### File Mode File mode is an in-process variant where flag configurations are read from a file. This is useful for development or environments without network access. ```rust use open_feature_flagd::{FlagdOptions, FlagdProvider, ResolverType}; use open_feature::provider::FeatureProvider; use open_feature::EvaluationContext; #[tokio::main] async fn main() { let file_path = "./path/to/flagd-config.json".to_string(); let provider = FlagdProvider::new(FlagdOptions { host: "localhost".to_string(), resolver_type: ResolverType::File, source_configuration: Some(file_path), ..Default::default() }).await.unwrap(); let context = EvaluationContext::default(); let result = provider.resolve_int_value("rollout-percentage", &context).await.unwrap(); println!("Rollout percentage: {}", result.value); } ``` ### Configuration Options Configurations can be provided as constructor options or via environment variables (with constructor options taking priority). The following options are supported: | Option | Env Variable | Type / Supported Value | Default | Compatible Resolver | |-----------------------------------------|-----------------------------------------|-----------------------------------|-------------------------------------|--------------------------------| | Host | FLAGD_HOST | string | "localhost" | RPC, REST, In-Process, File | | Port | FLAGD_PORT | number | 8013 (RPC), 8016 (REST) | RPC, REST, In-Process, File | | Target URI | FLAGD_TARGET_URI | string | "" | RPC, In-Process | | TLS | FLAGD_TLS | boolean | false | RPC, In-Process | | Socket Path | FLAGD_SOCKET_PATH | string | "" | RPC | | Certificate Path | FLAGD_SERVER_CERT_PATH | string | "" | RPC, In-Process | | Cache Type (LRU / In-Memory / Disabled) | FLAGD_CACHE | string ("lru", "mem", "disabled") | lru | RPC, In-Process, File | | Cache TTL (Seconds) | FLAGD_CACHE_TTL | number | 60 | RPC, In-Process, File | | Max Cache Size | FLAGD_MAX_CACHE_SIZE | number | 1000 | RPC, In-Process, File | | Offline File Path | FLAGD_OFFLINE_FLAG_SOURCE_PATH | string | "" | File | | Retry Backoff (ms) | FLAGD_RETRY_BACKOFF_MS | number | 1000 | RPC, In-Process | | Retry Backoff Maximum (ms) | FLAGD_RETRY_BACKOFF_MAX_MS | number | 120000 | RPC, In-Process | | Retry Grace Period | FLAGD_RETRY_GRACE_PERIOD | number | 5 | RPC, In-Process | | Event Stream Deadline (ms) | FLAGD_STREAM_DEADLINE_MS | number | 600000 | RPC | | Offline Poll Interval (ms) | FLAGD_OFFLINE_POLL_MS | number | 5000 | File | | Source Selector | FLAGD_SOURCE_SELECTOR | string | "" | In-Process | ### License Apache 2.0 - See [LICENSE](./../../LICENSE) for more information.