由于 Laravel 试图执行 Gearman 有效负载,因此您要求的内容是不可能的(请参阅 \Illuminate\Bus\Dispatcher)。
我遇到了同样的情况,只是在 Laravel 作业类周围创建了一个包装器 command。这不是最好的解决方案,因为它将重新排队事件,进入 json 队列,但您不必触及现有的作业类。也许有更多经验的人知道如何在不通过网络再次发送工作的情况下分派工作。
假设我们有一个名为GenerateIdentApplicationPdfJob 的常规 Laravel 工作者类。
class GenerateIdentApplicationPdfJob extends Job implements SelfHandling, ShouldQueue
{
use InteractsWithQueue, SerializesModels;
/** @var User */
protected $user;
protected $requestId;
/**
* Create a new job instance.
*
* QUEUE_NAME = 'ident-pdf';
*
* @param User $user
* @param $requestId
*/
public function __construct(User $user, $requestId)
{
$this->user = $user;
$this->requestId = $requestId;
}
/**
* Execute the job.
*
* @return void
*/
public function handle(Client $client)
{
// ...
}
}
为了能够处理这个类,我们需要提供我们自己的构造函数参数。这些是我们 json 队列中所需的数据。
下面是一个 Laravel command 类 GearmanPdfWorker,它完成了 Gearman 连接和 json_decode 的所有样板,以便能够处理原始作业类。
类 GearmanPdfWorker 扩展命令 {
/**
* The console command name.
*
* @var string
*/
protected $name = 'pdf:worker';
/**
* The console command description.
*
* @var string
*/
protected $description = 'listen to the queue for pdf generation jobs';
/**
* @var \GearmanClient
*/
private $client;
/**
* @var \GearmanWorker
*/
private $worker;
public function __construct(\GearmanClient $client, \GearmanWorker $worker) {
parent::__construct();
$this->client = $client;
$this->worker = $worker;
}
/**
* Wrapper listener for gearman jobs with plain json payload
*
* @return mixed
*/
public function handle()
{
$gearmanHost = env('CB_GEARMAN_HOST');
$gearmanPort = env('CB_GEARMAN_PORT');
if (!$this->worker->addServer($gearmanHost, $gearmanPort)) {
$this->error('Error adding gearman server: ' . $gearmanHost . ':' . $gearmanPort);
return 1;
} else {
$this->info("added server $gearmanHost:$gearmanPort");
}
// use a different queue name than the original laravel command, since the payload is incompatible
$queueName = 'JSON.' . GenerateIdentApplicationPdfJob::QUEUE_NAME;
$this->info('using queue: ' . $queueName);
if (!$this->worker->addFunction($queueName,
function(\GearmanJob $job, $args) {
$queueName = $args[0];
$decoded = json_decode($job->workload());
$this->info("[$queueName] payload: " . print_r($decoded, 1));
$job = new GenerateIdentApplicationPdfJob(User::whereUsrid($decoded->usrid)->first(), $decoded->rid);
$job->onQueue(GenerateIdentApplicationPdfJob::QUEUE_NAME);
$this->info("[$queueName] dispatch: " . print_r(dispatch($job)));
},
[$queueName])) {
$msg = "Error registering gearman handler to: $queueName";
$this->error($msg);
return 1;
}
while (1) {
$this->info("Waiting for job on `$queueName` ...");
$ret = $this->worker->work();
if ($this->worker->returnCode() != GEARMAN_SUCCESS) {
$this->error("something went wrong on `$queueName`: $ret");
break;
}
$this->info("... done `$queueName`");
}
}
}
GearmanPdfWorker 类需要像这样在你的\Bundle\Console\Kernel 中注册:
class Kernel extends ConsoleKernel
{
protected $commands = [
// ...
\Bundle\Console\Commands\GearmanPdfWorker::class
];
// ...
一切就绪后,您可以调用 php artisan pdf:worker 来运行 worker 并通过命令行将一项作业放入 Gearman:gearman -v -f JSON.ident-pdf '{"usrid":9955,"rid":"ABC4711"}'
然后就可以看到操作成功了
added server localhost:4730
using queue: JSON.ident-pdf
Waiting for job on `JSON.ident-pdf` ...
[JSON.ident-pdf] payload: stdClass Object
(
[usrid] => 9955
[rid] => ABC4711
)
0[JSON.ident-pdf] dispatch: 1
... done `JSON.ident-pdf`
Waiting for job on `JSON.ident-pdf` ...