12

For time-consuming tasks (email sending, image manipulation… you get the point), I want to run asynchronous PHP tasks.

It is quite easy on Linux, but I'm looking for a method that works on Windows too.

I want it to be simple, as it should be. No artillery, no SQL queueing, no again and again installing stuff… I just want to run a goddamn asynchronous task.

So I tried the Symfony Process Component. Problem is, running the task synchronously works fine, but when running it asynchronously it exits along the main script.

Is there a way to fix this?


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));
}

result

script (A) : 02:36:10 491
script (B) : 02:36:10 511
subscript (A) : 02:36:10 581
// subscript (B) is missing
Community
  • 1
  • 1
Gras Double
  • 15,901
  • 8
  • 56
  • 54

3 Answers3

1

Main script must be waiting when async process will be completed. Try this code:

$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());
}
Mikhail
  • 452
  • 3
  • 6
  • 1
    this makes it basically similar to run how does this get up votes – Buddhi741 May 23 '18 at 00:29
  • 1
    If main script must wait, then it's synchronous process. Your code is senseless, it will result in "max execution time" error. Dont get why people voting up – ymakux Aug 17 '20 at 11:58
1

If php supports fpm for Windows, you can listen to kernel.terminate event to provide all expensive tasks after response has been sent.

Service:

app.some_listener:
    class: SomeBundle\EventListener\SomeListener
    tags:
        - { name: kernel.event_listener, event: kernel.terminate, method: onKernelTerminate }

Listener:

<?php

namespace SomeBundle\EventListener;

use Symfony\Component\HttpKernel\Event\PostResponseEvent;

class SomeListener
{
    public function onKernelTerminate(PostResponseEvent $event)
    {
        // provide time consuming tasks here
    }
}
Community
  • 1
  • 1
  • Thanks for your interest :) Though, I'm not using FastCGI and I was looking for a simple, portable solution. Apparently it's just not possible... I'll live with it. – Gras Double Jan 21 '16 at 23:14
0

Not the best solution, but:

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