= Rest сервис Topic-management === Rest сервис для работы с топиками. Сервис состоит из 2-х контекстов: - _topic-management_ - управление топиками (создание/изменение/удаление) - _topic-subscription_ - клиентский сервис подписки и публикации сообщения При смене контекста в конфигурационных файлах требуется перераздать права на данный сервис. Схема работы подписок image::Topic_publish_diagram.png[] Схема работы нотификаций image::Scheme_of_work_notifications(events).png[] === Права Право доступа в сервис _topic-management_ Для доступа к сервису _topic-management_ у аккаунта должно быть право доступа в данный сервис. По умолчанию право на доступ к сервису есть у пользователя _admin_. Используя данного пользователя в сервисе _permission-management_ можно раздать права на аккаунты систем. Параметры для выдачи аккаунту прав на сервис: - _objectId_: идентификатор учётной записи - _objectType_: account - _subjectId_: topic-management - _subjectType_: service Право manage сервиса _topic-subscription_ Для доступа к менеджерским функциям сервиса _topic-subscription_ у аккаунта должно быть право manage - данное право открывает доступ к управлению подписками. Функционал управления подписками реализован в методах _subscribe_ и _unsubscribe_, пример использования приведён в подпунктах “Массовая обработка при наличии права manage для данного сервиса”. Параметры для выдачи аккаунту права _manage_: - _objectId_: идентификатор учётной записи - _objectType_: account - _subjectId_: topic-subscription - _subjectType_: service - _action_: manage === Конфигурационные файлы Конфигурационные файлы по умолчанию хранятся в папке сервера \etc\ - _ru.entaxy.esb.system.event.handler.cfg_ [source,properties] ---- # максимальное колчичество попыток отправить сообщение в очередь # почитать подробнее можно в https://camel.apache.org/components/latest/eips/dead-letter-channel.html#deadLetterChannel-Redelivery redelivery.maximumRedeliveries=-1 # время между попытками отправить сообщение в очередь redelivery.redeliveryDelay=5000 #cron - по умолчанию запускается каждые 00:00:00, #cron выражение использует знак "+" как разделитель для модуля quartz2l quirtz.job.clean.cron=0+0+0+*+*+?+* ---- - _ru.entaxy.esb.system.event.rest.cfg_ [source,properties] ---- service.host=http://0.0.0.0 service.port.management=9090 #Рутовый контекст управляющего сервиса, при изменении требуется перераздать права для данного сервиса service.root.path.management=/topic-management service.port.subscription=9092 #Рутовый контекст клиентского сервиса, при изменении требуется перераздать права для данного сервиса service.root.path.subscription=/topic-subscription ---- === Методы topic-management: - _create_ - создать топик При создании и изменении топика, есть возможность передать списки систем, которым доступна подписка или публикация в данном топике. Запрос: _POST server:9090/topic-management/create_ Тело [source,json] ---- { "topicName": "boomNews", "possibleSubscribers" : ["systemUuid1", "systemUuid2"], "possiblePublishers" : ["systemUuid3", "systemUuid4"] } ---- Ответ: Статус 201 Тело [source,json] ---- { "title": "Topic created", "topicName": "", "subscriberErrors": { "systemNotFound": [ "" ] }, "publisherErrors": { "systemNotFound": [] } } ---- - update - изменить топик (название не меняется, так как на него завязана сама очередь в брокере) Запрос: _POST server:9090/topic-management/update_ Тело [source,json] ---- { "topicName": "boomNews", "possibleSubscribers" : ["systemUuid1", "systemUuid2"], "possiblePublishers" : ["systemUuid3", "systemUuid4"] } ---- Ответ: Статус 201 Тело [source,json] ---- { "title": "Topic updated", "topicName": "", "subscriberErrors": { "systemNotFound": [ "" ] }, "publisherErrors": { "systemNotFound": [] } } ---- - delete - топик помечается как удалённый Запрос: _POST server:9090/topic-management/delete_ Тело [source,json] ---- { "topicName": "boomNews" } ---- Ответ: Статус 200 Тело [source,json] ---- { "title": "Topic deleted", "topicName": "" } ---- - clean - очистка хранилища топиков Окончательное удаление топиков, помеченных как удалённые. Запрос: _POST server:9090/topic-management/clean_ Ответ: Статус 200 Тело [source,json] ---- { "title": "Cleaned", "topicDeleted": "" } ---- === Методы topic-subscription: - _subscribe_ - подписаться на топик Запрос: _POST server:9090/topic-subscription/subscribe_ Тело [source,json] ---- { "topicName": "boomNews", "subscriptionType": "PUSH" } ---- Ответ: Статус 201 Тело [source,json] ---- { "title": "Subscription created", "topicName": "", "systemName": "", "subscriptionType": "" } ---- === Массовая обработка при наличии права manage для данного сервиса. - _subscribe_ - подписаться на топик Запрос: _POST server:9092/topic-subscription/subscribe_ Тело [source,json] ---- { "topicName": "boomNews", "systemUuids": [ { "systemUuid": "NNNNNNNN-NNNN-NNNN-NNNN-NNNNNNNNNNNN", "subscriptionType": "PUSH" }, { "systemUuid": "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX", "subscriptionType": "PULL" }, { "systemUuid": "YYYYYYYY-YYYY-YYYY-YYYY-YYYYYYYYYYYY", "subscriptionType": "PULL" } ] } ---- Ответ: Статус 200 Тело [source,json] ---- [ { "title": "Internal Server Error", "detail": "System not found NNNNNNNN-NNNN-NNNN-NNNN-NNNNNNNNNNNN", "reason": "javax.persistence.NoResultException: No entity found for query" }, { "title": "Subscription created", "topicName": "ooooo111-ff6e-4219-a878-bff120c495f1", "systemUUID": "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX", "subscriptionType": "PULL" }, { "title": "Forbidden", "detail": "No permission to subscribe for system YYYYYYYY-YYYY-YYYY-YYYY-YYYYYYYYYYYY" } ] ---- - _unsubscribe_ - отписаться от топика Запрос: _POST server:9090/topic-subscription/unsubscribe_ Тело [source,json] ---- { "topicName": "boomNews" } ---- Ответ: Статус 200 Тело [source,json] ---- { "title": "Subscription deleted", "topicName": "", "systemName": "" } ---- === Массовая обработка при наличии права manage для данного сервиса. Запрос: _POST server:9092/topic-subscription/unsubscribe_ Тело [source,json] ---- { "topicName": "boomNews", "systemUuids": [ { "systemUuid":"NNNNNNNN-NNNN-NNNN-NNNN-NNNNNNNNNNNN", "subscriptionType": "PUSH" }, { "systemUuid": "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX", "subscriptionType": "PULL" }, { "systemUuid": "YYYYYYYY-YYYY-YYYY-YYYY-YYYYYYYYYYYY", "subscriptionType": "PULL" } ] } ---- Ответ: Статус 200 Тело [source,json] ---- [ { "title": "Internal Server Error", "detail": "System not found NNNNNNNN-NNNN-NNNN-NNNN-NNNNNNNNNNNN", "reason": "javax.persistence.NoResultException: No entity found for query" }, { "title": "Subscription deleted", "topicName": "ooooo111-ff6e-4219-a878-bff120c495f1", "systemUUID": "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX" }, { "title": "Subscription not found", "topicName": "ooooo111-ff6e-4219-a878-bff120c495f1", "systemUUID": "YYYYYYYY-YYYY-YYYY-YYYY-YYYYYYYYYYYY" } ] ---- - _publish_ - опубликовать событие Запрос: _POST server:9090/topic-subscription/publish_ Тело [source,json] ---- { "topicName": "boomNews", "message": "messageText2" } ---- Ответ: Статус 200 Тело { "title": "Message published", "topicName": "" } === Примеры ответов при ошибке - _Передан некорректный JSON или логин не определён_ Статус 400 Тело [source,json] ---- { "title": "Incorrect input parameters", "detail": "Cannot parse incoming JSON or login/system not defined" } ---- - _Подписка не найдена_ Статус 404 Тело [source,json] ---- { "title": "Subscription not found", "topicName": "${exchangeProperty.topicName}", "systemUUID": "${header.X-SystemUuid}" } ---- - _Топик не зарегистрирован_ Статус 400 Тело [source,json] ---- { "title": "Topic not registered", "topicName": "${exchangeProperty.topicName}" } ---- - _Система не найдена_ Статус 500 Тело [source,json] ---- { "title": "Internal Server Error", "detail": "System not found ${header.X-SystemUuid}", "reason": "${exception.stacktrace}" } ---- - _Неизвестный тип подписки_ Статус 500 Тело [source,json] ---- { "title": "Internal Server Error", "detail": "Unknown subscription type ${exchangeProperty.subscriptionType}", "reason": "${exception.stacktrace}" } ---- - _Нет прав на выполнение запрошенной операции_ Статус 403 Тело [source,json] ---- { "title": "Forbidden", "detail": "No permission to subscribe" } ---- - _Неизвестная ошибка_ Статус 500 Тело [source,json] ---- { "title": "Internal Server Error", "detail": "Unknown exception", "reason": "${exception.stacktrace}" } ---- == Работа модуля топиков в кластере === Подписки *PULL подписки не реализованы!* Для реализации подписки используются _durable shareable_ подписчики _Apache Artemis_ топиков, а для доставки сообщений из топиков создаются специальные маршруты отправляющие сообщения в подписанную систему(PUSH-подписка). При работе в кластере системой создаются дублирующие маршруты на каждом узле, которые работают в конкурентном режиме, т.е. при падении одного из узлов доставка сообщений будет производиться оставшимися узлами. Работа в кластере обеспечивается через компоненты _Apache Felix Event Admin_, реализующий рассылку служебных событий по топикам внутри узла, и _Apache Karaf Cellar_ с интеграцией с _Event Admin_, реализующий рассылку данного события по всем узлам кластера. При создании/удалении подписки система создаёт соответствующее событие и отправляет в специальный топик _subscription_, далее подписчики на всех узлах, входящих в кластер, получают и обрабатывают данное событие. === Настройки Настройки производятся на любом узле либо на мастер узле, в зависимости от настроек кластера. Для синхронизации топика _subscription_ в конфигурационном файле _org.apache.karaf.cellar.groups.cfg_, нужно добавить строки: [source,properties] ---- default.event.blacklist.inbound = none default.event.blacklist.outbound = none default.event.whitelist.inbound = subscription default.event.whitelist.outbound = subscription ---- Далее если _Apache Karaf Cellar_ настроен правильно, то конфигурационные файлы _org.apache.karaf.cellar.groups.cfg_ должны синхронизироваться и строки, представленные выше, появятся на всех узлах. Если синхронизация конфигурационных файлов не проходит, можно проверить статус _cellar_ продюсера командой: cluster:producer-status если выключен, то можно включить командой: cluster:producer-start === Удаление топиков Удаление топиков происходит в 2 этапа - При вызове метода _delete_ топик помечается в БД, как удалённый - По расписанию запускается задача (по умолчанию раз в сутки в 00:00), которая удаляет топик окончательно вместе с подписками, правами и консьюмерами. Либо очистка запускается вручную вызовом метода _clean_ сервиса _topic-management_ Если до очистки системы изменить топик помеченный как удалённый или попытаться создать его заново, то восстановится старый топик === Плановая задача по очистке топиков Т.к. удаление топиков происходит в 2 этапа, с помощью планировщика _Quartz2_, работающего в кластере, запускается задача по очистке. Запуск происходит в конкурентном режиме, узел первый запустивший задачу получает приоритет, на остальных узлах задача останавливается до следующего запуска. Частота запуска задачи настраивается в конфигурационном файле _ru.entaxy.esb.system.event.handler.cfg_ в свойстве quirtz.job.clean.cron=0+0+0+*+*+?+* с помощью cron выражения. Особенность cron выражения для quartz в том что “++” используется, как разделитель.