JacDev's avatar

Multi tenancy multi database upgrade

Hi,

I am playing around with multi tenancy in Laravel and it looks nice. With subdomains and seperate .env files for them I can have seperate 'instances' for different tenants. This all works fine. But now I am thinking about the development, test, production environment.

I am having one development environment and that is sufficient. But I am thinking about mulitple test environments and multiple production environments. I am going to do this as:

Production (1 Prod Laravel instance as develop - 2): customer1.domain.com, customer2.domain.com, customer3.domain.com

Test (1 Test Laravel Instance as develop -1): customer1.test.domain.com, customer2.test.domain.com, customer3.test.domain.com

But now I am thinking about upgrading all the databases, since each customer has a seperate database (as well for test and production). When I do the database migration it will only take my 'default' instance. But I need to migrate all databases at once.

All databases will have the same naming convention: domain_prod_customer1 and domain_test_customer1.

How can I upgrade all databases at once after I have updated my laravel application code? For the test environment I want to test the prod upgrade as well, so prior to migrating the database, I first copy the last one from prod to test and then do the migrate there. So I would like to:

Upgrade test: For each database in domain_test_* (I can do this with SQL); Drop database; Copy domain_prod_x to domain_test_x Migrate database domain_test_x

Upgrade prod: Just a simple migrate.

Any ideas how to accomplish this?

0 likes
7 replies
bugsysha's avatar
Level 61

Maybe with foreach loop in migrations and specifying the DB name in connection method on DB object?

Schema::connection('foo')->create('users', function($table)
{
    $table->increments('id');
});

Note that this is documentation example for Laravel 4.2.

1 like
JacDev's avatar

Nice, strange that I haven't seen that one myself. Thanks, I think I can build something with this code!

andy's avatar

Just wondering,

What package are you using for multi tenancy?

1 like
bugsysha's avatar

I tend to write as much as possible of my own code. Had problems with few packages that stopped with maintenance and one that removed complete code from github. So I don't want to face that problem again.

Writing your own code with Laravel is not that big loss of time cause you can do everything pretty fast.

1 like
opheliadesign's avatar

Just curious, what was the deciding factor for you to go with multiple databases rather than a single database? I ask because I'm preparing to start my first SaaS app using Laravel and I really can't make up my mind.

Also, can you provide a little more information on using multiple .env files? Is any of this automated when a new subscriber signs up or do you take care of it all manually and then notify the subscriber once it's all finished?

crynobone's avatar

I believe my package https://github.com/orchestral/tenanti#multi-database-connection-setup can handle most of the requirement that you need. It is slightly trickier if you have shared prod and test database connection but it can be solved.

In config/database.php

'connections' => [
    'tenants_prod' => [ 
        // ...
        'database' => 'domain_prod_customer'
    ],
    'tenants_test' => [ 
        // ...
        'database' => 'domain_test_customer'
    ],
],

Then you can setup multiple database connection resolver via.

use App\Customer;

Tenanti::setupMultiDatabase('tenants_prod', function (Customer $entity, array $template) {
    $template['database'] = $template['database'].$entity->id;

    return $template;
});

This is under the impression that the model that you use is App\Customer. You might need to make tenants_prod an environment configuration so that you can swap between environment.

To run update you can either use the following:

Run directly

php artisan tenanti:migrate customer

Or push it under queue

php artisan tenanti:queue customer migrate

As your user grows, handling "batch update" is going to be PITA as you need to make X number of database connection that you need to connect in order to successfully update each tenant.

JacDev's avatar

I am not using any package for multi tenancy. It is a manual task, but I will make the .env settings for my environment in development, so when I do a repository checkout it is all in the code. Making in .env file is not that difficult and since I am reading the subdomain it can be easily extended.

I am using different databases for every customer and prod and test, since I don't want to mess things up and want to be able to move instances when necessary. I also want to provide customers with a test environment and don't want them to make changes to the prod environment then. I will be having 3 instances of my Laravel app:

  1. Development, only reachable for me. When development is testing ready, I'll remove my test environment (my complete directory) and check out my cvs to that location. That way I can check whether the code is complete and if upgrading the databases etc work. Then the customer can test it.
  2. Testing, reachable for testing purposes. Acessible through customer.test.domain.com. The customer can test and I read the environment vairable from customer.test to connect to the correct database. I see testing as a final test before upgrading the production environment where nothing must go wrong.
  3. Production. Accessible through customer.domain.com. Own database with only production information, since it is also for the bookkeeper etc and I want to keep it as clean as possible. In test they can do whatever, but production should always be clean.

@ crynobone: That looks nice, I will have a look at that. But I prefer using the .env variables because I need a lot more of configuration for the app and can be more easily done through .env I think (more clear). Like customername, address, logo, settings etc. But I'll check it out, it looks promising with what you have written here above.

Please or to participate in this conversation.