Php 中止和恢复Symfony控制台命令
我有一个Php 中止和恢复Symfony控制台命令,php,symfony,console,Php,Symfony,Console,我有一个Symfony Console命令,它迭代一个潜在的大型项目集合,并对每个项目执行一项任务。由于集合可能很大,因此该命令可能需要很长时间才能运行(小时)。命令完成后,将显示一些统计信息 我希望能够以一种好的方式中止该命令。现在,如果我中止它(即在CLI中使用ctrl+c),则没有统计信息摘要,也无法输出恢复命令所需的参数。另一个问题是,命令可能在处理一个项目的过程中被终止——如果它只能在处理项之间终止,那就更好了。 那么,有没有一种方法可以告诉命令“尽快很好地中止”,或者将ctrl+c命
Symfony Console
命令,它迭代一个潜在的大型项目集合,并对每个项目执行一项任务。由于集合可能很大,因此该命令可能需要很长时间才能运行(小时)。命令完成后,将显示一些统计信息
我希望能够以一种好的方式中止该命令。现在,如果我中止它(即在CLI中使用ctrl+c),则没有统计信息摘要,也无法输出恢复命令所需的参数。另一个问题是,命令可能在处理一个项目的过程中被终止——如果它只能在处理项之间终止,那就更好了。
那么,有没有一种方法可以告诉命令“尽快很好地中止”,或者将ctrl+c命令解释为这样
我试着使用ConsoleEvents::TERMINATE
事件,尽管此事件的处理程序仅在命令完成时启动,而不是在我按住ctrl+c键时启动。我还没能找到关于发出这种可恢复命令的更多信息。你应该看看的是,谷歌的信号处理。它的execute
方法只是通过pcntl\u signal()
函数调用链接一些回调。一个常见的情况应该是这样的:
<?php
use Symfony\Bundle\FrameworkBundle\Command\ContainerAwareCommand as Command;
class YourCommand extends Command
{
protected function execute(InputInterface $input, OutputInterface $output)
{
pcntl_signal(SIGTERM, array(&$this, 'stopCommand', $output));
pcntl_signal(SIGINT, array(&$this, 'stopCommand', $output));
pcntl_signal(SIGHUP, array(&$this, 'restartCommand', $output));
// The real execute method body
}
public function stopCommand(OutputInterface $output)
{
$output->writeln('Stopping');
// Do what you need to stop your process
}
public function restartCommand(OutputInterface $output)
{
$output->writeln('Restarting');
// Do what you need to restart your process
}
}
这对我来说很有用。在实际执行信号处理程序之前,需要调用pcntl\u signal\u dispatch
。没有它,所有任务都将首先完成
<?php
use Symfony\Component\Console\Command\Command;
class YourCommand extends Command
{
protected function execute(InputInterface $input, OutputInterface $output)
{
pcntl_signal(SIGTERM, [$this, 'stopCommand']);
pcntl_signal(SIGINT, [$this, 'stopCommand']);
$this->shouldStop = false;
foreach ( $this->tasks as $task )
{
pcntl_signal_dispatch();
if ( $this->shouldStop ) break;
$task->execute();
}
$this->showSomeStats($output);
}
public function stopCommand()
{
$this->shouldStop = true;
}
}
答案比需要的更复杂。当然,您可以注册POSIX信号处理程序,但是如果只需要处理基本中断之类的信号,那么您应该在命令上定义析构函数
class YourCommand extends Command
{
// Other code goes here.
__destruct()
{
$this->shouldStop = true;
}
}
您希望注册POSIX信号的情况是针对SIGCONT
信号,它可以处理已停止进程的恢复(SIGSTOP
)
另一种情况是,您希望每个信号的行为都不同;然而,在大多数情况下,SIGINT
和SIGTERM
以及少数其他人将使用相同的“OMG进程已终止”操作注册
除了这些示例之外,不需要注册信号事件。这就是析构函数存在的原因
您甚至可以使用\uu destruct
方法扩展Symfony的base命令
类,该方法将自动为每个命令提供清理功能;如果一个特定的命令需要额外的操作,只需覆盖它。我认为通过将您的输入作为交互式输入,您将能够解决这个问题,但我不知道您应该如何准确地实现它,以便在特定的按键时终止该命令,并提供此链接可能有帮助的统计信息[逐步创建交互式命令或您可以在命令中检查事件侦听器,并根据该命令终止您的命令[非常感谢,这和上面的评论让我找到了解决方案。您的示例缺少对pcntl_signal_dispatch的调用,并且还有一个语法错误:回调数组只有两个元素。您不能在这些元素之后插入参数。@JeroenDeDauw,哦,这是一些伪代码,我的错:)这就是我要找的,谢谢,但有一个提示:您我们需要设置declare(ticks=1);谢谢,由于PHP7.1,您还可以通过执行pcntl\u async\u signals(true);
@createproblem如果在循环中使用pcntl\u signal\u dispatch()
或pcntl\u async\u signals(true)
,则不需要declare(ticks=1)
。