Skip to content

feat: let providers own their lifecycle events - #353

Merged
josecolella merged 1 commit into
mainfrom
feat/provider-lifecycle-events
Oct 23, 2026
Merged

josecolella merged 1 commit into
mainfrom
feat/provider-lifecycle-events

Conversation

@josecolella

Copy link
Copy Markdown
Collaborator

Summary

Behavior changes worth noting

  • Legacy providers: a provider with init but no marker keeps the SDK-emitted READY/ERROR, as before. That path is now deprecated, and when a logger is configured the SDK logs a warning once per provider class. The forced READY when an already-initialized provider is set again with set_provider_and_wait now happens only for these providers.
  • Providers without init (for example NoOpProvider, InMemoryProvider, and contrib's flagd, ofrep, flipt and go-feature-flag) are READY when set_provider returns, with no background thread (2.8.5.1). Their READY handlers run on the thread calling set_provider, so a slow handler blocks that call. Binding one to another domain runs that domain's READY handlers.
  • InMemoryProvider#init is removed. A subclass init that calls super now raises NoMethodError; subclasses that define their own init take the legacy path. Contrib's meta_provider spec mocks InMemoryProvider#init with verified doubles, so it will need a small update when it moves to this version.
  • set_provider_and_wait still raises ProviderInitializationError when init raises, for every kind of provider. For a marker provider that never emits READY, it returns and the status stays NOT_READY.
  • Events a provider emits from its own init record their status when sent, so set_provider_and_wait called from one of its handlers returns with the new status.
  • Cucumber test providers now reach their states through real events instead of writing the status registry.

🤖 Generated with Claude Code

@coderabbitai

coderabbitai Bot commented Oct 23, 2026 •

Copy link
Copy Markdown

Warning

Review limit reached

This review ran on the open-source allowance, not this organization's plan, because the pull request author doesn't have an assigned seat. Waiting won't change this — ask an organization admin to assign them a seat, or add seats in Billing if every seat is already assigned, then retry.

Next included review available in 22 minutes.

Check out review usage here.

View limit details

Limit details: You’ve used the included review currently available.

Learn how review limits work.

Review configuration:

⚙️ Run configuration
  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: Organization UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: cda29f17-9433-4a3e-88aa-99a7643129fc
📥 Commits

Reviewing files that changed from the base of the PR and between 16bf89c and 0d1d20d.

📒 Files selected for processing: 11
  • README.md
  • features/step_definitions/evaluation_steps.rb
  • features/support/test_flags_provider.rb
  • lib/open_feature/sdk/configuration.rb
  • lib/open_feature/sdk/provider/in_memory_provider.rb
  • sig/open_feature/sdk/configuration.rbs
  • sig/open_feature/sdk/provider/in_memory_provider.rbs
  • spec/open_feature/sdk/configuration_spec.rb
  • spec/open_feature/sdk/provider_compatibility_spec.rb
  • spec/specification/domain_scoped_provider_spec.rb
  • spec/specification/provider_spec.rb
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Comment @coderabbitai help to get the list of available commands.

@codecov

codecov Bot commented Oct 23, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 99.67%. Comparing base (16bf89c) to head (0d1d20d).

Additional details and impacted files
@@           Coverage Diff           @@
##             main     #353   +/-   ##
=======================================
  Coverage   99.66%   99.67%           
=======================================
  Files          32       32           
  Lines         906      925   +19     
=======================================
+ Hits          903      922   +19     
  Misses          3        3           

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Base automatically changed from fix/ordered-event-delivery to main October 23, 2026 17:32
@josecolella
josecolella marked this pull request as ready for review October 23, 2026 17:33
@josecolella
josecolella requested a review from a team as a code owner October 23, 2026 17:33
Copilot AI balanced review requested due to automatic review settings October 23, 2026 17:33
Providers can opt in to emitting their own PROVIDER_READY/PROVIDER_ERROR
by defining emits_lifecycle_events? returning true (spec 2.8, Appendix E).
The SDK then sends no synthetic lifecycle events for them and takes
their status from their own events.

- Providers with init but no marker keep the SDK-emitted events, now
  deprecated, and log a warning once per class.
- Providers without init are READY when set_provider returns, and each
  new binding runs that domain's READY handlers (2.8.5.1).
- InMemoryProvider drops its no-op init.
- Events a provider emits from its own init record status when sent,
  so set_provider_and_wait from its handler returns with it.

Signed-off-by: Jose Colella <jose.colella@gusto.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@josecolella
josecolella force-pushed the feat/provider-lifecycle-events branch from aa400b2 to 0d1d20d Compare October 23, 2026 17:34

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Unresolved status-ordering, stale-event, and concurrent-registration issues can expose incorrect readiness or clear a provider’s failure state.

3 open issues
What changed in this PR

This PR advances OpenFeature specification compliance by letting providers own lifecycle events while retaining a deprecated SDK-managed path for legacy providers. It also includes event-delivery changes from the stacked PR.

Changes:

  • Adds lifecycle-event opt-in and synchronous readiness for providers without init.
  • Queues nested events and runs client handlers outside handler locks.
  • Updates documentation, type signatures, and tests to reflect event-driven provider status.
File Description
spec/​specification/​provider_spec.rb Tests lifecycle ownership, readiness, and legacy behavior.
spec/​specification/​events_spec.rb Tests event ordering, reentrancy, and handler validation.
spec/​specification/​domain_scoped_provider_spec.rb Adjusts initialization mocking.
spec/​open_feature/​sdk/​provider_compatibility_spec.rb Updates compatibility checks after removing init.
spec/​open_feature/​sdk/​configuration_spec.rb Updates mocks and checks dispatch-state cleanup.
sig/​open_feature/​sdk/​provider/​in_memory_provider.rbs Removes the init signature.
sig/​open_feature/​sdk/​event_dispatcher.rbs Declares handler validation.
sig/​open_feature/​sdk/​configuration.rbs Declares lifecycle and dispatch helpers.
README.md Documents lifecycle ownership and provider migration.
lib/​open_feature/​sdk/​provider/​in_memory_provider.rb Removes no-op initialization.
lib/​open_feature/​sdk/​event_dispatcher.rb Extracts reusable handler validation.
lib/​open_feature/​sdk/​configuration.rb Implements lifecycle ownership and queued event delivery.
features/​support/​test_flags_provider.rb Makes status fixtures emit provider events.
features/​step_definitions/​evaluation_steps.rb Replaces direct registry writes with provider setup.

Review effort: Balanced

end
elsif !has_init
# Spec 2.8.5.1: each new binding of a provider without init runs its domain's READY handlers
dispatch_provider_event(provider, ProviderEvent::PROVIDER_READY, token: attempt) unless old_provider.equal?(provider)
Comment on lines +206 to +208
elsif !has_init
# Spec 2.8.5.1: each new binding of a provider without init runs its domain's READY handlers
dispatch_provider_event(provider, ProviderEvent::PROVIDER_READY, token: attempt) unless old_provider.equal?(provider)
Comment on lines +282 to 283
token ||= running_init_attempt_on_this_thread(provider)
return if token && !accept_provider_event(provider, event_type, details, token)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants