Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to establish_connection with more than one database in parallel in Rails?

Context

I'm building a SaaS where users can create their own websites (like Wix or SquareSpace). That's what happens behind scenes:

  • My app has its main database which stores users
  • When a user creates his website, an external database is created to store its data
  • SQL file runs in this external database to set default settings
  • Other users shall create their websites simultaneously

Approach

To create a new database and establish connection I do the following:

ActiveRecord::Base.connection.execute("CREATE DATABASE #{name}")
ActiveRecord::Base.establish_connection(<dynamic db data>)

Then I execute sql code in the db by doing:

sql = File.read(sql_file.sql)
statements = sql.split(/;$/)
statements.pop
ActiveRecord::Base.transaction do
  statements.each do |statement|
    connection.execute(statement)
  end
end

Then I reestablish connection with main db:

ActiveRecord::Base.establish_connection :production

Problem

  1. Establishing connection to dynamic database makes application's main database inacessible for a while:
    • User A is creating a website (establishes dynamic database connection)
    • User B tries to access his user area (which requires application's main db data)
    • Application throws an error because it tries to retrieve data of app-main-db (which connection is not established at the moment)

How can I handle many users creating their websites simultaneously without databases conflict?

In other words, how can I establish_connection with more than one database in parallel?


NOTE: It is not the same as connecting to multiple databases through database.yml. The goal here is to connect and disconnect to dynamic created databases by multiple users simultaneously.

like image 531
Artur Haddad Avatar asked Oct 30 '17 23:10

Artur Haddad


People also ask

Is it possible to connect to multiple databases simultaneously?

This can be done several times to connect to different databases, with the restriction that it will only allow one connection to the same database. If you try to use a database from multiple instances of the same application either on the same computer or on different computers you will receive an error message.


2 Answers

This gem may help. However,you may need to rename some of your models to use the external database namespace instead of ApplicationRecord

https://github.com/ankane/multiverse

like image 68
Zzz Avatar answered Nov 13 '22 20:11

Zzz


I admit that this doesn't answer the core of your initial question but IMO this probably needs to be done via a separate operation, say a pure SQL script triggered somehow via a queue.

You could have your rails app drop a "create message" onto a queue and have a separate service that monitors the queue that does the create operations, and then pass a message with info back to the queue. The rails application monitors the queue for these and then does something with the information.

The larger issue is decoupling your operations. This will help you down the road with things like maintenance, scaling, etc.

FWIW here is a really cool website I found recently describing a lot of popular queuing services.

like image 41
engineerDave Avatar answered Nov 13 '22 21:11

engineerDave