Symfony - 在kernel.terminate上运行console命令

时间:2017-01-16 14:30:49

标签: console symfony background-process shell-exec

我已使用文件类型将swiftmailer配置为假脱机电子邮件。这是我的swiftmailer配置

swiftmailer:
    transport: "%mailer_transport%"
    host:      "%mailer_host%"
    username:  "%mailer_user%"
    password:  "%mailer_password%"
    spool:
        type: file
        path: "%kernel.root_dir%/../var/spool"

当我发送任何电子邮件时,它完全是假脱机。之后我运行以下命令发送电子邮件。

bin/console swiftmailer:spool:send --env=dev

根据Symfony documentation

the console command should be triggered by a cron job or scheduled task and run at a regular interval.

我的问题是,我不能使用crontab,因为cron可以配置至少1分钟的间隔,这是我买不起的。我希望在将响应发送回浏览器后立即执行后台进程,从而最大限度地减少假脱机的执行。

我尝试通过创建事件侦听器类并侦听kernel.terminate来解决此问题,并使用shell_execexec函数执行命令,以下是参考代码。< / p>

app.kernel.terminate.listener:
        arguments: ["@kernel"]
        class: AppBundle\EventListener\KernelTerminateListener
        tags:
            - { name: kernel.event_listener, event: kernel.terminate }

这是我的EventListener类

<?php

namespace AppBundle\EventListener;

use Symfony\Component\HttpKernel\Event\PostResponseEvent;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Exception\HttpExceptionInterface;
use Cocur\BackgroundProcess\BackgroundProcess;

class KernelTerminateListener
{
    protected $kernel;

    protected $console;

    public function __construct($kernel)
    {
        $this->kernel = $kernel;
        $this->console = $this->kernel->getRootDir().'/../bin/console ';
    }

    public function onKernelTerminate(PostResponseEvent $event)
    {
        $command = $this->console.'swiftmailer:spool:send --env='.$this->kernel->getEnvironment();
        shell_exec($command);
    }
}

我在这里尝试的是在bin/console swiftmailer:spool:send --env=dev事件上运行kernel.terminate,遗憾的是这不起作用,任何关于如何处理此问题的提示都表示赞赏。

谢谢。

3 个答案:

答案 0 :(得分:1)

请使用swift邮件程序的内存卷轴类型,它完全符合您的要求

  

当您使用假脱机将电子邮件存储到内存时,它们将在内核终止之前发送。 这意味着只有在整个请求执行时才会发送电子邮件,而不会发生任何未处理的异常或任何错误。要使用memory选项配置swiftmailer,请使用以下配置:

答案 1 :(得分:0)

不使用shel_exec而是使用进程组件,这将创建一个新进程,并在发送响应后执行命令。 shel_exec或exec将在相同的进程下执行,迫使内核等待完成请求(因为一旦父进程被终止,子进程也终止)。进程组件将创建一个新进程,在该命令下将执行。

use Symfony\Component\Process\Process;
....
....
....

public function onKernelTerminate(PostResponseEvent $event)
{
  $command = $this->console.'swiftmailer:spool:send --env=.'$this->kernel->getEnvironment().'> output.log 2> out.log &';
  $process = new Process($command);
  $process->run();
}

答案 2 :(得分:-1)

也许这是PHP的一个问题,我使用MAMP和OSX预装了PHP,基本上,我安装了两个php版本,并且出于某种原因,当我给出正确的PHP路径时,它工作,这是我的更新了我重命名为MailerSpoolListener的侦听器类

<?php

namespace AppBundle\EventListener;

use Symfony\Component\HttpKernel\Event\PostResponseEvent;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Exception\HttpExceptionInterface;
use Cocur\BackgroundProcess\BackgroundProcess;

class MailerSpoolListener
{
    protected $kernel;

    protected $php;

    protected $console;

    protected $env;

    protected $command;

    protected $muteOutput;

    public function __construct($kernel)
    {
        $this->kernel = $kernel;
        $this->php = PHP_BINDIR.'/php';
        $this->command = 'swiftmailer:spool:send';
        $this->console = $this->kernel->getRootDir().'/../bin/console';
        $this->env = $this->kernel->getEnvironment();
        $this->muteOutput = '> /dev/null 2>/dev/null &';
    }

    public function onKernelTerminate(PostResponseEvent $event)
    {
        $command = $this->php.' '.$this->console.' '.$this->command.' --env='.$this->env.' '.$this->muteOutput;
        $process = shell_exec($command);
    }
}