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

Queuing Tenant Database Migration Event To Landlord Jobs Table #77

Closed
3assy2018 opened this issue Jul 10, 2020 · 4 comments
Closed

Queuing Tenant Database Migration Event To Landlord Jobs Table #77

3assy2018 opened this issue Jul 10, 2020 · 4 comments

Comments

@3assy2018
Copy link
Contributor

First of all, thanks for great work in this package and the simplicity of implementation, I hope this package keep developing with same philosophy of simplicity.

Preconditions:

  • php version: 7.4.8
  • laravel version: 7.0
  • os: windows

I am trying to fire queuable event in the tenant model (created) observer method to run the migration of each created tenant in the background and simultaneously, but then I got an error like this when the event is fired:

Illuminate/Database/QueryException with message 'SQLSTATE[3D000]: Invalid catalog name: 1046 No database selected (SQL: insert into jobs (queue, attempts, reserved_at, available_at, created_at, payload) values (tenants_db, 0, ?, 1594402919, 1594402919, {"uuid":"77b0d6aa-6313-4276-82fd-0538c5eb7ee7","displayName":"App//Listeners//OnTenantCreated","job":"Illuminate//Queue//CallQueuedHandler@call","maxTries":null,"maxExceptions":null,"delay":null,"timeout":null,"timeoutAt":null,"data":{"commandName":"Illuminate//Events//CallQueuedListener","command":"O:36:/"Illuminate//Events//CallQueuedListener/":8:{s:5:/"class/";s:29:/"App//Listeners//OnTenantCreated/";s:6:/"method/";s:6:/"handle/";s:4:/"data/";a:1:{i:0;O:24:/"App//Events//TenantCreated/":2:{s:6:/"tenant/";O:45:/"Illuminate//Contracts//Database//ModelIdentifier/":4:{s:5:/"class/";s:26:/"App//Models//Landlord//Tenant/";s:2:/"id/";i:55;s:9:/"relations/";a:0:{}s:10:/"connection/";s:8:/"landlord/";}s:6:/"socket/";N;}}s:5:/"tries/";N;s:10:/"retryAfter/";N;s:9:/"timeoutAt/";N;s:7:/"timeout/";N;s:3:/"job/";N;}"}}))'

I think this problem happens because the database default connection is set to tenant which has database value set to null by default, so I cannot be able to access landlord database jobs table, and to be able to distribute the migrations queue tasks to each tenant it must migrate the jobs table first, so I feel that I am lost in an egg or chicken dilemma, so anyone can help with solution or suggest another workflow ?

@masterix21
Copy link
Collaborator

Hi @3assy2018, check if it is useful and give me a feedback.

@3assy2018
Copy link
Contributor Author

@masterix21 Thanks for help, it worked like a charm, but I have a question, will this solution cause problems with tenant specific queue events or jobs as the connection is specified in the config ?

@masterix21
Copy link
Collaborator

I think no, if your jobs will implement the TenantAware interface, and the queue is tenant aware.

@esalazarv
Copy link

First of all, thanks for great work in this package and the simplicity of implementation, I hope this package keep developing with same philosophy of simplicity.

Preconditions:

  • php version: 7.4.8
  • laravel version: 7.0
  • os: windows

I am trying to fire queuable event in the tenant model (created) observer method to run the migration of each created tenant in the background and simultaneously, but then I got an error like this when the event is fired:

Illuminate/Database/QueryException with message 'SQLSTATE[3D000]: Invalid catalog name: 1046 No database selected (SQL: insert into jobs (queue, attempts, reserved_at, available_at, created_at, payload) values (tenants_db, 0, ?, 1594402919, 1594402919, {"uuid":"77b0d6aa-6313-4276-82fd-0538c5eb7ee7","displayName":"App//Listeners//OnTenantCreated","job":"Illuminate//Queue//CallQueuedHandler@call","maxTries":null,"maxExceptions":null,"delay":null,"timeout":null,"timeoutAt":null,"data":{"commandName":"Illuminate//Events//CallQueuedListener","command":"O:36:/"Illuminate//Events//CallQueuedListener/":8:{s:5:/"class/";s:29:/"App//Listeners//OnTenantCreated/";s:6:/"method/";s:6:/"handle/";s:4:/"data/";a:1:{i:0;O:24:/"App//Events//TenantCreated/":2:{s:6:/"tenant/";O:45:/"Illuminate//Contracts//Database//ModelIdentifier/":4:{s:5:/"class/";s:26:/"App//Models//Landlord//Tenant/";s:2:/"id/";i:55;s:9:/"relations/";a:0:{}s:10:/"connection/";s:8:/"landlord/";}s:6:/"socket/";N;}}s:5:/"tries/";N;s:10:/"retryAfter/";N;s:9:/"timeoutAt/";N;s:7:/"timeout/";N;s:3:/"job/";N;}"}}))'

I think this problem happens because the database default connection is set to tenant which has database value set to null by default, so I cannot be able to access landlord database jobs table, and to be able to distribute the migrations queue tasks to each tenant it must migrate the jobs table first, so I feel that I am lost in an egg or chicken dilemma, so anyone can help with solution or suggest another workflow ?

Hi @3assy2018

For my implementation I run migrations for each tenant after been created using Eloquent events:
For this extend the Tenant Model

<?php

namespace App\Models\Tenancy;

use Illuminate\Support\Facades\Artisan;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Str;
use \Spatie\Multitenancy\Models\Tenant as Model;

class Tenant extends Model
{

    public static function booted()
    {
        static::created(function (Tenant $model) {
            // TODO: make async
            $model->database = $model->database ?? Str::slug($model->name, '_');
            $model->createDatabase();
            Artisan::call('tenants:artisan', [
                'artisanCommand' => 'migrate',
                '--tenant' => $model->id
            ]);
        });
    }

    public function createDatabase()
    {
        // TODO: make async
        $schema = $this->database;
        $charset = config("database.connections.tenant.charset",'utf8mb4');
        $collation = config("database.connections.tenant.collation",'utf8mb4_unicode_ci');
        $query = "CREATE DATABASE IF NOT EXISTS {$schema} CHARACTER SET {$charset} COLLATE {$collation};";
        DB::statement($query);
    }
}

If dispatch jobs from routes or controllers works fine but if you try dispatch jobs from artisan command then fails as I mention here #76 and the solution for me is #76 (comment)

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

No branches or pull requests

4 participants