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
1
  • In short: run commands in background using exec(). Commented Aug 17, 2020 at 12:01

3 Answers 3

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());
}
Sign up to request clarification or add additional context in comments.

2 Comments

this makes it basically similar to run how does this get up votes
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
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
    }
}

1 Comment

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.
0

Not the best solution, but:

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

1 Comment

How does it differ form simple exec()?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.