Изящно останавливая генераторы

Рассмотрим следующий код:

Loop::run(function() {
    Loop::onSignal(SIGINT, function () use ($w) {
        echo "Caught SIGINT! exiting ...\n";
        Loop::stop();
    });

    while([$jobId, $jobData] = yield $beanstalk->reserve()) {
        $response = yield $httpClient->send($request);
        yield $beanstalk->delete($jobId);
    }
});

Насколько я понимаю, когда этот код получает SIGINTОбратный звонок в Loop::onSignal будет выполнен на следующем тике, и, таким образом, цикл остановится и программа завершится.

В этом случае, если $httpClient->send() в while цикл еще не завершен, следующая строка не будет выполнена, а сообщение Beanstalk не будет удалено. Затем задание Beanstalk будет повторено, и это может вызвать проблему, если HTTP-запрос не идемпотентен. Мы можем заменить HTTP-запрос вызовом из базы данных.

Есть ли способ сказать циклу, чтобы он не выполнял новые генераторы и ждал завершения работы генераторов, когда SIGINT получил?

Я пытался обернуть голову вокруг этого, но не смог найти решение.

1 ответ

Такой опции нет, но вы можете легко достичь желаемого в простом приложении, добавив флаг.

Loop::run(function() {
    $running = true;

    Loop::onSignal(SIGINT, function () use (&$running) {
        echo "Caught SIGINT! exiting ...\n";
        $running = false;
    });

    while($running && [$jobId, $jobData] = yield $beanstalk->reserve()) {
        $response = yield $httpClient->send($request);
        yield $beanstalk->delete($jobId);
    }
});

Это просто продолжит текущий запрос и завершит работу позже.

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