-
Notifications
You must be signed in to change notification settings - Fork 66
feat(launchdarkly): Implement openfeature.StateHandler interface for clean shutdowns #758
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
Summary of ChangesHello @dangra, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed! This pull request enhances the LaunchDarkly OpenFeature provider by integrating proper shutdown procedures. By implementing the Highlights
Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here. You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension. Footnotes
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Code Review
This pull request correctly implements the openfeature.StateHandler interface, enabling clean shutdowns of the LaunchDarkly client. The changes are well-structured and directly address the goal of the PR. I have one suggestion to improve the test coverage for the new shutdown functionality to ensure its correctness and prevent future regressions.
13a5dd8 to
c044bb9
Compare
|
Hey @dangra. Thank you for your contribution. Could you share a bit more about why you want to do this? It seems a bit unfair that |
|
hi @erka, that is a fair observation. My take is that I don't always setup LaunchDarkly as provider but I want to my code to be independent of the provider and be able to call high level it looks like this: func main() {
setupOpenfeature(...)
defer openfeature.Shutdown()
ofc := openfeature.GetApiInstance().GetClient()
if ofc.Boolean("flag-name") {
callSomeStuff()
}
}
func setupOpenfeature(...) {
switch envvarOrConfig {
case "launchdarkly":
ldc, _ := ldclient.MakeClient(sdkey, 0)
provider := launchdarkly.NewProvider(ldc)
openfeature.SetProvider(provider)
case "other":
// setup some other for local development or tests
}
}That is a simplified structure, my setup function does a lot more open-feature related. In fact, due to the recent extended outage caused by AWS that also hit LaunchDarkly, I have setup a LaunchDarkly Relay Proxy and with the use of Multi-Provider it points to upstream and the relay. I am mentioning this because it is two LD providers wrapped in a single provider that supports the StateHandler interface and works transparently. openfeature.Shutdown and LDClient.Close are both supposed to be called as last thing before shutting down, they are pretty much aligned by definition. For the sake of completeness, this is my workaround in case other needs it: // The launchdarkly openfeature provider doesn't implement StateHandler interface
type LaunchdarklyProvider struct {
*ofld.Provider
ldClient *ld.LDClient
}
func (p *LaunchdarklyProvider) Init(evCtx openfeature.EvaluationContext) error {
return nil
}
func (p *LaunchdarklyProvider) Shutdown() {
_ = p.ldClient.Close()
}
func newLaunchdarklyProvider(ldClient *ld.LDClient) *LaunchdarklyProvider {
return &LaunchdarklyProvider{
ldClient: ldClient,
Provider: ofld.NewProvider(ldClient),
}
} |
c044bb9 to
f076203
Compare
|
@dangra thank you for sharing it. I think it would be an easier and quicker approach to simply return the shutdown function from setupOpenfeature. Something like this: func main() {
shutdown := setupOpenfeature( /*...*/ )
defer shutdown()
ofc := openfeature.NewDefaultClient()
if ofc.Boolean("flag-name") {
callSomeStuff()
}
}
func setupOpenfeature( /*...*/ ) func() {
switch envvarOrConfig {
case "launchdarkly":
ldc, _ := ldclient.MakeClient(sdkey, 0)
provider := launchdarkly.NewProvider(ldc)
openfeature.SetProvider(provider)
return func() {
openfeature.Shutdown()
ldc.Close()
}
case "other":
// setup some other for local development or tests
}
return func() {
openfeature.Shutdown()
}
}Another approach would be to create the LD client in the |
I don't want to hijack this PR but this use case stood out to me. It may make for an interesting blog if that's something you'd be interested in. |
I would be interested in understanding why you took this approach as well. Versus always using the proxy. If you are willing to share. |
|
@erka I won't argue against your approach, I think I understand the motivation behind it. To me in practical terms it is about passing the The only alternative I see other than closing this PR and if you are up to, is to have a would that be ok with you? |
|
hey @beeme1mr and @kinyoklion ! 👋🏼 I work for Fly.io so my approach includes running the LD relay proxy as a Fly application. But the service that uses the LD flags is the same that powers the hosting platform and I don't want to rely on a circular dependency without an external fallback source. Fly.io doesn't directly depend on AWS but LD does, and Fly relies on LD flags to fine tune its system. The code defaults aren't always in sync and the LD outage caused not ideal flag values to kick in for the extended period LD endpoints were down. I plan to write a community post about this topic, hopefully can get to it this week 😅 |
|
One thing to keep in mind is that for the LD SDKs close/shutdown is terminal. We added the support to our first-party providers, but because of this they are currently not completely compliant with the specification: https://github.com/open-feature/spec/blob/main/specification/sections/02-providers.md#requirement-252 Which expects a provider to be able to recover from a shutdown. When we did add shutdown support I think we mostly moved to support construction of the SDK instance via the provider instead of only accepting a pre-built client. Which makes this shutdown relationship more expected. This move also allows us to configure a wrapper name/version which helps us to understand OpenFeature adoption. |
@dangra Yeah... someone could be unhappy
Yes, this could be a solid middle-ground solution. |
f076203 to
a776761
Compare
…clean shutdowns Signed-off-by: Daniel Graña <dangra@gmail.com>
Signed-off-by: Daniel Graña <dangra@gmail.com>
Signed-off-by: Daniel Graña <dangra@gmail.com>
a776761 to
c37bac0
Compare
|
@erka thanks for approving. I am afraid I forgot to sign the commits so had to rebase and force push to fulfill DCO check. |
This PR
Implements openfeature.StateHandler interface to call LDClient.Close on shutdown.
How to test
It ensures the provider implements the
openfeature.StateHandlerinterface the same way it is done foropenfeature.FeatureProviderinterface.