2 releases
new 0.0.4 | Feb 20, 2025 |
---|---|
0.0.3 | Feb 20, 2025 |
#48 in Caching
170KB
3.5K
SLoC
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
:
[dependencies]
open-feature-flagd = "0.0.4"
open-feature = "0.2"
Then integrate it into your application:
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).
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.
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.
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.
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 for more information.
Dependencies
~22–36MB
~639K SLoC