LoginSignup
14
8

More than 5 years have passed since last update.

「やべっ、DB消えた!」を10行で撲滅

Last updated at Posted at 2016-12-20

ありますよね、こんなこと。

Migration Overrun

Railsの便利タスク、db:drop, db:schema:load, db:migrate, db:migrate:reset...
先日も共有の開発データベースが消えかけて、開発チームが半日開店休業なんてことがありました。

開発環境だから、「軽微事故」での笑い話。月1くらいで、身近に見かけます。
統計的ヒヤリハットで考えると、数年内に「重大事故」になりかねません。

これが「もし本番だったら…」

  • バックアップからのリストア (過去時点へのデータ戻し)
  • アクセスログ・Mysql-binlogからの戻し (人力)
  • お客様への謝罪告知 と 謝罪行脚
  • 再発防止のための運用変更
  • お客様の信頼を失って業務終了…

実際、世界中の記事で、ちょいちょい見かけますものね。
事業継続性を揺るがす大惨事を。

というわけで、実装してみました。
意外とドキュメント見つけにくいんですよねー

DB:migrateを撲滅する(憎しみをこめて)

実は簡単。
Railsだったら、以下6行。

lib/tasks/db.rake
Rake::Task.tasks.each do |t|
  if t.name[0,3] == "db:"
    t.clear
    t.add_description("!!! Disabled in favor of enterprise design at Acme.")
  end
end

タスク自体を不活化します。
今回は、db:系rakeタスクをgenocideしちゃいました。
db:migrate以下だけ、db:seedだけ などもできますね。

  if t.name[0,3] == "db:" && !t.name.start_with?('db:structure:dump')

などのように除外設定も可能。

$ bundle exec rake -T
...
rake cache_digests:dependencies                  # Lookup first-level dependencies for TEMPLATE (like messages/show or comments/_comment.html)
rake cache_digests:nested_dependencies           # Lookup nested dependencies for TEMPLATE (like messages/show or comments/_comment.html)
rake db:_dump                                    # !!! Disabled in favor of enterprise design at Acme
rake db:abort_if_pending_migrations              # !!! Disabled in favor of enterprise design at Acme
rake db:charset                                  # !!! Disabled in favor of enterprise design at Acme
rake db:collation                                # !!! Disabled in favor of enterprise design at Acme
rake db:create                                   # !!! Disabled in favor of enterprise design at Acme
rake db:create:all                               # !!! Disabled in favor of enterprise design at Acme
rake db:drop                                     # !!! Disabled in favor of enterprise design at Acme
rake db:drop:all                                 # !!! Disabled in favor of enterprise design at Acme
...

見事に消えてくれましたw

以下のような方々におすすめですね
- APIのようなサブシステム
- 運用中だがmigrationを金輪際実行しないアプリケーション

とはいえ、やっぱ要るよね、migration

一時の憎しみと恐怖に駆られてみたものの、
運用回らなくなっちゃいますよね。

  • テストが動かない
  • 開発環境の新規構築ができない

とかとかで。

そんなあなたには、「productionでは実行させない!」例をば。

lib/tasks/guard_db.rake
namespace :guard do
  desc 'Disable a task in production/development environments'
  task :db_by_env do
    if Rails.env.production?
      puts 'This task is disabled. Only available in test environments.'
      exit
    end
  end
end

def guard?(task)
  return false if task.name.in? ['db:structure:dump', 'db:version', 'db:load_config']
  task.name.start_with? 'db:'
end

Rake::Task.tasks.each do |t|
  Rake::Task[t].enhance ['guard:db_by_env'] if guard? t
end

ガード用のタスクを作り、タスク実行前に挟む、というシロモノ。

実行処理をtraceモードで見てみると、こんな感じ

$ rake db:version RAILS_ENV=production --trace
** Invoke db:version (first_time)
** Invoke environment (first_time)
** Execute environment
** Invoke db:load_config (first_time)
** Invoke guard:db_by_env (first_time)
** Execute guard:db_by_env
This task is disabled. Only available in test environments.

ちゃんと処理実行前に落ちてくれてますね。

これで皆さん、明日から枕高く寝られますねー


参考文献

Stackoverflow migration撲滅談義
Disable dangerous rake tasks in production プロダクション環境でやらかして…涙なしには読めません
Qiita Railsのマイグレーションをフックする シンプルな技術記事。こういう時に使うんですねー

14
8
3

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
14
8