Skip to content

Instantly share code, notes, and snippets.

@dwbutler
Last active May 8, 2018 20:54
Show Gist options
  • Save dwbutler/d7f7b768f41d3691d60426577c40fd92 to your computer and use it in GitHub Desktop.
Save dwbutler/d7f7b768f41d3691d60426577c40fd92 to your computer and use it in GitHub Desktop.
Sync Heroku prod data to another environment
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
@dwbutler
Copy link
Author

dwbutler commented May 8, 2018

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment