Советы PHP-разработчика

Блог содержащий короткие заметки касающиеся программирования для web.

Docker завершает остановку PHP контейнера с ошибкой Exited (137) для `yii queue/listen`

Разрыв коннекта с ошибкой packet_write_wait: Connection to xxx port 22: Broken pipe

Есть сайт на Yii framework 2 в docker и отдельный контейнер с php-cli, который запускает php yii queue/listen, слушает очередь и выполняет фоновые задачи. При выполнение docker container stop CONTAINER_NAME остановка завершается с кодом ошибки 137.

Это может быть проблемой если на момент остановки что-то находится в обработке. Задача может выполниться частично и запуститься повторно после перезапуска. Например, если мы рассылаем пачку писем пользователям и сохраняем состояние только в конце, то некоторые пользователи получат по 2 письма.

Дело в том, что при остановке контейнера докер сначала отправляет SIGTERM ("просьбу" завершить процесс) и ждет 10 секунд, чтобы контейнер корректно завершил все свои дела. Если остановки не произошло, то докер посылает SIGKILL ("приказ", который нельзя проигнорировать) и работа завершается принудительно с кодом 137.

Для получения сигналов в php необходимо установить модуль управления процессами pcntl при сборке своего контейнера:

RUN docker-php-ext-install pcntl

И на этом можно остановиться, так как процесс остановки queue/listen уже реализован внутри yii\queue\cli\SignalLoop.

Важно. Если задачи в очереди могут выполняться долго, то при запуске контейнера необходимо указать параметр stop_grace_period и время в формате 1h5m30s. Это время ожидание между SIGTERM и SIGKILL. Сделайте небольшой запас по времени, чтобы быть уверенным в корректном завершении фоновой задачи.

  • 2025-12-02 09:46:59