【问题标题】:Run an asynchronous PHP task using Symfony Process使用 Symfony 进程运行一个异步 PHP 任务
【发布时间】:2015-05-27 05:51:55
【问题描述】:

对于耗时的任务(电子邮件发送、图像处理……你明白了),我想运行异步 PHP 任务。

它是quite easy on Linux,但我正在寻找一种也适用于 Windows 的方法。

我希望它尽可能简单。没有artillery,没有SQL 排队,没有一次又一次installing stuff……我只想运行一个该死的异步任务。

所以我尝试了Symfony Process Component。 问题是,同步运行任务可以正常运行,但是当异步运行时,它会沿着主脚本退出。

有没有办法解决这个问题?


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() 在后台运行命令。

标签: windows symfony asynchronous cross-platform symfony-process


【解决方案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());
}

【讨论】:

  • 这使得它基本上类似于运行如何获得投票
  • 如果主脚本必须等待,那么它是同步过程。您的代码毫无意义,它会导致“最大执行时间”错误。不明白为什么人们投票
【解决方案2】:

如果php supports fpm for Windows,你可以监听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,我一直在寻找一种简单、便携的解决方案。显然这是不可能的......我会忍受它。
【解决方案3】:

不是最好的解决方案,但是:

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

【讨论】:

  • 它与简单的 exec() 有何不同?
猜你喜欢
  • 2010-10-25
  • 2013-01-23
  • 2023-01-10
  • 1970-01-01
  • 2020-10-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多