Pennant
Feature flags for your application, with pluggable backends.
Installation
-
Add the dependency to your
shard.yml
:dependencies: pennant: github: jgaskins/pennant
-
Run
shards install
Usage
Load and configure Pennant:
require "pennant"
require "redis"
redis = Redis::Client.new
Pennant.config do |c|
c.adapter = Pennant::RedisAdapter.new(redis)
end
Now, anywhere in your application, you can simply call Pennant.enabled?("my-feature")
to see if a particular feature flag is enabled.
To enable or disable a feature flag, you can simply call Pennant.enable("my-feature")
or Pennant.disable("my-feature")
, respectively. To run this in production, you can run the following command at a production Bash prompt (assuming your Pennant configuration exists in ./config/pennant.cr
):
crystal eval 'require "./config/pennant"; Pennant.enable "my-feature"'
For example, if your Crystal application is running on Heroku, you can prefix the command with heroku run ...
. If it's running on Kubernetes, you could prefix it with kubectl exec -it $POD -- ...
.
Enabling for a given actor
Pennant allows enabling a feature for specific actors, such as specific users, groups. Any object in your application can be used for this purpose as long as it includes the Pennant::Actor
mixin, which requires defining the pennant_id
method:
struct User
include Pennant::Actor
getter id : UUID
def pennant_id : String
"User:#{id}"
end
end
The format of pennant_id
is up to you, as long as it uniquely identifies that person, group, or concept and resolves to the same value for it every time. For database-backed objects, this is often a class (or table) name and a primary key.
Once you have this in place, you can check whether a feature is enabled by passing for: actor
to the enable
, disable
, and enabled?
method:
if Pennant.enabled?("my-feature", for: current_user)
# new hotness
else
# old and busted
end
Enabling for a percentage of requests
Sometimes you don't necessarily want to enable a feature for the same people, but instead for a percentage of your application's traffic. For this, you can pass percentage_of_time: 0.1
to enable
:
Pennant.enable("my-feature", percentage_of_time: 0.05)
All calls to Pennant.enabled?("my-feature")
will now return true
5% of the time.
Web UI
There is a web UI in progress to manage feature flags so that you don't need to enable/disable them via production shells. The intent is to be able to insert it into your HTTP::Server
middleware:
http = HTTP::Server.new([
HTTP::LogHandler.new,
Pennant::Web.new(mount_at: "/feature_flags"),
# the rest of your HTTP handler entries ...
])
With the Lucky framework, you'd insert this into your middleware
array.
With this in place, if you visit your application at /feature_flags
you will see a list of your feature flags and their current states.
Contributing
- Fork it (https://github.com/jgaskins/pennant/fork)
- Create your feature branch (
git checkout -b my-new-feature
) - Commit your changes (
git commit -am 'Add some feature'
) - Push to the branch (
git push origin my-new-feature
) - Create a new Pull Request
Contributors
- Jamie Gaskins - creator and maintainer