Ошибки подключения в разветвленных процессах PHP

У меня есть PHP-скрипт, который берет N документов из MongoDB, разветвляет процесс на K дочерних процессов PHP, каждый процесс делает что-то с каждым документом и пытается обновить информацию о документе (см. код ниже).

В моем локальном окружении (Docker) все круто, но на сервере (там нет Docker) иногда во время цикла происходят странные вещи...

Случайным образом все разветвленные процессы не могут подключиться к MongoDB. Команда updateOne возвращает ошибку:

"Failed to send "update" command with database "databasename": Invalid reply from server. in /vendor/mongodb/mongodb/src/Operation/Update.php on line 158".

Это происходит со всеми процессами одновременно только для одной (или нескольких) случайных итераций цикла. Когда каждый процесс переходит на другую итерацию (берёт следующий документ) -- всё снова в порядке. Я делаю 5 попыток записи в MongoDB.

Каждая попытка связана с задержка +1 сек. предыдущей, поэтому первая попытка выполняется немедленно, если возникнет какое-либо исключение -- подождите секунду и повторите попытку, следующая попытка будет через 2 секунды и так далее. Но это не помогает, все эти 5 попыток ломаются.

Это не проблема mongoDB, его журнал пуст, и он даже ничего не получает от PHP, когда происходит ошибка.

Также я признал, что чем больше одновременных процессов я запускаю, тем чаще возникают ошибки.

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

Может быть, у PHP есть какая-то конфигурация для этого? Какие-то ограничения памяти или что-то в этом роде...

Я использую PHP версии 7.1.30 МонгоДБ v 3.2.16 Пакет PHP mongodb/mongodb v 1.1.2

<?php

$processesAmount = 5;
$documents = $this->mongoResource->getDocuments();

for ($processNumber = 0; $processNumber < $processesAmount; $processNumber++) {
    // create child process
    $pid = pcntl_fork();

    // do not create new processes in child processes
    if ($pid === 0) {
        break;
    }

    if ($pid === -1) {
       // some errors catching staff here...
    }
    else if ($pid === 0) {
        // create new MongoDB connection
    }
    else { 
        // Protect against Zombie children
        // main process waits before all child processes end
        for ($i = 0; $i < $processesAmount; $i++) {
            pcntl_wait($status);
        }
        return null;
    }

    // spread documents to each process without duplicates
    for ($i = $processNumber; $i < count($documents); $i += $processesAmount) {
        $newDocumentData = $this->doSomeStaffWithDocument($documents[$i]);
        $this->mongoResource->updateDocument($documents[$i], $newDocumentData);
    }
}
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Symfony Station Communiqué - 7 июля 2023 г
Symfony Station Communiqué - 7 июля 2023 г
Это коммюнике первоначально появилось на Symfony Station .
Оживление вашего приложения Laravel: Понимание режима обслуживания
Оживление вашего приложения Laravel: Понимание режима обслуживания
Здравствуйте, разработчики! В сегодняшней статье мы рассмотрим важный аспект управления приложениями, который часто упускается из виду в суете...
Установка и настройка Nginx и PHP на Ubuntu-сервере
Установка и настройка Nginx и PHP на Ubuntu-сервере
В этот раз я сделаю руководство по установке и настройке nginx и php на Ubuntu OS.
Коллекции в Laravel более простым способом
Коллекции в Laravel более простым способом
Привет, читатели, сегодня мы узнаем о коллекциях. В Laravel коллекции - это способ манипулировать массивами и играть с массивами данных. Благодаря...
Как установить PHP на Mac
Как установить PHP на Mac
PHP - это популярный язык программирования, который используется для разработки веб-приложений. Если вы используете Mac и хотите разрабатывать...
2
0
96
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Здесь может быть много проблем, одна из которых заключается в том, что все процессы совместно используют 1 соединение с БД, и первый, кто подключается, затем отключается и уничтожает соединение для них всех. Проверьте второй пример в документации здесь: https://www.php.net/manual/en/ref.pcntl.php

Если это не поможет, то, как я читаю ваш код, часть «распространения» происходит в каждом процессе, когда это должно происходить один раз. Разве вы не должны помещать «работу» в дочерний раздел, как показано ниже?

$processesAmount = 5;
$documents = $this->mongoResource->getDocuments();
$numDocs = count($documents);
$i = 0;
$children = [];

    for ($processNumber = 0; $processNumber < $processesAmount; $processNumber++) {
        // create child
        $pid = pcntl_fork();

        if ($pid === -1) {
           // some errors catching staff here...
        } else if ($pid) {
            //parent
            $children[] = $pid;
        } else { 
            //child
           while (!empty($documents) && $i <= $numDocs) {
               $i += $processNumber;
               $doc = $documents[$i] ?? null;
               unset($documents[$i]);
               $newDocumentData = $this->doSomeStaffWithDocument($doc);
               $this->mongoResource->updateDocument($doc, $newDocumentData);
           }
        }
    }

    //protect against zombies and wait for parent
    //children is always empty unless in parent
    while (!empty($children)) {  

        foreach ($children as $key => $pid) {

            $status = null;

            $res = pcntl_waitpid($pid, $status, WNOHANG);

            if ($res == -1 || $res > 0) {   //if the process has already exited
                unset($children[$key]);
            }

        }

    }

}

Спасибо за ваш ответ! Проблема была с подключением. Глупый я! :) У меня есть синглтон, который удерживает соединение, и сервисы, которые сохраняют состояние соединения. Я создавал службу, а затем создавал дочерние процессы и обновлял соединение в синглтоне, но не в службе. ха-ха

Yurii Makukha 04.07.2019 17:30

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