-
Notifications
You must be signed in to change notification settings - Fork 25
Description
Summary
The OpenFeature specification now includes support for hook data, which allows hooks to maintain state across their execution stages (before → after/error → finally). This feature enables use cases like distributed tracing, performance monitoring, and multi-stage validation.
This issue tracks the implementation of hook data support in this SDK to achieve compliance with the latest specification.
Action Required
SDK maintainers need to implement hook data support according to the specification defined in:
- feat: Add hook-data concept for hooks. spec#273 - Initial hook data specification
- fix: Broaden definition of hook data value types. spec#307 - Hook data updates
A reference implementation is available in the .NET SDK PR: open-feature/dotnet-sdk#387
Hook data specification enables stateful hook operations
The OpenFeature hook data specification provides a mechanism for different stages of the same hook to share state during a single flag evaluation. This feature supports implementing telemetry, performance monitoring, and resource management use cases. The .NET SDK's implementation in open-feature/dotnet-sdk#387 demonstrates a successful approach that other SDKs can follow.
Reference Links
- Specification PRs:
- feat: Add hook-data concept for hooks. spec#273 - Initial hook data specification
- fix: Broaden definition of hook data value types. spec#307 - Hook data updates
- Implementation Example: feat: Add support for hook data. dotnet-sdk#387
- Documentation:
Understanding hook data fundamentals
Hook data provides the ability for hooks to maintain state across their execution lifecycle. When a hook starts an operation in the before
stage (like opening a telemetry span), it needs a way to access that same data in the after
stage to complete the operation. Without hook data, developers resort to workarounds like global state, weak maps, or thread-local storage, which introduce complexity and potential bugs.
The specification defines hook data as a mutable, per-hook, per-evaluation data structure. This scoping means each hook instance gets its own isolated data store that persists only for the duration of a single flag evaluation. Different hooks evaluating the same flag don't share data, preventing interference and ensuring predictable behavior.
Core specification requirements
Data structure and access patterns
Hook data MUST be implemented as a structure supporting arbitrary properties with string keys and values of any type. The structure must be mutable to allow stages to modify shared state. SDKs typically implement this as a map-like interface with set(key, value)
and get(key)
methods.
The data structure must be created before the first hook stage executes and remain available throughout all stages (before → after/error → finally). This lifecycle management is the SDK's responsibility, not the hook developer's.
Isolation and scoping guarantees
Each hook instance maintains its own hook data - there's no sharing between different hooks. This isolation extends to:
- Different hook types running for the same evaluation
- Multiple instances of the same hook type
- Hooks registered at different levels (global, client, invocation)
The specification explicitly states that hook data is not shared between different hooks, ensuring separation of concerns.
Integration with hook context
Hook data must be accessible through the hook context parameter passed to all hook stages. The typical pattern follows:
context.hookData.set("key", value) // In before stage
value = context.hookData.get("key") // In after stage
Learning from the .NET SDK implementation
The .NET SDK's PR open-feature/dotnet-sdk#387 provides implementation insights. Their approach enhanced the existing HookContext<T>
class with a Data
property, maintaining backward compatibility while adding new functionality. Lessons include:
API Design: The implementation uses a simple key-value store pattern that's intuitive for developers. Type safety is handled through casting when retrieving values, following .NET conventions.
No Breaking Changes: Existing hooks continue working without modification. The hook data feature is additive - hooks can opt-in to using it without requiring changes to hooks that don't need state sharing.
Examples: The implementation includes examples like timing hooks that measure execution duration, demonstrating the feature's value to developers.
Implementation roadmap for SDK maintainers
Phase 1: Core implementation
Start by implementing the basic hook data structure with these capabilities:
- String-keyed storage with any-type values
- Mutable data access through set/get operations
- Proper lifecycle management (creation before first stage, cleanup after finally)
- Thread-safe access for concurrent evaluations
Phase 2: Integration and testing
Integrate hook data with your existing hook infrastructure:
- Add data property to hook context
- Ensure data flows through all hook stages
- Implement isolation between hook instances
- Create comprehensive test suites covering edge cases
Phase 3: Documentation and examples
Provide guidance for hook developers:
- API documentation with type signatures
- Examples (timing, telemetry, validation)
- Best practices and anti-patterns
- Migration guide if introducing any changes
Implementation considerations
Memory management
Hook data should be garbage collected after the evaluation completes. Consider implementing weak references or explicit cleanup to prevent memory leaks in long-running applications.
Thread safety
Many applications evaluate flags concurrently. Ensure hook data access is thread-safe without introducing significant performance overhead. Consider using concurrent data structures appropriate for your language.
Type safety
In statically-typed languages, consider providing type-safe access patterns while maintaining the flexibility of arbitrary value storage. Generic methods or type assertions can help balance safety with usability.
Performance impact
Hook data should add minimal overhead to flag evaluations. Consider lazy initialization - only create the data structure when a hook actually uses it. Benchmark the implementation to ensure acceptable performance.
Common use cases to support
OpenTelemetry integration
The canonical use case involves creating spans in the before
stage and ending them in after
:
// Before stage
Span span = tracer.spanBuilder("feature-flag-evaluation").startSpan();
context.hookData.set("span", span);
// After stage
Span span = (Span) context.hookData.get("span");
span.end();
Performance monitoring
Tracking evaluation duration is a common requirement:
// Before stage
context.Data.Set("startTime", DateTime.UtcNow);
// After stage
var duration = DateTime.UtcNow - (DateTime)context.Data.Get("startTime");
logger.LogInformation($"Evaluation took {duration.TotalMilliseconds}ms");
Multi-stage validation
Complex validation scenarios benefit from accumulating results:
# Before stage
context.hook_data.set("validation_errors", [])
# Multiple validation stages can add errors
errors = context.hook_data.get("validation_errors")
if not is_valid(context):
errors.append("Validation failed")
# Finally stage checks accumulated errors
if context.hook_data.get("validation_errors"):
logger.warning(f"Validation issues: {errors}")
Testing requirements
Comprehensive test coverage should include:
- Basic functionality: Set and get operations work correctly
- Isolation: Data doesn't leak between hook instances
- Lifecycle: Data persists through all stages but not beyond
- Type handling: Various data types can be stored and retrieved
- Edge cases: Null values, missing keys, concurrent access
- Performance: Minimal overhead for evaluations not using hook data
Migration and compatibility
When implementing hook data support:
- Maintain backward compatibility: Existing hooks must continue working
- Version appropriately: Follow semantic versioning based on impact
- Provide migration guides: Help developers adopt the new feature
- Consider feature flags: Allow gradual rollout of hook data support
Success criteria
A complete hook data implementation should:
- Pass all specification compliance tests
- Support the primary use cases (telemetry, monitoring, validation)
- Add minimal performance overhead
- Provide good developer experience
- Include comprehensive documentation
- Maintain backward compatibility
Conclusion
Hook data provides a feature that enables observability and monitoring capabilities in OpenFeature. By following the specification requirements and learning from successful implementations like the .NET SDK, maintainers can provide consistent, reliable hook data support across all OpenFeature SDKs. The implementation should balance flexibility with safety, performance with functionality, and maintain the isolation guarantees that make hook data predictable and useful.
Additional Resources
Metadata
Metadata
Assignees
Labels
Type
Projects
Status