Skip to content

Commit

Permalink
feat: add option to delay starting processes until all migrations are…
Browse files Browse the repository at this point in the history
… run
  • Loading branch information
adamcooke committed Feb 24, 2024
1 parent bea7450 commit 1c5ff5a
Show file tree
Hide file tree
Showing 2 changed files with 65 additions and 0 deletions.
5 changes: 5 additions & 0 deletions config/initializers/_wait_for_migrations.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# frozen_string_literal: true

require "migration_waiter"

MigrationWaiter.wait_if_appropriate
60 changes: 60 additions & 0 deletions lib/migration_waiter.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
# frozen_string_literal: true

# This initializer will wait for all pending migrations to be applied before
# continuing to start the application. This is useful when running the application
# in a cluster where migrations are run in a separate job which runs at the same
# time as the other processes.

class MigrationWaiter

ATTEMPTS = ENV.fetch("MIGRATION_WAITER_ATTEMPTS", 120)
SLEEP_TIME = ENV.fetch("MIGRATION_WAITER_SLEEP_TIME", 2)

class << self

def wait
attempts_remaining = ATTEMPTS
loop do
pending_migrations = ActiveRecord::Base.connection.migration_context.open.pending_migrations.size
if pending_migrations.zero?
Postal.logger.info "no pending migrations, continuing"
return
end

attempts_remaining -= 1

if attempts_remaining.zero?
Postal.logger.info "#{pending_migrations} migration(s) are still pending after #{ATTEMPTS} attempts, exiting"
Process.exit(1)
else
Postal.logger.info "waiting for #{pending_migrations} migration(s) to be applied (#{attempts_remaining} remaining)"
sleep SLEEP_TIME
end
end
end

def wait_if_appropriate
# Don't wait if not configured
return unless ENV.fetch("MIGRATION_WAITER_ENABLED", "false") == "true"

# Don't wait in the console, rake tasks or rails commands
return if console? || rake_task? || rails_command?

wait
end

def console?
Rails.const_defined?("Console")
end

def rake_task?
Rake.application.top_level_tasks.any?
end

def rails_command?
caller.any? { |c| c =~ /rails\/commands/ }
end

end

end

0 comments on commit 1c5ff5a

Please sign in to comment.