Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cannot run rake task db:create with mysql. #426

Open
abMatGit opened this issue Apr 22, 2017 · 8 comments · May be fixed by #427
Open

Cannot run rake task db:create with mysql. #426

abMatGit opened this issue Apr 22, 2017 · 8 comments · May be fixed by #427

Comments

@abMatGit
Copy link

abMatGit commented Apr 22, 2017

Hey guys! There seems to be an interesting issue related to db:create rake tasks that were failing. This is a synopsis of our research (thanks @camertron):

Issue:

When running bundle exec rake db:create rake task on a fresh rails server, using mysql2 adapters, we get the following error:

Unknown database 'octopus_development'
/Users/amatuszewski/.rbenv/versions/2.1.9/lib/ruby/gems/2.1.0/gems/activerecord-4.2.7.1/lib/active_record/connection_adapters/mysql2_adapter.rb:23:in `rescue in mysql2_connection'
/Users/amatuszewski/.rbenv/versions/2.1.9/lib/ruby/gems/2.1.0/gems/activerecord-4.2.7.1/lib/active_record/connection_adapters/mysql2_adapter.rb:10:in `mysql2_connection'
/Users/amatuszewski/.rbenv/versions/2.1.9/lib/ruby/gems/2.1.0/gems/activerecord-4.2.7.1/lib/active_record/connection_adapters/abstract/connection_pool.rb:438:in `new_connection'
/Users/amatuszewski/.rbenv/versions/2.1.9/lib/ruby/gems/2.1.0/gems/activerecord-4.2.7.1/lib/active_record/connection_adapters/abstract/connection_pool.rb:448:in `checkout_new_connection'
/Users/amatuszewski/.rbenv/versions/2.1.9/lib/ruby/gems/2.1.0/gems/activerecord-4.2.7.1/lib/active_record/connection_adapters/abstract/connection_pool.rb:422:in `acquire_connection'
/Users/amatuszewski/.rbenv/versions/2.1.9/lib/ruby/gems/2.1.0/gems/activerecord-4.2.7.1/lib/active_record/connection_adapters/abstract/connection_pool.rb:349:in `block in checkout'
/Users/amatuszewski/.rbenv/versions/2.1.9/lib/ruby/2.1.0/monitor.rb:211:in `mon_synchronize'
/Users/amatuszewski/.rbenv/versions/2.1.9/lib/ruby/gems/2.1.0/gems/activerecord-4.2.7.1/lib/active_record/connection_adapters/abstract/connection_pool.rb:348:in `checkout'
/Users/amatuszewski/.rbenv/versions/2.1.9/lib/ruby/gems/2.1.0/gems/activerecord-4.2.7.1/lib/active_record/connection_adapters/abstract/connection_pool.rb:263:in `block in connection'
/Users/amatuszewski/.rbenv/versions/2.1.9/lib/ruby/2.1.0/monitor.rb:211:in `mon_synchronize'
/Users/amatuszewski/.rbenv/versions/2.1.9/lib/ruby/gems/2.1.0/gems/activerecord-4.2.7.1/lib/active_record/connection_adapters/abstract/connection_pool.rb:262:in `connection'
/Users/amatuszewski/.rbenv/versions/2.1.9/lib/ruby/gems/2.1.0/bundler/gems/octopus-6b10d719ce0f/lib/octopus/proxy.rb:72:in `safe_connection'
/Users/amatuszewski/.rbenv/versions/2.1.9/lib/ruby/gems/2.1.0/bundler/gems/octopus-6b10d719ce0f/lib/octopus/proxy.rb:79:in `select_connection'
/Users/amatuszewski/.rbenv/versions/2.1.9/lib/ruby/gems/2.1.0/bundler/gems/octopus-6b10d719ce0f/lib/octopus/proxy.rb:199:in `legacy_method_missing_logic'
/Users/amatuszewski/.rbenv/versions/2.1.9/lib/ruby/gems/2.1.0/bundler/gems/octopus-6b10d719ce0f/lib/octopus/proxy.rb:130:in `method_missing'
/Users/amatuszewski/.rbenv/versions/2.1.9/lib/ruby/gems/2.1.0/gems/activerecord-4.2.7.1/lib/active_record/tasks/mysql_database_tasks.rb:16:in `create'
/Users/amatuszewski/.rbenv/versions/2.1.9/lib/ruby/gems/2.1.0/gems/activerecord-4.2.7.1/lib/active_record/tasks/database_tasks.rb:93:in `create'
... <Further stack trace>

What seems to be the issue here is that we are calling the create task: here.
The connection is an Octopus::Proxy class which when calling the create_database method, hits Octopus::Proxy#method_missing which eventually delegates to: safe_connection's connection

The problem here is two things:
Rails db:create rake task establishes the connection with a database configuration { 'database' => nil }: here
The Octopus is overriding this connection with connection_pool.connection which uses a database configuration { 'database' => value in yaml file}. This connection raises the Unknown database issue.

Proposed solution:

Alias the establish_connection method to explicitly and return an establish_connection_without_octopus connection.

This will cause establish_connection configuration_without_database to return a MySQL2::Adapter class instead of a Octopus::Proxy class, from which we can successfully call connection.create_database and bypass Octopus::Proxy#method_missing

Replication stack of issue:

  • Rails 4.2.7
  • Octopus v0.9.0 or master-head
  • MySQL2

Gemfile:

gem 'rails', '4.2.7.1'
...
gem 'ar-octopus', git: 'git@github.com:thiagopradi/octopus'
gem 'mysql2'

Database.yml:

development:
  adapter: mysql2
  encoding: utf8
  database: 'octopus_development'
  username: 'root'
  password: 'password'

Shards.yml:

octopus:
  environments:
    - development

  shards: &shards
    master: &master
      adapter: mysql2
      encoding: utf8
      database: 'octopus_development'
      username: 'root'
      password: 'password'

  development:
    <<: *shards
@abMatGit abMatGit linked a pull request Apr 22, 2017 that will close this issue
@pboling
Copy link

pboling commented Jun 24, 2017

I am running into a similar issue with rake db:reset in development mode, where we are trying to use Octopus to expose write to read only errors before they hit production.

@swordfish444
Copy link
Contributor

@abMatGit @pboling What did you guys end up doing to address this in your apps?

Were you able to come up with a work-around? We are also experiencing this issue and it would help to know how you proceeded.

Thanks to both of you in advance!

@jughead
Copy link

jughead commented Feb 19, 2018

My current workaround:

  1. Add a rake task to enhance db:create db:drop tasks
namespace :octopus do
  task on: :environment do
    ActiveRecord::Base.clear_all_connections!
    Octopus.enable!
  end

  task off: :environment do
    ActiveRecord::Base.clear_all_connections!
    Octopus.disable!
  end
end

Rake::Task['db:create'].enhance(['octopus:off']) do
  Rake::Task['octopus:on'].invoke
end

Rake::Task['db:drop'].enhance(['octopus:off']) do
  Rake::Task['octopus:on'].invoke
end
  1. Patch Octopus module:
module Octopus
   class << self
    def disable!
      @@enabled = false
    end

    def enable!
      @@enabled = true
    end

    def enabled_with_additional_check?
      enabled_without_additional_check? && @@enabled
    end
    alias_method :enabled_without_additional_check?, :enabled?
    alias_method :enabled?, :enabled_with_additional_check?
  end
end
Octopus.enable!

@jvenezia
Copy link

jvenezia commented Dec 28, 2018

@jughead thanks for the workaround.

Didn't you mean to invoke octopus:off after db:drop (instead of octopus:on) ?

This works better for me, otherwise chaining rake db:drop db:create fails, because db:drop would keep Octopus enabled with no existing database.

@evanboho
Copy link

evanboho commented Jun 17, 2019

The problem with this approach is that passing in tasks to the arguments of the enhance method adds them as prerequisites. As such, they only get invoked once, so chaining db:create and db:drop may break.

I was able to get this to work more consistently with this:

Rake::Task['db:create'].actions.unshift Proc.new {
  Rake::Task['octopus:patch'].invoke
  Octopus.disable!
}
Rake::Task['db:create'].enhance do
  Rake::Task['octopus:patch'].invoke
  Octopus.enable!
end
Rake::Task['db:drop'].actions.unshift Proc.new {
  Rake::Task['octopus:patch'].invoke
  Octopus.disable!
}
Rake::Task['db:drop'].enhance do
  Rake::Task['octopus:patch'].invoke
  Octopus.enable!
end

Where there's a task octopus:patch that does the monkey patching. As it's a rake task, it will only ever get called once.

@jvenezia
Copy link

Thank you @evanboho

Can you share your octopus:patch rake task please?

@rajat23
Copy link

rajat23 commented Feb 23, 2020

Hello all, is there any update on this issue? thanks :)

@kvokka
Copy link

kvokka commented Sep 1, 2020

There is simpler solution. You can put

Octopus.environments=[]

in Rakefile and it will do the trick.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

8 participants