Migration warning helper, and only run in production env (#24253)
This commit is contained in:
		
							parent
							
								
									cc5208f020
								
							
						
					
					
						commit
						32553ac00c
					
				
					 4 changed files with 77 additions and 47 deletions
				
			
		| 
						 | 
					@ -1,7 +1,9 @@
 | 
				
			||||||
require Rails.root.join('lib', 'mastodon', 'migration_helpers')
 | 
					require_relative '../../lib/mastodon/migration_helpers'
 | 
				
			||||||
 | 
					require_relative '../../lib/mastodon/migration_warning'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class IdsToBigints < ActiveRecord::Migration[5.1]
 | 
					class IdsToBigints < ActiveRecord::Migration[5.1]
 | 
				
			||||||
  include Mastodon::MigrationHelpers
 | 
					  include Mastodon::MigrationHelpers
 | 
				
			||||||
 | 
					  include Mastodon::MigrationWarning
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  disable_ddl_transaction!
 | 
					  disable_ddl_transaction!
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -69,24 +71,12 @@ class IdsToBigints < ActiveRecord::Migration[5.1]
 | 
				
			||||||
    ]
 | 
					    ]
 | 
				
			||||||
    included_columns << [:deprecated_preview_cards, :id] if table_exists?(:deprecated_preview_cards)
 | 
					    included_columns << [:deprecated_preview_cards, :id] if table_exists?(:deprecated_preview_cards)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    # Print out a warning that this will probably take a while.
 | 
					    migration_duration_warning(<<~EXPLANATION)
 | 
				
			||||||
    if $stdout.isatty
 | 
					      This migration has some sections that can be safely interrupted
 | 
				
			||||||
      say ''
 | 
					      and restarted later, and will tell you when those are occurring.
 | 
				
			||||||
      say 'WARNING: This migration may take a *long* time for large instances'
 | 
					 | 
				
			||||||
      say 'It will *not* lock tables for any significant time, but it may run'
 | 
					 | 
				
			||||||
      say 'for a very long time. We will pause for 10 seconds to allow you to'
 | 
					 | 
				
			||||||
      say 'interrupt this migration if you are not ready.'
 | 
					 | 
				
			||||||
      say ''
 | 
					 | 
				
			||||||
      say 'This migration has some sections that can be safely interrupted'
 | 
					 | 
				
			||||||
      say 'and restarted later, and will tell you when those are occurring.'
 | 
					 | 
				
			||||||
      say ''
 | 
					 | 
				
			||||||
      say 'For more information, see https://github.com/mastodon/mastodon/pull/5088'
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
      10.downto(1) do |i|
 | 
					      For more information, see https://github.com/mastodon/mastodon/pull/5088
 | 
				
			||||||
        say "Continuing in #{i} second#{i == 1 ? '' : 's'}...", true
 | 
					    EXPLANATION
 | 
				
			||||||
        sleep 1
 | 
					 | 
				
			||||||
      end
 | 
					 | 
				
			||||||
    end
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    tables = included_columns.map(&:first).uniq
 | 
					    tables = included_columns.map(&:first).uniq
 | 
				
			||||||
    table_sizes = {}
 | 
					    table_sizes = {}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,4 +1,8 @@
 | 
				
			||||||
 | 
					require_relative '../../lib/mastodon/migration_warning'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class FixAccountsUniqueIndex < ActiveRecord::Migration[5.2]
 | 
					class FixAccountsUniqueIndex < ActiveRecord::Migration[5.2]
 | 
				
			||||||
 | 
					  include Mastodon::MigrationWarning
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  class Account < ApplicationRecord
 | 
					  class Account < ApplicationRecord
 | 
				
			||||||
    # Dummy class, to make migration possible across version changes
 | 
					    # Dummy class, to make migration possible across version changes
 | 
				
			||||||
    has_one :user, inverse_of: :account
 | 
					    has_one :user, inverse_of: :account
 | 
				
			||||||
| 
						 | 
					@ -35,22 +39,11 @@ class FixAccountsUniqueIndex < ActiveRecord::Migration[5.2]
 | 
				
			||||||
  disable_ddl_transaction!
 | 
					  disable_ddl_transaction!
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  def up
 | 
					  def up
 | 
				
			||||||
    if $stdout.isatty
 | 
					    migration_duration_warning(<<~EXPLANATION)
 | 
				
			||||||
      say ''
 | 
					      This migration will irreversibly delete user accounts with duplicate
 | 
				
			||||||
      say 'WARNING: This migration may take a *long* time for large instances'
 | 
					      usernames. You may use the `rake mastodon:maintenance:find_duplicate_usernames`
 | 
				
			||||||
      say 'It will *not* lock tables for any significant time, but it may run'
 | 
					      task to manually deal with such accounts before running this migration.
 | 
				
			||||||
      say 'for a very long time. We will pause for 10 seconds to allow you to'
 | 
					    EXPLANATION
 | 
				
			||||||
      say 'interrupt this migration if you are not ready.'
 | 
					 | 
				
			||||||
      say ''
 | 
					 | 
				
			||||||
      say 'This migration will irreversibly delete user accounts with duplicate'
 | 
					 | 
				
			||||||
      say 'usernames. You may use the `rake mastodon:maintenance:find_duplicate_usernames`'
 | 
					 | 
				
			||||||
      say 'task to manually deal with such accounts before running this migration.'
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      10.downto(1) do |i|
 | 
					 | 
				
			||||||
        say "Continuing in #{i} second#{i == 1 ? '' : 's'}...", true
 | 
					 | 
				
			||||||
        sleep 1
 | 
					 | 
				
			||||||
      end
 | 
					 | 
				
			||||||
    end
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    duplicates = Account.connection.select_all('SELECT string_agg(id::text, \',\') AS ids FROM accounts GROUP BY lower(username), lower(domain) HAVING count(*) > 1').to_ary
 | 
					    duplicates = Account.connection.select_all('SELECT string_agg(id::text, \',\') AS ids FROM accounts GROUP BY lower(username), lower(domain) HAVING count(*) > 1').to_ary
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,4 +1,8 @@
 | 
				
			||||||
 | 
					require_relative '../../lib/mastodon/migration_warning'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class MigrateAccountConversations < ActiveRecord::Migration[5.2]
 | 
					class MigrateAccountConversations < ActiveRecord::Migration[5.2]
 | 
				
			||||||
 | 
					  include Mastodon::MigrationWarning
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  disable_ddl_transaction!
 | 
					  disable_ddl_transaction!
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  class Mention < ApplicationRecord
 | 
					  class Mention < ApplicationRecord
 | 
				
			||||||
| 
						 | 
					@ -62,19 +66,7 @@ class MigrateAccountConversations < ActiveRecord::Migration[5.2]
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  def up
 | 
					  def up
 | 
				
			||||||
    if $stdout.isatty
 | 
					    migration_duration_warning
 | 
				
			||||||
      say ''
 | 
					 | 
				
			||||||
      say 'WARNING: This migration may take a *long* time for large instances'
 | 
					 | 
				
			||||||
      say 'It will *not* lock tables for any significant time, but it may run'
 | 
					 | 
				
			||||||
      say 'for a very long time. We will pause for 10 seconds to allow you to'
 | 
					 | 
				
			||||||
      say 'interrupt this migration if you are not ready.'
 | 
					 | 
				
			||||||
      say ''
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      10.downto(1) do |i|
 | 
					 | 
				
			||||||
        say "Continuing in #{i} second#{i == 1 ? '' : 's'}...", true
 | 
					 | 
				
			||||||
        sleep 1
 | 
					 | 
				
			||||||
      end
 | 
					 | 
				
			||||||
    end
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    migrated  = 0
 | 
					    migrated  = 0
 | 
				
			||||||
    last_time = Time.zone.now
 | 
					    last_time = Time.zone.now
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										55
									
								
								lib/mastodon/migration_warning.rb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										55
									
								
								lib/mastodon/migration_warning.rb
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,55 @@
 | 
				
			||||||
 | 
					# frozen_string_literal: true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					module Mastodon
 | 
				
			||||||
 | 
					  module MigrationWarning
 | 
				
			||||||
 | 
					    WARNING_SECONDS = 10
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    DEFAULT_WARNING = <<~WARNING_MESSAGE
 | 
				
			||||||
 | 
					      WARNING: This migration may take a *long* time for large instances.
 | 
				
			||||||
 | 
					      It will *not* lock tables for any significant time, but it may run
 | 
				
			||||||
 | 
					      for a very long time. We will pause for #{WARNING_SECONDS} seconds to allow you to
 | 
				
			||||||
 | 
					      interrupt this migration if you are not ready.
 | 
				
			||||||
 | 
					    WARNING_MESSAGE
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def migration_duration_warning(explanation = nil)
 | 
				
			||||||
 | 
					      return unless valid_environment?
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      announce_warning(explanation)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      announce_countdown
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def announce_countdown
 | 
				
			||||||
 | 
					      WARNING_SECONDS.downto(1) do |i|
 | 
				
			||||||
 | 
					        say "Continuing in #{i} second#{i == 1 ? '' : 's'}...", true
 | 
				
			||||||
 | 
					        sleep 1
 | 
				
			||||||
 | 
					      end
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def valid_environment?
 | 
				
			||||||
 | 
					      $stdout.isatty && Rails.env.production?
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def announce_warning(explanation)
 | 
				
			||||||
 | 
					      announce_message prepare_message(explanation)
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def announce_message(text)
 | 
				
			||||||
 | 
					      say ''
 | 
				
			||||||
 | 
					      text.each_line do |line|
 | 
				
			||||||
 | 
					        say(line)
 | 
				
			||||||
 | 
					      end
 | 
				
			||||||
 | 
					      say ''
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def prepare_message(explanation)
 | 
				
			||||||
 | 
					      if explanation.blank?
 | 
				
			||||||
 | 
					        DEFAULT_WARNING
 | 
				
			||||||
 | 
					      else
 | 
				
			||||||
 | 
					        DEFAULT_WARNING + "\n#{explanation}"
 | 
				
			||||||
 | 
					      end
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
		Loading…
	
		Reference in a new issue