Jump to main content Jump to doc navigation

Что такое modRegistry?

Сервис modRegistry, предоставляемый с ядром MODX Revolution, представляет собой простой сервис очереди сообщений, который разработчики могут использовать для самых разных целей. Он поставляется с реализацией файла и базы данных modRegister и может быть расширен для работы с пользовательскими или внешними реализациями очереди сообщений.

Сервис modRegistry может подключаться к любому количеству уникальных регистров. В каждом реестре подписаны определенные темы, и затем сообщения могут быть отправлены или прочитаны из темы.

Выбор реализации modRegister

MODX поставляется с двумя простыми реализациями modRegister. Один основан на файлах, а другой использует таблицы базы данных для хранения. У каждого есть свои преимущества и ограничения, которые вы должны рассмотреть, прежде чем определять, какой из них использовать для конкретной цели.

modFileRegister

Этот файловый регистр по умолчанию считывает и записывает сообщения в файлы в папке registry/ в папке MODX cache_path. Это отлично подходит для развертываний с одним сервером, которые не требуют большого трафика, когда запись и чтение в одной и той же теме могут происходить одновременно из нескольких клиентских запросов.

Вот как бы вы добавили конкретный файловый регистр с именем food:

<?php
$modx->getService('registry', 'registry.modRegistry');
$modx->registry->addRegister('food', 'registry.modFileRegister', array('directory' => 'food'));

Будь осторожен!: Очистка кэша вручную путем удаления всех файлов и папок в core/cache/ также удалит все существующие сообщения modFileRegister.

modDbRegister

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

Вот как бы вы добавили конкретный регистр базы данных с именем food:

<?php
$modx->getService('registry', 'registry.modRegistry');
$modx->registry->addRegister('food', 'registry.modDbRegister', array('directory' => 'food'));

Использование Registry API

Сервис modRegistry предоставляет очень простой API для работы с регистрами, подписки на темы и отправки/чтения сообщений внутри них.

Соединение

После того как вы получили modRegistry и инициализировали реализацию modRegister по вашему выбору, вы можете попытаться установить соединение с вашей очередью. Вот как вы можете подключиться к регистру food, который мы добавили в приведенных выше примерах.

<?php
$connected = $modx->registry->food->connect();

Если есть какие-либо проблемы с подключением к экземпляру регистра, возвращаемое значение будет false.

Подписка

После успешного подключения пришло время подписаться на тему для отправки или прочтения соответствующих сообщений. Давайте подпишемся на интересную тему о beer в нашем food реестре:

<?php
$modx->registry->food->subscribe("/beer/");

Это добавит тему "/beer/" в ваши подписки и сделает ее текущей темой. Темы похожи на относительные URI. Если вы укажете косую черту в начале, вы подписываетесь на тему из корня реестра. Никакая начальная косая черта не означает, что вы хотите подписаться на подтему текущей темы. Подписавшись хотя бы на одну тему, вы можете по своему желанию отправлять и читать сообщения из них.

Отправка сообщений

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

Отправка массива последовательных сообщений

Допустим, мы хотели отправить три сообщения, которые должны быть прочитаны в том же порядке, в котором они были отправлены. Мы просто предоставляем массив этих сообщений для того, чтобы прочитать их в:

<?php
$modx->registry->food->send("/beer/", array("beer1", "beer2", "beer3"));

Отправка массива именованных сообщений

Вы также можете предоставить ассоциативный массив для отправки сообщений с определенными ключами, которые будут считываться в соответствии с порядком ключей:

<?php
$modx->registry->food->send("/beer/", array("Heineken" => "not so good", "Pabst Blue Ribbon" => "rocks", "Molson Golden" => "ok for Canadian beer"));

Эти сообщения будут прочитаны в возрастающем алфавитном порядке или, в частности, по ключу.

Отправка одного сообщения

Иногда необходимо отправить одно сообщение без определенного ключа. Регистр MODX автоматически предоставляет основанный на времени ключ для сообщения, чтобы оно читалось в правильном основанном на времени порядке.

<?php
$modx->registry->food->send("/beer/", "It's Miller Time!", array('kill' => true));

Параметр kill указывает потребителям сообщений прекратить чтение любых дальнейших сообщений после прочтения сообщения с этим параметром.

Варианты отправки сообщений

delay

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

ttl

Параметр time to live указывает, сколько секунд сообщения остаются в очереди. После того, как сообщение изжило ttl, оно не будет включено в сообщения, возвращаемые операцией read().

kill

Если указано, когда получатель сообщения читает сообщение с установленным параметром, дальнейшие сообщения не будут считываться из очереди, независимо от других параметров чтения.

Чтение сообщений

Вы также можете читать сообщения из темы различными способами, используя опции, переданные методу read().

Опрос новых сообщений в теме

Наиболее распространенное использование реестра - поиск до x количества новых сообщений в любых подписанных темах. Здесь мы опрашиваем один раз до 5 новых сообщений в текущей теме, которая "/beer/":

<?php
$msgs = $modx->registry->food->read(array(
    'poll_limit' => 1,
    'msg_limit' => 5
));

Это возвращает массив сообщений, отправленных в очередь в порядке их чтения, без соответствующих ключей сообщений, независимо от того, были ли они указаны при отправке.

Options for Reading Messages

poll_limit

По умолчанию modRegister будет пытаться опрашивать сообщения, пока не встретится сообщение msg_limit, time_limit или сообщение с опцией kill. В большинстве случаев при использовании modRegister в веб-запросах это нежелательно. В большинстве случаев требуется установить этот параметр равным 1, поэтому операция чтения проверяет очередь только один раз на наличие сообщений и перемещается независимо от того, нажата ли команда msg_limit или time_limit. Эта опция полезна, если вы хотите настроить простой сервер опросов PHP, который проверяет сообщения и выполняет действия на их основе (например, в cronjob).

poll_interval

Настраиваемая задержка ожидания между опросами новых сообщений в секундах. По умолчанию не ограничено.

time_limit

Максимальное количество секунд для опроса новых сообщений при настройке нескольких попыток опроса (например: poll_limit != 1).

msg_limit

Максимальное количество сообщений для чтения из очереди. По умолчанию 5 сообщений.

remove_read

Указывает, следует ли удалять сообщение при прочтении.

include_keys (только MODX 2.2+)

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

Использование процессоров реестра

В дополнение к необработанному API MODX также предоставляет соединители и процессоры для отправки сообщений и чтения сообщений из раздела реестра. Они могут быть легко использованы компонентами, использующими метод runProcessor, или AJAX-запросами через соединители.

Отправка сообщений

Существует несколько параметров, которые управляют поведением процессора system/registry/register/send, который используется для отправки сообщения или нескольких сообщений в конкретную тему реестра. Эти параметры можно передать методу runProcessor как свойства или передать процессору через переменные REQUEST из соединителя.

  • register (обязательный) — Имя регистра для отправки сообщения.
  • topic (обязательный) — Тема для отправки сообщения в указанный регистр.
  • register_class (необязательный) — Определяет реализацию modRegister для использования, по умолчанию registry.modFileRegister.
  • message (необязательный) — Сообщения для отправки в тему регистрации. В MODX 2.2+ несколько сообщений могут быть отправлены с использованием json в качестве message_format.
  • message_key (необязательный, MODX 2.2+) — Дополнительный ключ сообщения, который может быть предоставлен для отправки именованного сообщения в тему. Если пусто, сообщению присваивается метка времени в качестве ключа.
  • message_format (необязательный, MODX 2.2+) — По умолчанию это строка, которая просто отправляет сообщение в виде строки. Если для этого параметра установлено значение json, сообщение перед отправкой преобразуется в PHP, что позволяет отправлять несколько или более сложных сообщений.

Reading Messages

Чтение сообщений с system/registry/register/read процессора также может быть выполнен через runProcessor или connector. Ниже приведены параметры для чтения.

  • register (обязательный) — Имя регистра для отправки сообщения.
  • topic (обязательный) — Тема для отправки сообщения в указанный регистр.
  • register_class (необязательный) — Определяет реализацию modRegister для использования, по умолчанию registry.modFileRegister.
  • format (необязательный, MODX 2.2+) — Если указано как json, сообщения перед возвращением преобразуются в JSON. Особенно полезно для запросов AJAX. Если указано как html_log, предполагается, что сообщения являются сообщениями журнала xPDO/modX и отформатированы для вывода в формате HTML (полезно для консолей modExt). По умолчанию сообщения возвращаются в виде массива.
  • poll_limit (необязательный) — Количество раз, чтобы опросить новые сообщения перед выходом. По умолчанию 1.
  • poll_interval (необязательный) — Количество секунд, чтобы задержать каждую попытку опроса для новых сообщений перед выходом. По умолчанию 1.
  • time_limit (необязательный) — Количество секунд, чтобы продолжить опрос новых сообщений перед выходом. По умолчанию 10.
  • message_limit (необязательный) — Максимальное количество сообщений для возврата. По умолчанию 20.
  • remove_read (необязательный) — Указывает, должны ли возвращенные сообщения быть удалены из очереди. По умолчанию true.
  • include_keys (необязательный, MODX 2.2+) — Указывает, должны ли возвращаемые сообщения включать ключи сообщений. По умолчанию false.
  • show_filename (необязательный) — Указывает, должны ли сообщения в формате html_log включать имя файла. По умолчанию false.

Примеры

Альтернатива хранилищу сессий

В некоторых случаях хранилище сеансов не подходит для сохранения персонализированной информации. В этих случаях вы можете использовать тему регистрации для хранения данных и их извлечения независимо от состояния сеанса пользователя. Это может быть полезно для пользовательских систем регистрации, где неавторизованные пользователи превращаются в авторизованных пользователей, и вам необходим доступ к данным, сохраненным до начала сеанса нового авторизованного пользователя (т.е. они вошли в систему).

Вы можете написать именованное сообщение в тему для поиска по ключу позднее, как это сделано в дополнении «Вход в систему» для активизации использования:

<?php
$modx->getService('registry', 'registry.modRegistry');
$modx->registry->addRegister('login', 'registry.modFileRegister', array('directory' => 'login'));
$modx->registry->login->connect();
$modx->registry->login->subscribe('/useractivation/');
$modx->registry->login->send('/useractivation/',array($user->get('username') => $pword),array(
    'ttl' => ($modx->getOption('activationttl',$scriptProperties,180)*60),
));

И чтобы получить конкретное сообщение позже:

<?php
$modx->getService('registry', 'registry.modRegistry');
$modx->registry->addRegister('login','registry.modFileRegister');
$modx->registry->login->connect();
$modx->registry->login->subscribe('/useractivation/'.$user->get('username'));
$msgs = $modx->registry->login->read(array('poll_limit' => 1));
$password = reset($msgs);

Захват сообщений журнала

MODX поддерживает указание logTarget как экземпляра modRegister. Это позволяет вам захватывать все сообщения журнала в очередь сообщений, где вы можете прочитать их позже, чтобы обеспечить обратную связь с пользователем, просмотры аудита и т.д.

<?php
$modx->getService('registry', 'registry.modRegistry');
$modx->registry->addRegister('logging', 'registry.modFileRegister', array('directory' => 'logging'));
$modx->registry->logging->connect();
$modx->registry->logging->subscribe($topic);

/* установите logTarget для экземпляра регистра */
$oldTarget = $modx->setLogTarget($modx->registry->logging);

/* код здесь, который отправляет сообщения журнала */

/* установить старую цель обратно */
$modx->setLogTarget($oldTarget);

Регистрация веб-узлов с балансировкой нагрузки для удаленных команд

В этом примере решения с использованием modRegistry используются два плагина для управления операциями обновления кэша на нескольких веб-узлах, каждый из которых использует свой собственный локальный файловый кэш.

Первый, прикрепленный к OnWebPageComplete, регистрирует каждый экземпляр сервера в течение 20 минут (это было разработано для облачного развертывания, которое будет запускать и уничтожать новые экземпляры сервера по требованию, но вы можете удалить время истечения, чтобы избежать накладных расходов на написание этих сообщений каждые 20 минут), а затем ищет сообщения с указанной командой clearCache. Второе, прикрепленное к событию OnSiteRefresh, позволяет очистить кэш в диспетчере, чтобы зарегистрировать сообщение clearCache со всеми «экземплярами» удаленного сервера, которые были зарегистрированы первым плагином. Вы можете взять эту идею и адаптировать ее для своей среды, но, как показывает наш опыт, рекомендуется изолировать один экземпляр сервера для менеджера (через конфигурацию поддоменов или аналогичный), который отделен от удаленных веб-узлов. Это позволяет выполнять действия на экземпляре менеджера в большом объеме, тогда изменения будут вытеснены только тогда, когда действие Обновить сайт будет выполнено из меню администратора.

Вот пример плагина remotecommands (ПРИМЕЧАНИЕ, это для MODX 2.1, и 2.0 будет немного отличаться, используя clearCache() вместо refresh()):

<?php
/* RemoteCommands плагин -- зарегистрироваться в событии OnWebPageComplete */

/* найти любые удаленные команды для выполнения из главного экземпляра */
$instance = $_SERVER['SERVER_ADDR'];
if (!empty($instance) && $modx->getService('registry', 'registry.modRegistry')) {
    $modx->registry->addRegister('remotes', 'registry.modDbRegister', array('directory' => 'remotes'));
    $modx->registry->remotes->connect();

    /* зарегистрировать этот экземпляр */
    $modx->registry->remotes->subscribe("/distrib/instances/");
    $modx->registry->remotes->send("/distrib/instances/", array($instance => true), array('expires' => time() + 1440));

    /* найдите любые действительные командные сообщения для этого экземпляра и действуйте на них */
    $modx->registry->remotes->subscribe("/distrib/commands/{$instance}/");
    $commands = $modx->registry->remotes->read(array('poll_limit' => 1, 'msg_limit' => 1));
    if (!empty($commands)) {
        $command = reset($commands);
        if (!empty($command)) {
             switch ($command) {
                 case 'clearCache':
                    $results= $modx->cacheManager->refresh();
                    break;
                 default:
                    break;
             }
        }
    }
}

А вот пример плагина sendclearcache для регистрации сообщения удаленной команды каждому экземпляру удаленного сервера:

<?php
/* SendClearCache плагин -- зарегистрироваться с помощью события OnSiteRefresh */

/* читать экземпляры и записывать сообщения для очистки кэша в каждый каталог команд */
if ($modx->getService('registry', 'registry.modRegistry')) {
    $modx->registry->addRegister('remotes', 'registry.modDbRegister', array('directory' => 'remotes'));
    $modx->registry->remotes->connect();
    $modx->registry->remotes->subscribe('/distrib/instances/');
    $instances = $modx->registry->remotes->read(array('poll_limit' => 1, 'msg_limit' => 25, 'remove_read' => false));
    if (!empty($instances)) {
        foreach ($instances as $instance) {
            if ($instance == $_SERVER['SERVER_ADDR']) continue;
            $modx->registry->remotes->subscribe("/distrib/commands/{$instance}/");
            $modx->registry->remotes->send("/distrib/commands/{$instance}/", 'clearCache', array('expires' => time() + 1440));
        }
    }
}

Другие удаленные команды также могут быть отправлены и обработаны таким образом. Вы просто реализуете обработку дополнительных команд в операторе switch плагина RemoteCommands.