从 Laravel Jobs 返回数据

问题描述 投票:0回答:4

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
方法的结果。

php laravel api-design task-queue
4个回答
16
投票

您正在 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() 时,响应还不会出现。但这就是异步作业的全部目的:)


9
投票

Laravel 7 及更早版本

如果您使用

sync
以外的队列驱动程序,并且使用 Laravel 版本 7 或更早版本,则可以使用 @Denis Mysenko 方法和方法
dispatchNow
从 Job 对象获取数据效果很好。

Laravel 8

但是,在 Laravel 版本 8 中,

dispatchNow
方法已被弃用,取而代之的是
dispatchSync
。但是,这个新方法创建了作业的新实例,您将无法从客户端脚本访问这个新实例或其任何属性。

解决方案

但是,根据 rodrigo.pedra 的回答,如果您从作业中删除

Illuminate\Bus\Queueable
特征,您将能够从作业
handle
方法返回数据,并在客户端脚本中使用此结果。

如果作业不使用

Queueable
特征,则在使用
dispatchSync
时,handle 方法的返回将可用于请求 - 请参阅这个答案

<?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
驱动程序,立即运行作业。


5
投票

如果你想从 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() . ')'
                 );
   });
}

0
投票

对于 SYNC 模式,请注释

use Queueable

$result = dispatch_sync(new Job());

对于异步模式,您不能直接将结果分配给任何变量,但您可以使用 livewire 和事件广播来分析后台进程并显示结果。设置很容易,只需检查一些文档即可开始!

© www.soinside.com 2019 - 2024. All rights reserved.