feat(ffe): Add Feature Flagging and Experimentation support#3643
Closed
leoromanovsky wants to merge 2 commits intoffe/1-libdatadog-bumpfrom
Closed
feat(ffe): Add Feature Flagging and Experimentation support#3643leoromanovsky wants to merge 2 commits intoffe/1-libdatadog-bumpfrom
leoromanovsky wants to merge 2 commits intoffe/1-libdatadog-bumpfrom
Conversation
be2b697 to
f3d286f
Compare
Update libdatadog submodule to include: - feat: Add FFE_FLAGS remote config product and capability (#1532) This adds RemoteConfigProduct::FfeFlags, RemoteConfigCapabilities:: FfeFlagConfigurationRules, and RemoteConfigData::FfeFlags to the remote config layer. Required for the PHP FFE integration (PR #2). Cargo.lock regenerated with pins for CI compatibility: home→0.5.9, rmp→0.8.14, rmp-serde→1.3.0 (edition2024 crates).
Add FFE support to dd-trace-php. Flag evaluation is delegated to libdatadog's datadog-ffe Rust crate via FFI. PHP handles orchestration: config lifecycle, exposure dedup, and HTTP transport. Rust FFI layer (components-rs/ffe.rs): - C-callable bridge to datadog-ffe::rules_based - Global config store behind Mutex<FfeState> - Structured attribute passing (no JSON on hot path) C extension (ext/ddtrace.c): - ffe_evaluate, ffe_has_config, ffe_config_changed, ffe_load_config - Marshals PHP arrays to FfeAttribute structs Remote Config (components-rs/remote_config.rs): - Register FfeFlags product + FfeFlagConfigurationRules capability - Handle add/remove of FFE configs via sidecar PHP Provider (src/DDTrace/FeatureFlags/Provider.php): - Singleton checking RC config state - Calls native evaluate, parses JSON results - Reports exposures via LRU-deduplicated writer Exposure pipeline: - LRU cache (65K entries) with length-prefixed composite keys - Batched writer to /evp_proxy/v2/api/v2/exposures (1000 cap) - Auto-flush via register_shutdown_function OpenFeature adapter (src/DDTrace/OpenFeature/DataDogProvider.php): - Implements AbstractProvider for open-feature/sdk Tests: - LRU cache unit tests (11 tests) - Exposure cache unit tests (12 tests) - 220 evaluation correctness tests from JSON fixtures Config: DD_EXPERIMENTAL_FLAGGING_PROVIDER_ENABLED (default: false)
182801f to
d83199b
Compare
|
Author
|
Superseded — going with single PR #3630 instead of stacked approach. |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## ffe/1-libdatadog-bump #3643 +/- ##
=========================================================
- Coverage 62.20% 62.11% -0.09%
=========================================================
Files 141 141
Lines 13387 13387
Branches 1753 1753
=========================================================
- Hits 8327 8315 -12
- Misses 4263 4273 +10
- Partials 797 799 +2 see 2 files with indirect coverage changes Continue to review full report in Codecov by Sentry.
🚀 New features to boost your workflow:
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Motivation
Add FFE support to dd-trace-php. PHP applications can evaluate feature flags delivered via Remote Config using the same
datadog-ffeRust engine used by Ruby and Python.Stacked on #3642 (libdatadog bump).
Changes
components-rs/ffe.rs): C-callable bridge todatadog-ffe::rules_based— config store, evaluate, result accessorsext/ddtrace.c):ffe_evaluate,ffe_has_config,ffe_config_changed,ffe_load_configinternal functions that marshal PHP arrays toFfeAttributestructscomponents-rs/remote_config.rs): RegisterFfeFlagsproduct +FfeFlagConfigurationRulescapability; handle add/remove of FFE configssrc/DDTrace/FeatureFlags/Provider.php): Singleton that checks RC config state, calls native evaluate, parses JSON results, reports exposures/evp_proxy/v2/api/v2/exposures(1000 event buffer cap)src/DDTrace/OpenFeature/DataDogProvider.php): ImplementsAbstractProviderfor theopen-feature/sdkcomposer packageDD_EXPERIMENTAL_FLAGGING_PROVIDER_ENABLEDgating via X-macro inext/configuration.hDecisions
Evaluation in Rust, not PHP. All flag evaluation (UFC parsing, targeting rules, shard hashing, allocation resolution) happens in
libdatadog'sdatadog-ffecrate via FFI. PHP only handles orchestration (config lifecycle, exposure dedup, HTTP transport). This matches Ruby and Python — no language re-implements evaluation logic.Global config behind
Mutex<FfeState>. The Rust FFE config is stored in alazy_staticglobal with aMutex. PHP is single-threaded per process, soRwLockwould be unnecessary complexity. Thechangedflag andconfigare bundled in one struct to avoid torn reads.Reuses existing RC pipeline. FFE configs flow through the same sidecar →
ddog_process_remote_configs()path as APM Tracing and Live Debugger. No new polling mechanism.Structured attributes, not JSON blobs. The C extension converts PHP arrays into
FfeAttributestructs (typed: string/number/bool) before calling Rust, avoiding JSON encode/decode overhead on the hot path.Exposure dedup uses length-prefixed composite keys. Key =
len(flag):flag:subject, value =len(variant):variant:allocation. Avoids collision from delimiters appearing in flag/subject strings.ExposureWriter caps at 1000 events per request. Matches Ruby and Python. Flush via
register_shutdown_function.Test Results
Unit tests (local, no extension):
Unit tests (Docker with extension):
System tests (FEATURE_FLAGGING_AND_EXPERIMENTATION, apache-mod-8.0):
Cross-language dogfood parity (6 flags, 6 SDKs):
Companion PRs
LOC Breakdown (excluding Cargo.lock + JSON fixtures)