Crate open_feature_flagd

Source
Expand description

§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:

cargo add open-feature-flagd
cargo add open-feature

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:

OptionEnv VariableType / Supported ValueDefaultCompatible Resolver
HostFLAGD_HOSTstring“localhost”RPC, REST, In-Process, File
PortFLAGD_PORTnumber8013 (RPC), 8016 (REST)RPC, REST, In-Process, File
Target URIFLAGD_TARGET_URIstring“”RPC, In-Process
TLSFLAGD_TLSbooleanfalseRPC, In-Process
Socket PathFLAGD_SOCKET_PATHstring“”RPC
Certificate PathFLAGD_SERVER_CERT_PATHstring“”RPC, In-Process
Cache Type (LRU / In-Memory / Disabled)FLAGD_CACHEstring (“lru”, “mem”, “disabled”)lruRPC, In-Process, File
Cache TTL (Seconds)FLAGD_CACHE_TTLnumber60RPC, In-Process, File
Max Cache SizeFLAGD_MAX_CACHE_SIZEnumber1000RPC, In-Process, File
Offline File PathFLAGD_OFFLINE_FLAG_SOURCE_PATHstring“”File
Retry Backoff (ms)FLAGD_RETRY_BACKOFF_MSnumber1000RPC, In-Process
Retry Backoff Maximum (ms)FLAGD_RETRY_BACKOFF_MAX_MSnumber120000RPC, In-Process
Retry Grace PeriodFLAGD_RETRY_GRACE_PERIODnumber5RPC, In-Process
Event Stream Deadline (ms)FLAGD_STREAM_DEADLINE_MSnumber600000RPC
Offline Poll Interval (ms)FLAGD_OFFLINE_POLL_MSnumber5000File
Source SelectorFLAGD_SOURCE_SELECTORstring“”In-Process

§License

Apache 2.0 - See LICENSE for more information.

Re-exports§

pub use cache::CacheService;
pub use cache::CacheSettings;
pub use cache::CacheType;
pub use resolver::rpc::RpcResolver;

Modules§

cache
error
flagd
resolver

Structs§

FlagdOptions
Configuration options for the flagd provider
FlagdProvider
Main provider implementation for flagd

Enums§

ResolverType
Type of resolver to use for flag evaluation