switches
Switches lets you turn on and off sections of your code with Switches.foobar?
booleans.
It’s an extraction from brighterplanet.com, where we use it as an emergency button to turn on/off API integration with Facebook, Campaign Monitor, etc.
Quick start
Add 2 lines to config/environment.rb
:
require File.join(File.dirname(__FILE__), 'boot')
[...]
require 'switches' # AFTER boot, BEFORE initializer
[...]
Rails::Initializer.run do |config|
[...]
config.gem 'switches', :lib => false # INSIDE initializer
Now run this:
my-macbook:~/my_app $ ./script/runner 'Switches.setup'
Add your defaults to config/switches/defaults.yml
:
---
ssl: true # ssl support is on by default
campaign_monitor: true # campaign monitor integration is on by default
Tasks
RAKE TASK CAP TASK NOTES
rake s:c cap TARGET s:c show current switches
rake s:d cap TARGET s:d show difference between current and default switches
rake s:on[SWITCH] cap TARGET s:on ARG=SWITCH turn on SWITCH
rake s:off[SWITCH] cap TARGET s:off ARG=SWITCH turn off SWITCH
rake s:clear[SWITCH] cap TARGET s:clear ARG=SWITCH clear any switch for SWITCH
rake s:reset cap TARGET s:reset go back to defaults (deletes config/switches/current.yml)
rake s:backup cap TARGET s:backup backup current switches (copies to config/switches/backup.yml)
rake s:restore cap TARGET s:restore restore backed-up switches (copies backup.yml to current.yml)
rake s:default cap TARGET s:default list default settings
Throwing switches remotely with Capistrano
This is the minimum needed in the TARGET task:
task :production do
role :app, 'ec2-88-77-66-55.compute-1.amazonaws.com'
role :app, '177.133.33.144'
set :rails_env, 'production'
set :deploy_to, '/data/my_app'
set :gfs, false
end
The switches will get applied to any role that matches /app/
(so :app_master, :app, etc.)
Throwing switches before you db:migrate
I like to use Switches to turn off %w{memoization caching facebook campaign_monitor delayed_job}
before running rake db:migrate, so I put this in lib/tasks/zzz_rake_switches.rake
:
namespace :rake_switches do
task :turn_stuff_off do
Rake::Task['s:backup'].execute
%w{memoization caching facebook campaign_monitor delayed_job}.each do |switch|
Rake::Task['s:off'].execute(Rake::TaskArguments.new([:name], [switch]))
end
end
task :turn_stuff_back_on do
Rake::Task['s:restore'].execute
Rake::Task['cache:clear'].execute
end
end
# modify what happens on db:migrate, etc.
[ 'db:migrate', 'your:task:if:it:needs:wrapping' ].each do |task_to_wrap|
Rake::Task[task_to_wrap].enhance(['rake_switches:turn_stuff_off']) do
Rake::Task['rake_switches:turn_stuff_back_on'].invoke
end
end
Note that ‘s:backup’ and ‘s:restore’ are not thread safe or really GFS safe, either.
Usage
You can do stuff like (in app/models/user.rb
):
after_create :subscribe_email if Switches.campaign_monitor?
def subscribe_email
CampaignMonitor.subscribe email
end
Uhh ohh! Campaign Monitor’s API is down and you need to shut off those failing after_creates, like, NOW.
production-server-1:/var/www/apps/my_app $ rake s:off[campaign_monitor]
production-server-1:/var/www/apps/my_app $ sudo monit restart all -g my_app
[...]
production-server-2:/var/www/apps/my_app $ rake s:off[campaign_monitor]
production-server-2:/var/www/apps/my_app $ sudo monit restart all -g my_app
Or, even better, do it with cap:
my-macbook:~/my_app $ cap production s:off ARG=campaign_monitor
my-macbook:~/my_app $ cap production mongrel:restart
For another example, let’s say you’re a developer who doesn’t have a self-signed certificate:
my-macbook:~/my_app $ rake s:off[ssl]
Those changes get persisted in config/switches/current.yml
.
If you want to see your switches vis-a-vis the defaults:
my-macbook:~/my_app $ rake s:d
---
ssl: true => false
And if you want to go back to the defaults:
my-macbook:~/my_app $ rake s:reset
Remember, you should version control config/switches/defaults.yml
and ignore config/switches/current.yml
.
Rationale
Sometimes you just need an easy way to “turn off” code.
Wishlist
+ ?
Copyright
Copyright © 2009 Seamus Abshere. See LICENSE for details.