Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Schedule runInBackground not fired #27541

Closed
oriceon opened this issue Feb 15, 2019 · 14 comments · Fixed by #29826
Closed

Schedule runInBackground not fired #27541

oriceon opened this issue Feb 15, 2019 · 14 comments · Fixed by #29826
Labels

Comments

@oriceon
Copy link
Contributor

oriceon commented Feb 15, 2019

  • Laravel Version: 5.7.26
  • PHP Version: 7.3.2
  • Database Driver & Version:

Description:

I`m on Windows 10 x64 System and trying to run a schedule, from cli, to run in background.
Running scheduled command is displayed but it does not fired.
If i copying it and running manualy it work like it should.
Any ideea what could be?!

Steps To Reproduce:

$schedule->command('my-command')->everyMinute()->runInBackground();

Running scheduled command: ("C:\php-7\php.exe" "artisan" my-command > "NUL" 2>&1 & "C:\php-7\php.exe" "artisan" schedule:finish "framework\schedule-47987621c9ff2fa8a91fa554f7471894a3325831") > "NUL" 2>&1 &

@driesvints
Copy link
Member

I'll need more info and/or code to debug this further. Please post relevant code like models, jobs, commands, notifications, events, listeners, controller methods, routes, etc. You may use https://paste.laravel.io to post larger snippets or just reply with shorter code snippets. Thanks!

@oriceon
Copy link
Contributor Author

oriceon commented Feb 15, 2019

Hi @driesvints . It`s just a simple command run in Kernel.php and a normal command file that write a x.txt in public_path with current date time.

As i told, after i run php artisan schedule:run i receive message regarding running scheduled command but nothing happened (no file is writed to public_path as it should by the command function...).

So, if i copy / paste the command outputed by schedule:run, everything is working as expected.
Command will be executed.

@driesvints
Copy link
Member

I don't have the means to test on Windows myself so hoping that someone on windows might be of help here. In the meantime you might have more luck on one of the support channels below. If you do confirm this as a bug please report back.

@oriceon
Copy link
Contributor Author

oriceon commented Feb 15, 2019

I'll try tomorrow to install a fresh Laravel app, maybe on other Windows machine also and do this simpliest schedule / command test. And i`ll came back with news.

@oriceon
Copy link
Contributor Author

oriceon commented Feb 19, 2019

@driesvints I come back with some conclusions. I installed a fresh laravel app and created a new command.
And get same behaviour. Not runned on background.

<?php

namespace App\Console\Commands;

use Illuminate\Console\Command;

class MyCommand extends Command
{
    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $signature = 'my:command';

    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = 'Command description';

    /**
     * Create a new command instance.
     *
     * @return void
     */
    public function __construct()
    {
        parent::__construct();
    }

    /**
     * Execute the console command.
     *
     * @return mixed
     */
    public function handle()
    {
        \File::append(public_path('x.txt'), date('Y-m-d H:i:s') . "\r\n");
    }
}

and in Kernel i have:

 protected function schedule(Schedule $schedule)
 {
     $schedule->command('my:command')
         ->everyMinute()
         ->runInBackground();
 }

On php artisan schedule:run i get:

Running scheduled command: ("C:\php\php-7\php.exe" "artisan" my:command > "NUL" 2>&1 & "C:\php\php-7\php.exe" "artisan" schedule:finish "framework\schedule-50fc191aea7ac0d2b86a23a08b17304051384890") > "NUL" 2>&1 &

But command is not Fired!

If i manualy run that outputed command, will executed it...

And to exclude my PC, i installed same stuff on other clean Windows 10 PC and is same..

@Travis-Britz
Copy link

Travis-Britz commented Feb 27, 2019

I'm running into the same issue. Laravel 5.7.28/PHP 7.2.7/Win10

Schedule:

$schedule->command('background')->everyMinute()->runInBackground();

background command:

public function handle()
{
    logger()->debug('ran background command');
}

Running schedule:run from the console I get:

Running scheduled command: ("C:\Program Files\PHP\v7.2\php.exe" "artisan" background > "NUL" 2>&1 & "C:\Program Files\PHP\v7.2\php.exe" "artisan" schedule:finish "framework\schedule-77231983319c8e5f12f54d6ce91f8dc5290b559a") > "NUL" 2>&1 &

However, the command does not run.

I don't think this is the correct syntax for spawning a background process on windows, based on this stackoverflow answer. I don't have much experience here, so I can't say for certain.

@Travis-Britz
Copy link

Travis-Britz commented Feb 27, 2019

Additionally, since Symfony Process spawns each process under cmd /c (I think the full line is cmd /V:ON /E:ON /D /C (<command>)), I'm starting to wonder if the problem is related to using parenthesis for command grouping?

When I test in my (cmd.exe) terminal, this doesn't seem to work:

cmd /c (command1 & command2)

(where command1 and command2 are the respective artisan commands from the schedule:run console output shown above)

but using quotes as suggested in a comment here does appear to work:

cmd /c "(command1 & command2)" 

I haven't dug deep enough into the Laravel and Symfony Process combination to know whether the grouped command is being quoted this way for cmd, but that might be something to investigate if anyone else knows more?

@oriceon
Copy link
Contributor Author

oriceon commented Mar 1, 2019

Ping.

@driesvints
Copy link
Member

@Travis-Britz @oriceon currently a bit swamped and still no option to test on Windows. If you one of you two can whip up a PR with a fix, send it in and the other one confirm it we could merge that in.

@oriceon
Copy link
Contributor Author

oriceon commented Mar 6, 2019

@Travis-Britz sure, it works with quotes but still not run as async. Does not respect that >NUL parameter..

For async it necessary start /B, and is fired OK from a cli.

start /B cmd /V:ON /E:ON /D /C "("C:\php-7\php.exe" "C:\php-7\test1.php" && "C:\php-7\php.exe" "C:\php-7\test2.php")" > NUL &

So, it`s about Symfony Process.

I changed \vendor\symfony\process\Process.php in prepareWindowsCommandLine method:

$cmd = 'start /B cmd /V:ON /E:ON /D /C "('.str_replace("\n", ' ', $cmd).')"';

Then fired with:

$command = '"C:\php-7\php.exe" "C:\php-7\test1.php" && "C:\php-7\php.exe" "C:\php-7\test2.php"';

$process = Process::fromShellCommandline($command, base_path(), null, null, null)->start();

but if i run, i get proc_open(): CreateProcess failed, error code - 2

Now, if i set $options['bypass_shell'] = true; to false, will fire and execute async as it should...

Why with bypass_shell false get that error code ? As i found, it means ERROR_FILE_NOT_FOUND The system cannot find the file specified..

*** bypass_shell (windows only): bypass cmd.exe shell when set to TRUE

@WorldSeso7
Copy link
Contributor

Same issue for me!

@WorldSeso7
Copy link
Contributor

Same issue for me!

I found I workaround I'm using that works (for my needs)
I'm using
$schedule->exec('start /b php artisan command:name')->everyMinute();
instead of
$schedule->command('command:name')->everyMinute();

Inside the command I'm using a custom mutex (just install a third part package) that prevents the overlapping manually. In this way the after callback doesn't work as expected (it's run immediately, not waiting for task end), but I don't need it in this moment.

Hope this helps someone before the bug is resolved

@FredMK
Copy link

FredMK commented May 8, 2019

For me the problem solved after I deleted the last & character from this line:

.ProcessUtils::escapeArgument($event->getDefaultOutput()).' 2>&1 &'

Before: .ProcessUtils::escapeArgument($event->getDefaultOutput()).' 2>&1 &'
After: .ProcessUtils::escapeArgument($event->getDefaultOutput()).' 2>&1 '

Sadly as far as I can see the runInBackground() is running the command as a foreground process on Windows.
I put sleep(10) in my code, and the schedule command just wait 10 seconds before moving on to the next job.

@islandblaze
Copy link

islandblaze commented Jul 9, 2019

Guys, I made a fix that works for me on windows to run artisan commands in the background.

// @islandblaze: Fix for Windows
if(windows_os()) {
  return 'start /b cmd /c "(' . $event->command . ' & ' . $finished.')' . $redirect . $output . ' 2>&1"';
}

I added a check for windows platform and executed the command in a new background process which will also notify Laravel once it's completed (via php artisan schedule:finish {id}). This also redirects any output from $schedulingEvent->then(Closure) to the same destination defined in $schedulingEvent->sendOutputTo($outputPath).

I cloned Illuminate\Console\Scheduling\CommandBuilder and added an alias in config/app.php to replace the original class with my customized clone App\VendorCustom\Illuminate\Console\Scheduling\CommandBuilder

// config/app.php
'aliases' => [
  ...
  'Illuminate\Console\Scheduling\CommandBuilder' => 
  App\VendorCustom\Illuminate\Console\Scheduling\CommandBuilder::class,
],

return $this->ensureCorrectUser($event,
'('.$event->command.$redirect.$output.' 2>&1 '.(windows_os() ? '&' : ';').' '.$finished.') > '
.ProcessUtils::escapeArgument($event->getDefaultOutput()).' 2>&1 &'
);

App\VendorCustom\Illuminate\Console\Scheduling\CommandBuilder:

...
protected function buildBackgroundCommand(Event $event)
{
  $output = ProcessUtils::escapeArgument($event->output);
  $redirect = $event->shouldAppendOutput ? ' >> ' : ' > ';
  $finished = Application::formatCommandString('schedule:finish').' "'.$event->mutexName().'"';

  // @islandblaze: Fix for Windows
  if(windows_os()) {
    return 'start /b cmd /c "(' . $event->command . ' & ' . $finished.')' . $redirect . $output . ' 2>&1"';
  }

  // Original return statement for non-windows platforms
  return $this->ensureCorrectUser($event, 
    '('.$event->command.$redirect.$output.' 2>&1 '.(windows_os() ? '&' : ';').' '.$finished.') > ' 
    .ProcessUtils::escapeArgument($event->getDefaultOutput()).' 2>&1 &' 
  );
}
...

I hope this helps someone. Cheers!

taylorotwell pushed a commit that referenced this issue Sep 4, 2019
* fixed #27541

* fixed wrong style

* Update CHANGELOG-5.8.md

* Update CommandBuilder.php
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging a pull request may close this issue.

6 participants