Comments 28
Кейсы с блокировкой требуются в крон-задачах и почти никогда при обычных запусках. Если учитывать это — думаю лучшим вариантом было бы просто написать простенький адаптер под уже существующее несколько лет решение, которое использует симфонийский консольный компонент: https://github.com/illuminate/console
Оно уже покрывает все проблемы, озвученные в статье.
$sheduler->command('some')->everyFiveMinute()->withoutOverlap();
М?
Да и в моем случае это не крон.
Я подозреваю, что вполне сопоставимо будет. Все команды уже отнаследованы от симфони, всё что потребуется — это написать бандл, который их будет регать в сервисах с нужным тегом.
С другой стороны — согласен, нужен ресёрч, я сходу не могу представить как добавить сервис в "зафризенный" симфонёвый контейнер, кроме как выполнить ещё раз его билд. Да и возможно могут возникнуть проблемы с контейнером, в симфони у него нет функционала двойной диспатчеризации и получения сервиса по интерфейсу, только сервислокация и автовайринг.
Короче, да, согласен, надо смотреть. В качестве быстрого решения на коленке — ваш вариант оправдан более чем.+
public function lock($name)
{
$file = $this->getFilePath($name);
if ($this->fileSystem->exists($file)) {
return false;
}
$this->fileSystem->touch($file);
return true;
}
Если команда сломалась и ваш лок-файл остался, то команда больше никогда не будет вызвана.
Например, если процесс будет убит из консоли. Или выключится электричество. Или произойдет какой-то сбой на сервере.
В моем случае есть сборщик мусора, который проверяет «залежавшиеся» лок-файлы и сообщает о том, что это подозрительно. Как ни крути — при солидном кол-ве серверов такое бывает частенько, чем-то жертвовать приходится.
Подумаю над Вашим замечанием, может быть придет идея, спасибо.
Но, в принципе, это можно поправить.
А зачем в абстрактном классе
/** @var string */
protected $name = null;
?
Можно же использовать \Symfony\Component\Console\Command\Command::getName
Я стесняюсь спросить, а что это за юс-кейсы такие странные? Один процесс на N серверов?
Что это таким путём надо делать? Не проще ли это порешать очередью, где можно сколько угодно консумеров запускать, но отрабатывать они могут по одному друг за другом?
Безусловно, в стартап-ах и молодых проектах есть возможность не задумываться о таком, но мои статьи в основном связаны с проектами-тинейджерами, где все не так просто.
@jced и всё-таки что за юс-кейсы то такие?
Невозможность установки серверов очередей.
Наше вам сочувствие.
Я писал микросервис для лицо-распознавания на питонах и вместо скучного REST'а сделал AMQP-консумера. Это оказалось просто и эффективно. Особенно помогло в горизонтальном масштабировании — можно было запустить кучу консумеров где угодно и задачи отрабатывались быстрее.
Как мне показалось — один файл (без учета интерфейса), довольно «изящно», решил, может есть такие же как я, застрявшие в 20 веке и им тоже пригодится :)
Плюсы: Простота, не нужно подчищать lock файлы, так как в случае падения/завершения команды блокировка автоматически удалится. Также есть возможность ожидания освобождение блокировки.
Минусы: не дружит с репликацией.
pgrep %cmd% || %cmd%
не пробовали?
Блокировка дубликатов Symfony Сommand