benr1804's avatar

Overriding config values when Job is executed

Hi all, I have an issue which has been bothering me for a while.

I have a multi tenanted app where each tenant has their own database.

I have the concept of Members on each tenant - so each tenant has its own Members table.

Some tenants have the concept of shared members so their members table is on another database entirely, so to resolve this I am using the getConnectionName() on the Member model:

public function getConnectionName()
    {
        if (app('usesCentralMembers')) {
            return 'central_members';
        } else {
			return 'tenant';
		}
    }

MemberServiceProvider.php I return usesCentralMembers as a boolean and also override the default config values with values from the tenants database - the configurable connection details

$this->app->bind('usesCentralMembers', function () {
    if (setting('central_member_host') && setting('central_member_database')) {
        config([
            'database.connections.central_members.host' => setting('central_member_host'),
            'database.connections.central_members.database' => setting('central_member_database')
        ]);
        return true;
    } else {
        return false;
    }
});
            		

config/database.php

return [
   ...
	'connections' => [
       'central_members' => [
            'driver' => 'mysql',
            'host' => env('CENTRAL_MEMBERS_DB_HOST', 'localhost'),
            'port' => env('CENTRAL_MEMBERS_DB_PORT', '3306'),
            'database' => env('CENTRAL_MEMBERS_DB_DATABASE', 'central_members_please_override_me'),
            'username' => env('CENTRAL_MEMBERS_DB_USERNAME', env('DB_USERNAME', '')),
            'password' => env('CENTRAL_MEMBERS_DB_PASSWORD', env('DB_PASSWORD', '')),
            'unix_socket' => env('CENTRAL_MEMBERS_DB_SOCKET', ''),
            'charset' => 'utf8mb4',
            'collation' => 'utf8mb4_unicode_ci',
            'prefix' => '',
            'strict' => false,
            'engine' => null,
        ]
    ]
...
];

I am sending members an email on the back of an event and via a Job on a Redis Queue.

My issue is that with the tenants that have a central database the configuration values are not respected from the MemberServiceProvider override above. I get the following error:

SQLSTATE[HY000] [1049] Unknown database 'central_members_please_override_me'

How can I tell the application to load the member from the central members connection when the job executes? Not on dispatch. I assume the usesCentralMembers connection is resolving to false when the job executes so it never overrides the config values

Thanks in advance

0 likes
1 reply
LaryAI's avatar
Level 58

To address the issue of overriding configuration values when a job is executed, you need to ensure that the configuration is correctly set up within the job's context. When a job is dispatched, it is serialized and then unserialized when it is processed by the queue worker. This means that any configuration changes made before dispatching the job may not be present when the job is actually executed.

Here’s a step-by-step solution to ensure that the configuration values are correctly set when the job is executed:

  1. Ensure Configuration is Set in the Job's Context: You need to set the configuration values within the job itself, ensuring that the correct database connection is used when the job is executed.

  2. Modify the Job to Set Configuration: Update your job class to set the configuration values in the handle method. This ensures that the configuration is set when the job is executed.

Here’s an example of how you can modify your job class:

  1. Dispatch the Job with Tenant Information: When dispatching the job, pass the tenant information to the job constructor.
$tenant = Tenant::find($tenantId);
SendMemberEmailJob::dispatch($tenant);
  1. Ensure Tenant Model has the Necessary Methods: Make sure your Tenant model has the usesCentralMembers method and the necessary attributes.
class Tenant extends Model
{
    public function usesCentralMembers()
    {
        return $this->central_member_host && $this->central_member_database;
    }
}

By setting the configuration values within the job's handle method, you ensure that the correct database connection is used when the job is executed. This approach ensures that the configuration is correctly set in the context of the job execution, avoiding the issue of configuration values not being respected.

Please or to participate in this conversation.