Перехват терминальных завершений/выходов с помощью 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.

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


person GiamPy    schedule 27.02.2018    source источник
comment
Вы также можете проверить этот вопрос: > stackoverflow.com/questions/23479107/   -  person etudor    schedule 27.02.2018


Ответы (1)


Когда вы нажимаете 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(), например, в цикле вашей команды (его нужно вызывать на каждой итерации).

person Jakub Krawczyk    schedule 27.02.2018
comment
Однако это мешает мне использовать CTRL + C. Команда продолжает работать, даже если я прерываю ее. - person GiamPy; 27.02.2018
comment
Это обработчик, поэтому он должен обрабатывать сигнал так, как вы хотите. Если вы хотите что-то сделать, а затем все же остановить выполнение, вы можете использовать функцию exit() или die(). - person Jakub Krawczyk; 27.02.2018
comment
pcntl_signal_dispatch() необходимо запускать после каждой задачи для запуска обработчиков сигналов, это означает, что если будет отправлена ​​команда SIGINT, обработчики не будут выполняться до тех пор, пока не будет запущена pcntl_signal_dispatch(). Это означает, что я не могу прервать процесс посреди чего-либо. - person GiamPy; 27.02.2018
comment
Это зависит от того, что вы делаете в задаче, но если ваши операции блокируют ввод-вывод, то, конечно, вам нужно дождаться завершения задачи перед вызовом обработчика. - person Jakub Krawczyk; 27.02.2018