使用Symfony Process运行异步PHP任务

12
针对耗时任务(如发送电子邮件、图像处理等),我希望能运行异步PHP任务。在Linux系统上实现这一点相当容易,但我想要一个适用于Windows的方法。
我希望它很简单,不需要重装软件,也不需要使用SQL队列等工具,只需运行一个异步任务即可。
因此,我尝试了Symfony进程组件。问题是,同步运行任务正常,但异步运行时会随着主脚本退出。
是否有办法修复这个问题?


composer require symfony/process

index.php

<?php
require './bootstrap.php';
$logFile = './log.txt';

file_put_contents($logFile, '');

append($logFile, 'script (A) : '.timestamp());

$process = new Process('php subscript.php');
$process->start(); // async, subscript exits prematurely…
//$process->run(); // sync, works fine

append($logFile, 'script (B) : '.timestamp());

subscript.php

<?php
require './bootstrap.php';
$logFile = './log.txt';

//ignore_user_abort(true); // doesn't solve issue…

append($logFile, 'subscript (A) : '.timestamp());
sleep(2);
append($logFile, 'subscript (B) : '.timestamp());

bootstrap.php

<?php
require './vendor/autoload.php';
class_alias('Symfony\Component\Process\Process', 'Process');

function append($file, $content) {
    file_put_contents($file, $content."\n", FILE_APPEND);
}

function timestamp() {
    list($usec, $sec) = explode(' ', microtime());
    return date('H:i:s', $sec) . ' ' . sprintf('%03d', floor($usec * 1000));
}

结果

script (A) : 02:36:10 491
script (B) : 02:36:10 511
subscript (A) : 02:36:10 581
// subscript (B) is missing

简而言之:使用exec()在后台运行命令。 - ymakux
3个回答

1
主脚本必须等待异步过程完成。请尝试此代码:
$process = new Process('php subscript.php');
$process->start();
do {
    $process->checkTimeout();
} while ($process->isRunning() && (sleep(1) !== false));
if (!$process->isSuccessful()) {
   throw new \Exception($process->getErrorOutput());
}

1
这使其基本类似于运行。这是如何获取投票的? - Buddhi741
1
如果主脚本必须等待,那么它是同步进程。你的代码毫无意义,会导致“最大执行时间”错误。不明白为什么有人会投赞成票。 - ymakux

1
如果php支持Windows下的fpm, 你可以监听kernel.terminate事件,在响应已发送后提供所有昂贵的任务。
服务:
app.some_listener:
    class: SomeBundle\EventListener\SomeListener
    tags:
        - { name: kernel.event_listener, event: kernel.terminate, method: onKernelTerminate }

监听器:

<?php

namespace SomeBundle\EventListener;

use Symfony\Component\HttpKernel\Event\PostResponseEvent;

class SomeListener
{
    public function onKernelTerminate(PostResponseEvent $event)
    {
        // provide time consuming tasks here
    }
}

谢谢您的关注 :) 不过,我没有使用FastCGI,而且我正在寻找一个简单、便携的解决方案。显然这是不可能的... 我会接受它的。 - Gras Double

0

这不是最优方案,但是可以使用:

$process = new Process('nohup php subscript.php &');
$process->start();

它与简单的exec()有何不同? - ymakux

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接