• Блог
  • Параллельная обработка записей

Периодически на сайте сообщества появляются вопросы, как обойти лимит на время выполнения скрипта при обработке большого количества записей. Варианты есть. Одни больше подходят, другие меньше. Но все они требуют доработки под конкретные задачи. Я хочу в дополнение к этим вариантам добавить ещё один, основанный на использовании библиотеки modHelpers, а конкретно — функции exec_bg_script(). Пример я снял на видео. Так что устраивайтесь по-удобнее.

Последовательное добавление ресурсов

// Получаем все корневые ресурсы, в которые будут добавлены новые ресурсы
$q = $modx->newQuery('modResource', ['parent' => 0]);
$q->select('id');
if ($q->prepare() && $q->stmt->execute()) {
    $resources = $q->stmt->fetchAll(PDO::FETCH_ASSOC);
}

// Для каждого родительского ресурса добавляется 100 зависимых ресурсов
foreach($resources as $resource) {
    for ($i = 1; $i <= 100; $i++) {
        $new = $modx->newObject('modResource', [
            'pagetitle' => 'Ресурс ' . $resource['id'] . $i,
            'pagetitle' => 'Ресурс ' . $resource['id'] . $i,
            'longtitle' => 'Ресурс ' . $resource['id'] . $i,
            'description' => faker(['text'=>[300]]),
            'introtext' => faker(['text'=>[500]]),
            'content' => '<p>' . faker(['text'=>[800]]) . '</p>',
            'alias' => 'resource' . $resource['id'] . $i,
            'parent' => $resource['id'],
        ]);
        if (!$new->save()) {
            echo_br('Ошибка');
        }
    }
}

Параллельное добавление ресурсов

Скрипт, запускающий указанный php файл myscript.php параллельно.
// Получаем все корневые ресурсы, в которые будут добавлены новые ресурсы
$q = $modx->newQuery('modResource', ['parent' => 0]);
$q->select('id');
if ($q->prepare() && $q->stmt->execute()) {
    $resources = $q->stmt->fetchAll(PDO::FETCH_ASSOC);
}

// Для каждого родительского ресурса добавляется 100 зависимых ресурсов
foreach($resources as $resource) {
    echo_br('Категория ' . $resource['id']);
    exec_bg_script('myscript.php', ['token' => '123456789', 'id' => $resource['id']]);
}
Код файла myscript.php.
<?php
# Пример коннектора (точки входа)

// Пропускаем только запросы из командной строки (если нужно) 
if (php_sapi_name() != 'cli') {
    header("HTTP/1.1 404 Not Found");
    exit();
}

// Инициализируем MODX
define('MODX_API_MODE', true);
require_once __DIR__.'/index.php';
$modx->getService('error','error.modError');

// Получаем массив параметров из командой строки
$_REQUEST = get_exec_args();

// Проверка безопасности
if (empty($_REQUEST['token']) || $_REQUEST['token'] !== '123456789') {
    header("HTTP/1.1 403 Forbidden");
    die('Access denied');
}

for ($i = 1; $i <= 100; $i++) {
    $new = $modx->newObject('modResource', [
            'pagetitle' => 'Ресурс ' . $_REQUEST['id'] . $i,
            'longtitle' => 'Ресурс ' . $_REQUEST['id'] . $i,
            'description' => faker(['text'=>[300]]),
            'introtext' => faker(['text'=>[500]]),
            'content' => '<p>' . faker(['text'=>[800]]) . '</p>',
            'alias' => 'resource' . $_REQUEST['id'] . $i,
            'parent' => $_REQUEST['id'],
        ]);

    if (!$new->save()) {
        // Выводим массив с параметрами запроса
        $modx->log(1, 'Ошибка при добавлении ресурсов для категории ' .  $_REQUEST['id'] . '.');
    }
}
$modx->log(1, 'Ресурсы для категории ' .  $_REQUEST['id'] . ' добавлены.');

П.С. Лучше всего этот скрипт положить в закрытую папку core. Таким образом он будет закрыт от внешнего доступа, что положительно влияет на безопасность. В этом случае токен можно не использовать, как и проверку на запуск из командной строки.

0   1847

Комментарии ()

    Вы должны авторизоваться, чтобы оставлять комментарии.

    Выделите опечатку и нажмите Ctrl + Enter, чтобы отправить сообщение об ошибке.