Php 如何在laravel 5中为失败的作业插入覆盖数据库连接?

Php 如何在laravel 5中为失败的作业插入覆盖数据库连接?,php,laravel,laravel-5,queue,Php,Laravel,Laravel 5,Queue,我正在尝试一个多租户多数据库应用程序,这基本上意味着每个租户都有自己的数据库、自己的用户、资源等 很自然,当一个请求进来时,Laravel需要知道使用哪个DB连接,所以我编写了一个中间件,它基本上解析请求中的JWT并查找租户id或用户名,然后简单地连接到租户的数据库 但是现在我正在处理队列,我试图克服laravel 5的默认行为,它连接到主数据库并插入失败的作业记录 当我深入查看供应商文件时,我发现一个FailedJobProvider界面: <?php namespace Illumi

我正在尝试一个多租户多数据库应用程序,这基本上意味着每个租户都有自己的数据库、自己的用户、资源等

很自然,当一个请求进来时,Laravel需要知道使用哪个DB连接,所以我编写了一个中间件,它基本上解析请求中的JWT并查找租户id或用户名,然后简单地连接到租户的数据库

但是现在我正在处理队列,我试图克服laravel 5的默认行为,它连接到主数据库并插入失败的作业记录

当我深入查看供应商文件时,我发现一个FailedJobProvider界面:

<?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);
    }
}