The API usage is very inefficent when using it for every feature-flag in an app. If you could call the API with user-ID and group and it returns all the feature-flags active there would be a far greater use-case.
Agreed. Launch Darkly has some interesting Feature Flag SDKs that do local caching and other optimizations to reduce overhead. https://github.com/launchdarkly
o/t, was checking out your blog and saw that you launched Outlier; congrats! I was a big fan (and heavy user) of Flurry.. excited to see what comes of this.
Thanks for the shout-out! One of the cool things about LaunchDarkly is that you can use it out-of-the-box without needing to provision any additional infrastructure.
By default, the SDKs use server-sent events to push feature flags to an in-memory store. If you need persistence + strong consistency, you can back the SDK with Redis as well.
Disclaimer: I'm one of the co-founders of LaunchDarkly.
I've implemented a similar service in our company inspired from this project. There are few of differences though:
- we are using redis instead of leveldb. This way we can scale the service to multiple instances
- created an API to get all feature flags for an user which is also rendered to the client, so there are no unnecessary requsts to APIs not available
- next on the list there will be caching on the service side and syncronization using redis pub/sub
- currenty we are keeping the user ids explicitly enabled for a feature inside the feature array, but we are going to store them in a more efficient way. For example, if we are going to launch the v2 dashboard view, users should be able to opt-in for beta access. Storing half of your user ids in a leveldb/redis array and iterating each time over it is not efficient.
- Changed user ids from integer to strings. We are using uuids, but everybody should be able to hash the integer user id to an efficient string randomized represantation (hmac, sha1, md5).
- Using a hashing function to represent user ids on a scale between 1 and 100 is not efficient. What happens if you allow 5% traffic and only users with hash > 10 are using your site ? Hashing user id to a 1..100 key always yields the same result. Users having hash key 1 will always see the new features and bugs. Not a nice thing.
We are going to implement a more efficient way: first time a user is checked for a feature we put him in a bucket (there are 100 buckets). First user in bucket 1, second in bucket 2, etc. This way, usage gets randomized for each user on each feature, and inactive users will not have the feature enabled by default
Rollout flags are IMHO best implemented when they are pushed to the machines that need to read them by a technology like zookeeper. Pushed updates are then cached in memory by the machines receiving the updates and can be queried in the hotpath without having to worry about cache invalidation and the extra overhead of network calls.
You can use the Go API client[1] to make this possible from Go. I'm biased as I work for HashiCorp but just wanted to add a server-based option to the mix if a local BoltDB won't work for you.
We've been working on something very similar at work. I don't know if this solution scales very well, as others have mentioned here. One thing that seems unusual to me is the decision to use a POST request instead of GET for the /access endpoint.
14 comments
[ 3.4 ms ] story [ 16.4 ms ] threado/t, was checking out your blog and saw that you launched Outlier; congrats! I was a big fan (and heavy user) of Flurry.. excited to see what comes of this.
By default, the SDKs use server-sent events to push feature flags to an in-memory store. If you need persistence + strong consistency, you can back the SDK with Redis as well.
Disclaimer: I'm one of the co-founders of LaunchDarkly.
- we are using redis instead of leveldb. This way we can scale the service to multiple instances
- created an API to get all feature flags for an user which is also rendered to the client, so there are no unnecessary requsts to APIs not available
- next on the list there will be caching on the service side and syncronization using redis pub/sub
- currenty we are keeping the user ids explicitly enabled for a feature inside the feature array, but we are going to store them in a more efficient way. For example, if we are going to launch the v2 dashboard view, users should be able to opt-in for beta access. Storing half of your user ids in a leveldb/redis array and iterating each time over it is not efficient.
- Changed user ids from integer to strings. We are using uuids, but everybody should be able to hash the integer user id to an efficient string randomized represantation (hmac, sha1, md5).
- Using a hashing function to represent user ids on a scale between 1 and 100 is not efficient. What happens if you allow 5% traffic and only users with hash > 10 are using your site ? Hashing user id to a 1..100 key always yields the same result. Users having hash key 1 will always see the new features and bugs. Not a nice thing. We are going to implement a more efficient way: first time a user is checked for a feature we put him in a bucket (there are 100 buckets). First user in bucket 1, second in bucket 2, etc. This way, usage gets randomized for each user on each feature, and inactive users will not have the feature enabled by default
You can use the Go API client[1] to make this possible from Go. I'm biased as I work for HashiCorp but just wanted to add a server-based option to the mix if a local BoltDB won't work for you.
[1]: https://github.com/hashicorp/consul/tree/master/api