Skip to content

Allow SDK key/config to be changed after client has been initialized.#64

Merged
drichelson merged 16 commits into
masterfrom
dr/changeSdkKey
Nov 17, 2016
Merged

Allow SDK key/config to be changed after client has been initialized.#64
drichelson merged 16 commits into
masterfrom
dr/changeSdkKey

Conversation

@drichelson

@drichelson drichelson commented Nov 5, 2016

Copy link
Copy Markdown
Contributor

The reasoning behind this is that it makes the reset SDK Key feature much more managable when a dynamic configuration is in place.

The intention is that this is an api-breaking change for anyone using the new singleton flow found in init.py, but anyone still using the client constructor should not have to make any code changes.

Comment thread ldclient/__init__.py Outdated


def get():
def get(sdk_key=None):

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

This is the least terrible pattern I could think of: first call get(sdk_key), then on subsequent calls it is optional..
I still don't like it though

@drichelson

Copy link
Copy Markdown
Contributor Author

[ch138]

@drichelson drichelson changed the title Allow SDK key to be changed after client has been initialized. [HOLD] Allow SDK key to be changed after client has been initialized. Nov 8, 2016
Comment thread demo/demo.py
ldclient.sdk_key = 'sdk_key'
ldclient.start_wait = 10
client = ldclient.get()
ldclient.set_sdk_key('YOUR_SDK_KEY')

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Example of new usage pattern.

Comment thread ldclient/__init__.py
# 2 use cases:
# 1. Initial setup: sets the sdk key for the uninitialized client
# 2. Allows on-the-fly changing of the sdk key. When this function is called after the client has been initialized
# the client will get re-initialized with the new sdk key. In order for this to work, the return value of

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

This is the pitfall of this approach, but I don't see another way to do it. any ideas @pkaeding ?

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.

I don't think we should say that it should never be assigned; that seems a bit extreme. It is fine to get the client at the beginning of a request handler that needs to get a bunch of flags. You just don't want to keep the reference long-term.

On the other hand, we believe the population of users who need to change the SDK key at runtime is rather small. So most people can disregard this warning altogether if they like. I think we can re-word this to be less scary, while still explaining enough of the implications of different use cases.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I'm almost inclined to avoid this wording, except when documenting how to change the config in an already-running app.

Comment thread ldclient/client.py
from cachecontrol import CacheControl
from threading import Lock

GET_LATEST_FEATURES_PATH = '/sdk/latest-flags'

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

config code now in its own file.

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.

In order to make this change backwards compatible, I think you could alias the Config class in this package

Comment thread ldclient/config.py
@@ -0,0 +1,171 @@
from ldclient.event_consumer import EventConsumerImpl

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

The refactored Config class is as immutable as python allows..

@drichelson drichelson changed the title [HOLD] Allow SDK key to be changed after client has been initialized. Allow SDK key to be changed after client has been initialized. Nov 11, 2016
@drichelson drichelson changed the title Allow SDK key to be changed after client has been initialized. Allow SDK key/config to be changed after client has been initialized. Nov 11, 2016
Comment thread ldclient/__init__.py Outdated
global __config
global __client
global __lock
if sdk_key is __config.sdk_key:

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.

this should probably be guarded by the read lock, right?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

yes

Comment thread ldclient/__init__.py Outdated
global client
_lock.lock()
if not client:
global __client

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.

I don't think this is needed, since you declared global __client above.

Comment thread ldclient/__init__.py


# the return value should not be assigned.
def get():

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.

In the README, you give an example of:

ldclient.get("your sdk key")

Should this be:

def get(sdk_key=None):

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

apologies- readme is not up to date.

Comment thread ldclient/client.py Outdated

class LDClient(object):
def __init__(self, sdk_key, config=None, start_wait=5):
def __init__(self, config=None, start_wait=5):

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.

To try to make this backwards-compatible, I think you can also allow the sdk_key to be passed to this ctor, and apply it to the config if it is passed in.

If there is some reason not to do that (that I'm missing), then the config argument should not be optional-- it is not valid to create a client with no SDK key.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

it is valid to create an offline client with no sdk key, or a client with a redis feature store (events of course will fail or can be disabled)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Also, directly creating a client is no longer the suggested route, so I prefer to have it only take in the config object.

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.

Ahh, good point about the offline client. I get that we don't want to encourage people to directly create the client, but it might ease the transition if they could drop in the new version, and have everything work as it did before, modulo some deprecation warnings that they can then work to eliminate.


class EventConsumerImpl(Thread, EventConsumer):
def __init__(self, event_queue, sdk_key, config):
def __init__(self, event_queue, config):

@pkaeding pkaeding Nov 11, 2016

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.

This (and below) is a little harder to rationalize the backwards-compatible way of overlaying an optional sdk_key argument on the config.

Maybe doing that, and marking it deprecated would be the way to go? Then we can remove it in the next major release.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

These changes necesitate a major release (due to changes in singleton init flow). Does this change your take on this?

@pkaeding

Copy link
Copy Markdown
Contributor

I think this approach makes sense. I would like to see if we can possibly do it in a backwards-compatible way, to avoid needing a major release, and make upgrading easier for our users. I'm not totally sure if that is possible, though.

Comment thread ldclient/__init__.py Outdated
__lock.unlock()


def init():

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

My thinking here is that this could be called in server init code to pre-warm the client so the first request doesn't incur the penalty of connecting to the stream etc... on second thought I have removed it. Thoughts?

Comment thread ldclient/client.py Outdated
check_uwsgi()
self._config = config or Config.default()

if config is not None and sdk_key is not None:

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.

I think this should check if the skd_key is set in both places, not if any config is passed in. Some existing clients might be using a modified config (changed timeouts, etc), but passing in the sdk_key separately.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

good point- this could break existing patterns..

@pkaeding

Copy link
Copy Markdown
Contributor

lgtm
👍
looks good to me
merge away
I approve
canned replies are great.

@jkodumal

Copy link
Copy Markdown
Contributor

👍

@drichelson drichelson merged commit 2125c5a into master Nov 17, 2016
@drichelson drichelson deleted the dr/changeSdkKey branch November 17, 2016 20:04
eli-darkly added a commit that referenced this pull request Aug 3, 2018
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.

3 participants