Перехват терминальных завершений / выходов с помощью Symfony Console (CTRL+C)

Я создал команду, которая запускает загрузку файлов через Интернет, однако, поскольку эти файлы должны обрабатываться другим компонентом, мы должны убедиться, что каждый файл, который был загружен и не был изменен в течение последних 10 секунд, правильное видео и не повреждено / частично загружено.

По этой причине нам нужно найти способ перехватить комбинации клавиш CTRL+C или команды и очистить любой подходящий файл, который не был успешно загружен.

Это то, что я пытался до сих пор, используя symfony/console а также symfony/event-dispatcher:

#!/usr/bin/env php
<?php

require_once(__DIR__ . '/../vendor/autoload.php');

use Symfony\Component\Console\Application;
use Symfony\Component\Console\ConsoleEvents;
use Symfony\Component\Console\Event\ConsoleTerminateEvent;
use Symfony\Component\EventDispatcher\EventDispatcher;
use ImportExport\Console\ImportCommand;
use Monolog\Logger;

$dotenv = new Dotenv\Dotenv(__DIR__ . '/../');
$dotenv->load();

$logger = new Logger('console');

$dispatcher = new EventDispatcher();
$dispatcher->addListener(ConsoleEvents::TERMINATE, function (ConsoleTerminateEvent $event) {
    // gets the command that has been executed
    $command = $event->getCommand();

    var_dump($command);
});

$application = new Application("Import-Export System", 'v0.1.0-ALPHA');
$application->add(new ImportCommand($logger));
$application->setDispatcher($dispatcher);
$application->run();

Тем не менее var_dump() никогда не отображается в консоли, если я делаю CTRL+C.

Предложения?

2 ответа

Решение

Когда вы делаете CTRL+C, это на самом деле SIGINT что отправляется, а не SIGTERM, Лучший способ, о котором я могу подумать, - это зарегистрировать обработчик на http://php.net/manual/en/function.pcntl-signal.php и отправить сигнал с pcntl_signal_dispatch, пример:

pcntl_signal(SIGINT,'sigIntHandler');

function sigIntHandler() {
  // Do some stuff
}

Конечно, вам нужно настроить его в соответствии с вашими потребностями. Обратите внимание, что вы также можете отложить методы класса внутри ваших команд, так что вы можете, например, создать AbstractCommand с универсальным sigIntHandler() и зарегистрируйте его в конструкторе:

pcntl_signal(SIGINT, [$this, 'sigIntHandler']);

Тогда используйте pcntl_signal_dispatch() например, в цикле вашей команды (она должна вызываться в каждой итерации).

Начиная с Symfony 5.2, это встроенная функция: https://symfony.com/blog/new-in-symfony-5-2-console-signals

Реализуйте интерфейс (SignalableCommandInterface), подпишитесь на сигналы и обработайте их:

      public function handleSignal(int $signal)
{
    if (SIGINT === $signal) {
        // ...
    }

    // ...
}
Другие вопросы по тегам