dcr*_*cro 7 php architecture queue laravel laravel-5
我正在构建一个多租户Laravel应用程序(在Laravel 5.3上),它允许每个租户为任何支持的Laravel设置拥有自己的一组配置.这是通过Application使用我自己的实现覆盖默认Laravel 来实现的,该实现提供了自定义配置加载器(覆盖默认值Illuminate\Foundation\Bootstrap\LoadConfiguration).应用程序在引导程序中从环境(PHP $_ENV或.env文件)中检测当前承租人,然后为检测到的承租人加载相应的配置文件.
上述方法适用于HTTP和控制台内核,其中每个请求/命令的生命周期都有限,但我不确定如何接近队列工作程序.我希望为所有租户都有一个队列工作器,并且我已经实现了一个自定义队列连接器,以便在安排队列作业时添加其他元数据,以便在工作人员收到租户时识别租户.
我正在寻求帮助的部分是如何在隔离环境中运行每个队列作业,我可以使用自定义配置进行引导.
我看到的一些可能的解决方案是:
运行作为守护程序运行的自定义队列工作程序并从队列中获取作业,但在单独的PHP进程中执行作业(通过创建exec()); 一旦作业被执行,工作人员收集结果(状态,例外等)并完成父进程中的作业(例如删除作业等)
与上面类似,但是在单独的PHP线程中运行作业而不是使用单独的进程 RunKit Sandbox
实现一个解决方案,一旦收到队列作业,"重新启动"应用程序(例如,重新加载当前租户的配置,重置任何已解析的依赖关系等)
重要的是,我希望这个多租户作业执行对于作业本身是透明的,这样那些不适合在多租户环境中运行的作业(例如来自Laravel Scout等第三方软件包的作业)可以是没有任何修改处理.
有关如何处理此问题的任何建议?
jsz*_*ody 10
我们的情况几乎相同.这是我们的方法:
我们有一个ServiceProvider BootTenantServiceProvider,它在普通的HTTP/Console请求中引导租户.它期望存在一个名为的环境变量TENANT_ID.这样,它将加载所有适当的配置并设置特定的租户.
我们BootsTenant将在队列作业中使用一个特征,它看起来像这样:
trait BootsTenant
{
protected $tenantId;
/**
* Prepare the instance for serialization.
*
* @return array
*/
public function __sleep()
{
$this->tenantId = env('TENANT_ID');
return array_keys(get_object_vars($this));
}
/**
* Restore the ENV, and run the service provider
*/
public function __wakeup()
{
// We need to set the TENANT_ID env, and also force the BootTenantServiceProvider again
\Dotenv::makeMutable();
\Dotenv::setEnvironmentVariable('TENANT_ID', this->tenantId);
app()->register(BootTenantServiceProvider::class, [], true);
}
}
Run Code Online (Sandbox Code Playgroud)
现在我们可以编写一个使用此特征的队列作业.在队列上序列化作业时,该__sleep()方法将在本地存储tenantId.当它被反序列化时,该__wakeup()方法将恢复环境变量并运行服务提供者.
我们的队列作业只需要使用这个特性:
class MyJob implements SelfHandling, ShouldQueue {
use BootsTenant;
protected $userId;
public function __construct($userId)
{
$this->userId = $userId;
}
public function handle()
{
// At this point the job has been unserialized from the queue,
// the trait __wakeup() method has restored the TENANT_ID
// and the service provider has set us all up!
$user = User::find($this->userId);
// Do something with $user
}
}
Run Code Online (Sandbox Code Playgroud)
在SerializesModels该Laravel包括性状提供了自己__sleep和__wakeup方法.我还没弄清楚如何使这两种特性协同工作,或者即使它是可能的.
现在我确保我从未在构造函数中提供完整的Eloquent模型.您可以在上面的示例作业中看到我只将ID存储为类属性,而不是完整模型.我有handle()方法在队列运行时期间获取模型.然后我根本不需要这个SerializesModels特性.
您需要使用queue:listen而不是运行队列工作程序queue:work --daemon.前者为每个队列作业引导框架,后者将引导的框架保存在内存中.
至少,您需要这样做,假设您的租户启动过程需要新的框架启动.如果你能够连续启动多个租户,干净地覆盖每个租户的配置,那么你可能可以侥幸逃脱queue:work --daemon.
| 归档时间: |
|
| 查看次数: |
1788 次 |
| 最近记录: |