Summary
The Rust SDK currently exposes an async-only evaluation API: every Client::get_*_value/get_*_details method and every FeatureProvider::resolve_* method is async. This proposal asks for a complementary synchronous evaluation path for providers whose resolution is purely in-memory, without removing or changing the existing async API.
Motivation
Our backend servers resolve flags from a local, periodically refreshed in-memory cache (with state polled from S3 in a background task,). For such providers, evaluation itself performs no I/O , yet the async-only API still forces us to set.await through dozens of unrelated functions, even though the underlying evaluation is a hash-map lookup.
The Java SDK also provides a sync-first API (client.getBooleanValue(...))
Spec compliance
Requirement 1.4.12
states:
The client SHOULD provide asynchronous or non-blocking mechanisms for flag evaluation.
This is a SHOULD, not a MUST.
Design sketch (for discussion)
SyncFeatureProvider trait: same surface as FeatureProvider but with plain fn resolve_*_value(...) -> EvaluationResult<ResolutionDetails<T>> methods. Intended for providers backed by local state (files, env vars, in-memory caches).
- Sync accessors on
Client (e.g. get_bool_value_sync(...) -> EvaluationResult<bool>): available when the bound provider implements SyncFeatureProvider;
- Sync-safe internal state for the sync path: the sync accessors must not go through
tokio::sync::RwLock::blocking_*. Options include a
std::sync::RwLock/arc-swap-style snapshot for provider registration.
Open questions:
- Should this live behind a cargo feature (e.g.
sync) to keep the default dependency footprint unchanged?
If the maintainers are open to this direction, I'm happy to work on a PR implementing the agreed design.
Summary
The Rust SDK currently exposes an async-only evaluation API: every
Client::get_*_value/get_*_detailsmethod and everyFeatureProvider::resolve_*method isasync. This proposal asks for a complementary synchronous evaluation path for providers whose resolution is purely in-memory, without removing or changing the existing async API.Motivation
Our backend servers resolve flags from a local, periodically refreshed in-memory cache (with state polled from S3 in a background task,). For such providers, evaluation itself performs no I/O , yet the async-only API still forces us to set
.awaitthrough dozens of unrelated functions, even though the underlying evaluation is a hash-map lookup.The Java SDK also provides a sync-first API (
client.getBooleanValue(...))Spec compliance
Requirement 1.4.12
states:
This is a
SHOULD, not aMUST.Design sketch (for discussion)
SyncFeatureProvidertrait: same surface asFeatureProviderbut with plainfn resolve_*_value(...) -> EvaluationResult<ResolutionDetails<T>>methods. Intended for providers backed by local state (files, env vars, in-memory caches).Client(e.g.get_bool_value_sync(...) -> EvaluationResult<bool>): available when the bound provider implementsSyncFeatureProvider;tokio::sync::RwLock::blocking_*. Options include astd::sync::RwLock/arc-swap-style snapshot for provider registration.Open questions:
sync) to keep the default dependency footprint unchanged?If the maintainers are open to this direction, I'm happy to work on a PR implementing the agreed design.