TL;DR: 如何从排队作业返回数据而不将其保存在任何地方,并处理作业可能因重试而运行多次的情况?或者如果Jobs不适合这个还有其他办法吗?
我正在 Laravel 上为移动应用程序开发 API。
方法将向其他API发出请求,组合和过滤数据,更改其结构等。
对应用程序的要求之一是响应时间不超过30秒,或者根本不响应。所以,我必须尽可能重复请求。我试图通过 Laravel 队列来实现这一点,目前我的 Job 类中有类似的东西:
private $apiActionName;
public function __construct($apiActionName)
{
$this->apiActionName = $apiActionName;
}
public function handle(SomeService $someService)
{
return $someService->{$this->apiActionName}();
}
控制器中的操作代码:
public function someAction()
{
$data = $this->dispatch(new MyJob($apiActionName));
return response()->json($data);
}
是的,我知道从工作中获得回报是个坏主意,但希望这是可能的。但是
$this->dispatch()
仅返回排队作业 ID,而不是 handle
方法的结果。
您正在 Job 类中返回数据,但将 $data 分配给调度程序 - 请注意,dispatch() 方法不是 Job 类的一部分。
您可以尝试这样的操作,假设您的作业同步运行:
private $apiActionName;
private $response;
public function __construct($apiActionName)
{
$this->apiActionName = $apiActionName;
}
public function handle(SomeService $someService)
{
$this->response = $someService->{$this->apiActionName}();
}
public function getResponse()
{
return $this->response;
}
然后在你的控制器中:
public function someAction()
{
$job = new MyJob($apiActionName);
$data = $this->dispatch($job);
return response()->json($job->getResponse());
}
显然,一旦您进入异步模式和队列,这将不起作用 - 当您调用 getResponse() 时,响应还不会出现。但这就是异步作业的全部目的:)
如果您使用
sync
以外的队列驱动程序,并且使用 Laravel 版本 7 或更早版本,则可以使用 @Denis Mysenko 方法和方法 dispatchNow
从 Job 对象获取数据效果很好。
但是,在 Laravel 版本 8 中,
dispatchNow
方法已被弃用,取而代之的是 dispatchSync
。但是,这个新方法创建了作业的新实例,您将无法从客户端脚本访问这个新实例或其任何属性。
但是,根据 rodrigo.pedra 的回答,如果您从作业中删除
Illuminate\Bus\Queueable
特征,您将能够从作业 handle
方法返回数据,并在客户端脚本中使用此结果。
如果作业不使用
特征,则在使用Queueable
时,handle 方法的返回将可用于请求 - 请参阅这个答案。dispatchSync
<?php
// ...
class MyJob implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, SerializesModels;
// use Queueable
/* do not use ^^ this trait */
private $apiActionName;
/**
* Create a new job instance.
*
* @return void
*/
public function __construct($apiActionName)
{
$this->apiActionName = $apiActionName;
}
/**
* Execute the job.
*
* @return void
*/
public function handle()
{
// operations generating result
$result = $someService->{$this->apiActionName}();
return $result;
}
}
在客户端脚本中
public function someAction()
{
$result = MyJob::dispatchSync($apiActionName);
return response()->json($result);
}
注意:
dispatchSync
方法与使用dispatch()->onQueue('sync')
相同,这将强制队列系统使用sync
驱动程序,立即运行作业。
如果你想从 Laravel 作业返回数据,你需要在
Queue
内部 Providers/AppServiceProvider.php
方法中编写一些 boot
方法(Laravel 7.x / 8)
public function boot()
{
Queue::before(function ( JobProcessing $event ) {
Log::info('Job ready: ' . $event->job->resolveName());
Log::info('Job started: ' . $event->job->resolveName());
});
Queue::after(function ( JobProcessed $event ) {
Log::notice('Job done: ' . $event->job->resolveName());
Log::notice('Job payload: ' . print_r($event->job->payload(), true));
});
Queue::failing(function ( JobFailed $event ) {
Log::error('Job failed: ' .
$event->job->resolveName() .
'(' . $event->exception->getMessage() . ')'
);
});
}
对于 SYNC 模式,请注释
use Queueable
$result = dispatch_sync(new Job());
对于异步模式,您不能直接将结果分配给任何变量,但您可以使用 livewire 和事件广播来分析后台进程并显示结果。设置很容易,只需检查一些文档即可开始!