Laravel - 调用 Artisan 命令并等待结果
Laravel - call Artisan command and wait for the result
我试图在控制器中调用一个非常耗时的 Artisan 命令(它在 20-90 秒内执行),但我有两个问题。首先,似乎命令根本没有执行(如果我 return 输出它只是 returns "0")。
其次,另一部分(returning the file)不等待命令执行(但它可以与第一部分相关)。这是我的代码:
public function returnZip()
{
// just a failsafe, in case if scheduled command did not created the file yet
if( ! file_exists( storage_path( '/app/exports/' . date('Y_m_d') . '.zip' ) ) ){
Artisan::call('maximus:export');
}
return response()->file( storage_path( '/app/exports/' . date('Y_m_d') . '.zip' ) );
}
如何从 route/controller 正确执行 Artisan 命令并等待它完成任务?
编辑
我尝试进一步调试这个问题,发现从 route/controller 调用时根本没有执行该命令。
试过这个:
Route::get('/test', function(){
Artisan::call('maximus:export');
return ['ok'];
});
我的命令应该创建一个文件:
public function handle()
{
exec('touch /some/path/storage/app/exports/test');
}
当我 运行 在终端中执行此命令时,正在创建文件,但是当我点击路由时,却没有。有任何想法吗?
我很确定 artisan 命令是异步处理的,所以它不会等待命令完成。因此,您的回复很可能是 empty/malformed.
您可能需要查看 Events
和 Listeners
以确保您的操作顺序正确 (https://laravel.com/docs/5.4/events)。
例如,在您的 maximus:export
命令中,您可以在文件创建后立即触发一个事件。
示例:
创建一个名为 ZipCreated
的事件和一个名为 SendZip
的侦听器。然后在您的 artisan 命令处理程序中调用事件:
event(new ZipCreated($file));
然后link它给你EventServiceProvider.php
中的一个听众:
protected $listen = [
Events\Repository\ZipCreated::class => [
Listeners\Repository\SendZip::class,
],
];
这样 ZipCreated
将为 SendZip
提供压缩文件(或文件路径,如果需要)并且 SendZip
可以处理将文件返回给用户。
现在只要命令是 运行,文件的创建和响应的处理将始终以正确的顺序发生。
if I return the output it just returns "0"
让我指出,以防万一 call
方法不是 return 命令的输出,而是它的退出代码(“0”表示成功)。相反,Artisan::output()
将 return 输出。
我会说检查日志看看发生了什么,还要检查你实际上 use
ing Artisan facade。否则,尝试调试器或插入信息性 dd()
语句 ;)(入口点是 Illuminate\Foundation\Console\Kernel::call
)。
好的,我启动了 Laravel 并进行了测试。我的命令是:
public function handle()
{
exec('touch ' . storage_path(str_random(16) . '.txt'));
}
通过调用 Artisan::call()
.
,它在终端和路由中都能完美运行
大胆猜测:www-data 用户(或您的网络服务器使用的 PHP 是 运行 的任何用户)是否有足够的权限来写入文件?
试试这个:
dd(Artisan::输出());
我试图在控制器中调用一个非常耗时的 Artisan 命令(它在 20-90 秒内执行),但我有两个问题。首先,似乎命令根本没有执行(如果我 return 输出它只是 returns "0")。
其次,另一部分(returning the file)不等待命令执行(但它可以与第一部分相关)。这是我的代码:
public function returnZip()
{
// just a failsafe, in case if scheduled command did not created the file yet
if( ! file_exists( storage_path( '/app/exports/' . date('Y_m_d') . '.zip' ) ) ){
Artisan::call('maximus:export');
}
return response()->file( storage_path( '/app/exports/' . date('Y_m_d') . '.zip' ) );
}
如何从 route/controller 正确执行 Artisan 命令并等待它完成任务?
编辑
我尝试进一步调试这个问题,发现从 route/controller 调用时根本没有执行该命令。
试过这个:
Route::get('/test', function(){
Artisan::call('maximus:export');
return ['ok'];
});
我的命令应该创建一个文件:
public function handle()
{
exec('touch /some/path/storage/app/exports/test');
}
当我 运行 在终端中执行此命令时,正在创建文件,但是当我点击路由时,却没有。有任何想法吗?
我很确定 artisan 命令是异步处理的,所以它不会等待命令完成。因此,您的回复很可能是 empty/malformed.
您可能需要查看 Events
和 Listeners
以确保您的操作顺序正确 (https://laravel.com/docs/5.4/events)。
例如,在您的 maximus:export
命令中,您可以在文件创建后立即触发一个事件。
示例:
创建一个名为 ZipCreated
的事件和一个名为 SendZip
的侦听器。然后在您的 artisan 命令处理程序中调用事件:
event(new ZipCreated($file));
然后link它给你EventServiceProvider.php
中的一个听众:
protected $listen = [
Events\Repository\ZipCreated::class => [
Listeners\Repository\SendZip::class,
],
];
这样 ZipCreated
将为 SendZip
提供压缩文件(或文件路径,如果需要)并且 SendZip
可以处理将文件返回给用户。
现在只要命令是 运行,文件的创建和响应的处理将始终以正确的顺序发生。
if I return the output it just returns "0"
让我指出,以防万一 call
方法不是 return 命令的输出,而是它的退出代码(“0”表示成功)。相反,Artisan::output()
将 return 输出。
我会说检查日志看看发生了什么,还要检查你实际上 use
ing Artisan facade。否则,尝试调试器或插入信息性 dd()
语句 ;)(入口点是 Illuminate\Foundation\Console\Kernel::call
)。
好的,我启动了 Laravel 并进行了测试。我的命令是:
public function handle()
{
exec('touch ' . storage_path(str_random(16) . '.txt'));
}
通过调用 Artisan::call()
.
大胆猜测:www-data 用户(或您的网络服务器使用的 PHP 是 运行 的任何用户)是否有足够的权限来写入文件?
试试这个: dd(Artisan::输出());