Php 如何在laravel 5中为失败的作业插入覆盖数据库连接?
我正在尝试一个多租户多数据库应用程序,这基本上意味着每个租户都有自己的数据库、自己的用户、资源等 很自然,当一个请求进来时,Laravel需要知道使用哪个DB连接,所以我编写了一个中间件,它基本上解析请求中的JWT并查找租户id或用户名,然后简单地连接到租户的数据库 但是现在我正在处理队列,我试图克服laravel 5的默认行为,它连接到主数据库并插入失败的作业记录 当我深入查看供应商文件时,我发现一个FailedJobProvider界面:Php 如何在laravel 5中为失败的作业插入覆盖数据库连接?,php,laravel,laravel-5,queue,Php,Laravel,Laravel 5,Queue,我正在尝试一个多租户多数据库应用程序,这基本上意味着每个租户都有自己的数据库、自己的用户、资源等 很自然,当一个请求进来时,Laravel需要知道使用哪个DB连接,所以我编写了一个中间件,它基本上解析请求中的JWT并查找租户id或用户名,然后简单地连接到租户的数据库 但是现在我正在处理队列,我试图克服laravel 5的默认行为,它连接到主数据库并插入失败的作业记录 当我深入查看供应商文件时,我发现一个FailedJobProvider界面: <?php namespace Illumi
<?php
namespace Illuminate\Queue\Failed;
interface FailedJobProviderInterface
{
/**
* Log a failed job into storage.
*
* @param string $connection
* @param string $queue
* @param string $payload
* @return void
*/
public function log($connection, $queue, $payload);
/**
* Get a list of all of the failed jobs.
*
* @return array
*/
public function all();
/**
* Get a single failed job.
*
* @param mixed $id
* @return array
*/
public function find($id);
/**
* Delete a single failed job from storage.
*
* @param mixed $id
* @return bool
*/
public function forget($id);
/**
* Flush all of the failed jobs from storage.
*
* @return void
*/
public function flush();
}
<?php
namespace Illuminate\Queue\Failed;
use Carbon\Carbon;
use Illuminate\Database\ConnectionResolverInterface;
class DatabaseFailedJobProvider implements FailedJobProviderInterface
{
/**
* The connection resolver implementation.
*
* @var \Illuminate\Database\ConnectionResolverInterface
*/
protected $resolver;
/**
* The database connection name.
*
* @var string
*/
protected $database;
/**
* The database table.
*
* @var string
*/
protected $table;
/**
* Create a new database failed job provider.
*
* @param \Illuminate\Database\ConnectionResolverInterface $resolver
* @param string $database
* @param string $table
* @return void
*/
public function __construct(ConnectionResolverInterface $resolver, $database, $table)
{
$this->table = $table;
$this->resolver = $resolver;
$this->database = $database;
}
/**
* Log a failed job into storage.
*
* @param string $connection
* @param string $queue
* @param string $payload
* @return void
*/
public function log($connection, $queue, $payload)
{
$failed_at = Carbon::now();
$this->getTable()->insert(compact('connection', 'queue', 'payload', 'failed_at'));
}
/**
* Get a list of all of the failed jobs.
*
* @return array
*/
public function all()
{
return $this->getTable()->orderBy('id', 'desc')->get();
}
/**
* Get a single failed job.
*
* @param mixed $id
* @return array
*/
public function find($id)
{
return $this->getTable()->find($id);
}
/**
* Delete a single failed job from storage.
*
* @param mixed $id
* @return bool
*/
public function forget($id)
{
return $this->getTable()->where('id', $id)->delete() > 0;
}
/**
* Flush all of the failed jobs from storage.
*
* @return void
*/
public function flush()
{
$this->getTable()->delete();
}
/**
* Get a new query builder instance for the table.
*
* @return \Illuminate\Database\Query\Builder
*/
protected function getTable()
{
return $this->resolver->connection($this->database)->table($this->table);
}
}
我知道这太晚了,但我遇到了同样的问题。我想出来了。因此,对于遇到此问题的任何其他人,这是如何做到的:
首先,您需要创建自己的失败作业提供程序类来实现接口。我建议将代码从复制到您的自定义类中,并简单地将其更改为您需要的工作方式。Laravel使用该类中的其余函数执行多项任务,并且该类本身需要与实现的接口相匹配
我只是简单地更改了log方法,将附加数据记录到数据库中的附加列中
在服务提供者(您自己的或默认的)中完成后,您需要包括刚刚创建的新的失败作业提供者类
然后在服务提供商的引导方法中输入以下代码:
// Get a default implementation to trigger a deferred binding
$_ = $this->app['queue.failer'];
//regiter the custom class you created
$this->app->singleton('queue.failer', function ($app) {
$config = $app['config']['queue.failed'];
return new NAMEOFYOURCLASS($app['db'], $config['database'], $config['table']);
});
那个代码正在被覆盖
为了代码清晰,您可以将该代码作为函数放在服务提供程序中,也可以在boot方法中运行该方法
如果要将不同的数据记录到数据库中,请确保同时更新失败的作业迁移和/或数据库表
现在,当一个作业失败时,您的自定义代码将以您想要的方式运行日志记录失败的作业,即使您更新了Laravel版本,这也应该可以正常工作。我参加聚会的时间更晚,但在研究主题时发现了这篇文章,所以我想我也会给出自己的解决方案
我发现最干净的处理方法是使用(非)序列化
我总是将SerializesModels
特性分配给我的工作,我用这种方式“扩展”了它(为了清晰起见,简化了):
<?php
namespace App\Jobs\Traits;
use Illuminate\Queue\SerializesModels;
trait RestoresTenant
{
use SerializesModels {
SerializesModels::__serialize as serialize;
SerializesModels::__unserialize as unserialize;
}
/**
* The tenant ID.
*
* @var string
*/
protected $tenantId;
/**
* Save the current tenant before serialization.
*
* @return array
*/
public function __serialize()
{
// SET THE CURRENT TENANT ID HERE, OR WHATEVER YOU USE TO IDENTIFY IT
// $this->tenantId = ...
return $this->serialize();
}
/**
* Restore the tenant upon unserialization.
*
* @param array $values
* @return array
*/
public function __unserialize(array $values)
{
// RETRIEVE THE TENANT ID AND RESTORE THE DATABASE CONNECTION HERE
// $tenantId = $values["\0*\0tenantId"];
// ...
return $this->unserialize($values);
}
}