Last active
May 8, 2018 20:54
-
-
Save dwbutler/d7f7b768f41d3691d60426577c40fd92 to your computer and use it in GitHub Desktop.
Sync Heroku prod data to another environment
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
namespace :sync do | |
desc "Run production sync" | |
task run: [ | |
:set_app, | |
:maint_on, | |
:scale_down, | |
:cancel_backup, | |
:delete_database, | |
:create_production_fork, | |
:migrate, | |
:clear_jobs, | |
:clear_sessions, | |
:clear_cache, | |
:scale_up, | |
:maint_off, | |
:test_data, | |
:notify, | |
:reindex_solr, | |
:s3 | |
] | |
desc "Trigger production sync on the CI server" | |
task trigger: "deploy:set_app" do | |
CircleCi.configure do |config| | |
config.token = AppConfig.circleci_token | |
end | |
build_environment_variables = { "RAKE_COMMAND" => "deploy:sync:run", "APP" => APP } | |
res = CircleCi::Project.build_branch( | |
AppConfig.github_org, | |
AppConfig.github_repo, | |
'develop', | |
build_environment_variables | |
) | |
if res.success? | |
build_url = res.body['build_url'] | |
puts "Successfully triggered production -> #{APP} sync. Follow the progress at #{build_url}" | |
Launchy.open(build_url) | |
else | |
$stderr.puts "Trigger failed" | |
exit(1) | |
end | |
end | |
PROD_APP_NAME = "heroku_app_prod" | |
task :set_app do | |
next if defined?(APP) | |
if ENV['APP'] | |
APP = ENV['APP'] | |
puts "Setting Application to #{APP}" | |
else | |
$stderr.puts "Expected environment variable APP to be set" | |
exit(1) | |
end | |
end | |
task :maint_on do | |
puts "\nPutting the app into maintenance mode ..." | |
_execute heroku_command("maintenance:on") | |
end | |
task :maint_off do | |
puts "\nTaking the app out of maintenance mode ..." | |
_execute heroku_command("maintenance:off") | |
end | |
task :cancel_backup do | |
_execute heroku_command("pg:backups:cancel"), exit_on_failure: false | |
end | |
task :clear_cache do | |
puts "\nClearing Cache ..." | |
_execute heroku_command("run --exit-code rake cache:clear") | |
end | |
task :scale_down do | |
_execute heroku_command("ps:scale worker=0 web=0") | |
end | |
task :scale_up do | |
_execute heroku_command("ps:scale worker=1 web=2") | |
end | |
task :delete_database do | |
puts "Deleting #{APP} database..." | |
_execute heroku_command("addons:destroy DATABASE --confirm #{APP}"), exit_on_failure: false | |
end | |
task :create_production_fork do | |
puts "Creating new fork of production database in #{APP}..." | |
_execute heroku_command("addons:create heroku-postgresql:standard-2 --fork #{PROD_APP_NAME}::DATABASE_URL --fast") | |
# pg:wait needs some time to recognize that a new database has been created | |
sleep(60) | |
_execute heroku_command("pg:wait") | |
end | |
task :migrate do | |
puts "Running any migrations needed..." | |
_execute heroku_command("run --exit-code rake db:migrate") | |
end | |
task :test_data do | |
puts "Creating test users..." | |
_execute heroku_command("run:detached rake db:devdata:test_users") | |
end | |
task :clear_jobs do | |
puts "Clearing background jobs..." | |
_execute heroku_command("run --exit-code rake jobs:clear") | |
end | |
task :clear_sessions do | |
puts "Clearing sessions..." | |
_execute heroku_command("pg:psql --command 'truncate table sessions;'") | |
end | |
task :notify do | |
notify "#{APP} has finished syncing with prod. Solr and S3 will continue syncing in the background." | |
end | |
task :reindex_solr do | |
_execute heroku_command("run:detached rake sunspot:reindex") | |
end | |
task :s3 do | |
puts "Syncing production S3 bucket with cloned bucket..." | |
_execute("aws s3 sync s3://uploads-prod s3://uploads-prod-clone --acl public-read") | |
end | |
end | |
def heroku_command(command, opt = { account: ENV['ACCOUNT'] }) | |
command = "heroku #{command} --app #{APP}" | |
command = "#{command} --account #{opt[:account]}" if opt[:account] | |
command | |
end | |
def notify(message) | |
Slack.notify(message, username: 'Deploy Notifications', channel: '#deploys', icon_emoji: ':sheep:') | |
end | |
def _execute(command, exit_on_failure: true) | |
print "Executing '#{command}'\n" | |
unless system(command) | |
puts "Failed to Execute #{command}" | |
if exit_on_failure | |
code = $CHILD_STATUS.exitstatus | |
puts "cowardly exiting with code #{code}" | |
exit(code) | |
end | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Extracted from a Rake task used to synchronize Heroku production data to another Heroku environment (typically a dev/testing environment).
Note that this would probably work well as a Makefile due to the number of callouts to the heroku CLI.