Spring boot & Feature Toggles

Photo by John Carlisle on Unsplash

Developing applications becomes harder as they grow. We know that. What we don’t know is what’s the best way to deal with it. Watching Feature Branches and Toggles in a Post-GitHub World • Sam Newman inspired me to try and explore implementing feature toggles in a micro-services context. This post has examples for Java with Spring Boot but should be useful for other stacks.

Considerations

Feature toggles have some requirements that we need to take into account when thinking about them:

  • difficulty: one point to consider is the amount of code YOU need to write to make everything awesome
  • default state: when my app first starts what state will the flags be in? will the features be default-disabled? default-enabled?
  • run-time configuration: can I change the state of the flags once the app has started?
  • persistence: what happens when my service restarts? do all the flags reset to their initial state? do they maintain any changes I’ve made?
  • (advanced) trigger: are they enabled/disabled for everyone all the time? or just a subset of users? how do you pick which users / connections / requests / API calls get the feature and which don’t?
  • suitability: is the solution suited to the problem at hand? (are you over-engineering this? )

Single instance

Using a single service instance is a good entry level problem for trying out workflows based on feature flags.

Attempt 1. Feature flags can be as simple as having a constant global Map<String, Boolean> which you can update/check from anywhere in your code. Let’s review our checklist:

  • difficulty: low
  • default state: default state is hard-coded
  • run-time configuration: not without some boilerplate
  • persistence: no persistence
  • trigger: no ability to categorize requests differentiate between them
  • suitability: this solution is suitable for very small, short-lived projects

Attempt 2. To try and overcome some of the short-comings of the previous attempt we could have a repository that stores the state of the flags when they’re changed. Also have a few strategies that tell us if a flag should or should not be considered for a certain user. Getting back to our list:

  • difficulty: high. there’s a lot of repository/service methods to implement. not hard in itself, but the code needs to be written, tested and maintained.
  • default state: default state is hard-coded
  • run-time configuration: not without some boilerplate
  • persistence: if implemented adds to the overall complexity
  • trigger: if implemented adds to the overall complexity
  • suitability: I don’t think this solution is worth pursuing when considering alternatives

Attempt 3. What if I want to both have my cake (have persistence and triggers) and eat it (have a low implementation cost)? One solution is to use the Togglz library. It’s simple to use and easy to get started with. Quick glance at the checklist:

  • difficulty: low
  • default state: default state is hard-coded (cold start) or loaded from store (subsequent starts)
  • run-time configuration: has a nice console that allows you to change all variables
  • persistence: can be added if needed with minimal code. multiple storage back-ends are available
  • trigger: has support
  • suitability: suitable for projects of all sizes

Here’s how you implement it

Preparation: add dependencies to build.gradle

compile "org.togglz:togglz-spring-boot-starter:2.5.0.Final"
compile "org.togglz:togglz-console:2.5.0.Final"
compile "org.togglz:togglz-spring-security:2.5.0.Final"
  • define a feature that you want to enable/disable
The isActive method is just for convenience but we keep it ’cause it’s convenient.
  • define a FeatureProvider bean (tell Togglz which enum has your features)
  • use it!
notice the more convenient way to do things :)

Features can be toggled in code, at runtime

Multiple instances

Having multiple instances of your service is both a blessing and a curse. Dealing with distributed configuration is more of the latter than the former. We push on regardless.

We’re going to leverage the fact that Togglz is able to store the flags in a repository and use that to sync state between the instances of our service.

Although database connections are quite cheap they do add up and having each request generate an extra database round-trip can quickly add up. We’re going to use Redis for storing this state as it’s more suited for many short-lived connections, thus freeing up our main database for other tasks.

Changes

  1. Add jedis to your build.gradle:
    compile group: ‘redis.clients’, name: ‘jedis’, version: ‘2.9.0’
  2. Add the Redis data store class found here to your class path. 
    Special care must be taken when the Redis instance is temporarily unavailable as this will bubble up a ConnectException when checking if the feature is active. Not extremely proud of my solution but it keeps things more predictable (returning default — hard-coded — values for properties when the redis connection is unavailable)
  3. Define a StateRepository

That’s it! you can now use your configuration across multiple instances and keep them in sync!

Further considerations

Securing the console

The security console can be secured by defining a UserProvider bean (simpler examples here):

Activation strategies

Activation strategies are an alternative means to enable a feature based on username, IP, current date or other criteria. It’s plug-able so you can define your own strategies but some great ones are already defined!

Bonus

Once you’ve implemented this and have a good workflow you can start trying out other things such as feature flags on the front end and canary releases!


All the code is available on github. Thanks for reading (and don’t forget to clap :) )!