NAV
json scala

Verdi

Описание команд всех сервисов, которые входят в состав Verdi.

Список версий

v9.0.0

Прочие изменения

v4.0.0

Ломающие изменения

Прочие изменения

v3.3.0

Прочие изменения

v3.2.0

Прочие изменения

v3.1.0

Прочие изменения

v3.0.0

Ломающие изменения

Прочие изменения

v2.1.0

Прочие изменения

v2.0.0

Ломающие изменения

Прочие изменения

v1.12

Ломающие изменения

Прочие изменения

v1.11.7

Прочие изменения

v1.11.6

v1.11.5

Ломающие изменения

v1.11.4

Ломающие изменения

Прочие изменения

v1.11.3

Ломающие изменения

Прочие изменения

v1.11.2

Прочие изменения

Применены изменения из v1.10.1:

v1.11.1

Прочие изменения

v1.11

Ломающие изменения

Прочие изменения

v1.10.2

Ломающие изменения

Прочие изменения

v1.10.1

Прочие изменения

v1.10

Ломающие изменения

Прочие изменения

v1.9.1

v1.9

В данном релизе есть ломающие изменения (смотри ниже)

Ломающие изменения:

  1. Библиотека senderlib:

Удалена зависимость для log4j: slf4j-log4j12 Удален layout для логов в формате CEF: CEFLog4jLayout

  1. Микросервис Alexandrina:

Команда "GetCatalogItemBatch" теперь возвращает пустой список, если на вход был передан пустой список ID

v1.8

Важные изменения

v1.7.1

Важные изменения

v1.7

Важные изменения

v1.6.1

Важные изменения

v1.6

Важные изменения

v1.5.3

v1.5.2

Технический хотфикс

v1.5.1

Версия от 27.06.2023. Список изменений:

v1.5

Версия от 06.06.2023. Список изменений:

v1.4.1

Версия от 03.05.2023. Список изменений:

v1.4

Версия от 22.03.2023. Список изменений:

Общие типы данных

Для некоторых команд предусматривается фильтрация, сортировка и пагинация результата. Для этих целей был добавлен объект Search, который передается в качестве параметров к команде.
Также в этот объект можно преобразовать фильтры из ответа авторизации AuthorizationResult.

Search - универсальный тип параметров списочного запроса. Он состоит из полей

Поле Тип Обязательное Описание Ограничения
query string да Строка с запросом, в котором указывается комбинация фильтров. Для запросов без фильтрации - пустая строка Значения в строке должны быть указаны в поле context
context json object да Контекст фильтров запроса. Объект, в котором ключ - это название фильтра, а значение - это значение фильтра. Для запросов без фильтрации - пустой объект
sorting Sorting нет Параметры сортировки данных
paging Paging нет Параметры пейджинга. В случае отсутствия данного поля, считается что пейджинг указан как "Номер страницы - 1, число элементов - 10".

Filter query

Является строкой с запросом для фильтрации при выполнении команды.
Запрос состоит из названий атрибутов фильтруемого ресурса и способов их комбинирования:

Filter context

С помощью контекста передаются параметры для фильтрации полей из query.
Контекст является JSON объектом, который представляет собой тип Map[String, Json], где

FilterQueryContext

Общий тип для всех видов фильтров. Существует несколько реализаций, у которых может поддерживаться несколько форматов для записи условия.
Рекомендуется передавать все условия фильтрации в виде JSON объекта, как более очевидный формат.

InSetQuery

Фильтрация атрибута ресурса по списку значений. Если значение атрибута ресурса является массивом, то условие фильтрации возвращает TRUE, если этот массив и список значений для условия фильтрации пересекаются хотя бы по одному элементу. Иначе условие фильтрации возвращает TRUE, если одиночное значение из атрибута соответствует хотя бы *одному значению * из фильтра.

Поле Тип Обязательное Описание Значение по умолчанию Ограничения
values List[string] да Список значений для условия фильтрации.
kind "any" да Тип фильтра. Может принимать только значение "any".
negation bool нет Необходимость отрицания результата фильтрации: FALSE -> TRUE. false

Возможные форматы:

В формат с одной строкой нельзя добавить отрицание (negation), т.к. вся строка является значением для фильтра. Например, "not some value" будет преобразовано в {"values": ["not some value"], "kind": "any", "negation": false}.

AllInSetQuery

Фильтрация массива из атрибута ресурса по списку значений. Условие фильтрации возвращает TRUE, если массив из атрибута содержит все значения из фильтра. Работает только для полей, являющихся массивом.

Поле Тип Обязательное Описание Значение по умолчанию Ограничения
values List[string] да Список значений для условия фильтрации.
kind "all" да Тип фильтра. Может принимать только значение "all".
negation bool нет Необходимость отрицания результата фильтрации: FALSE -> TRUE. false

Возможные форматы:

LikeQuery

Фильтрация атрибута ресурса по шаблону. Условие фильтрации возвращает TRUE, если значение из атрибута соотвествует шаблону.
Данный фильтр соответствует фильтру like из SQL. Например, like в PostgreSQL.

Поле Тип Обязательное Описание Значение по умолчанию Ограничения
likequery string да Шаблон для условия фильтрации.
kind "like" да Тип фильтра. Может принимать только значение "like".
negation bool нет Необходимость отрицания результата фильтрации: FALSE -> TRUE. false

В поле likequery, помимо слов для условия, поддерживаются символы % - неограниченное кол-во любых символов, _ - только один любой символ, которые можно использовать несколько раз подряд. Например, "%s_me thi__%".

Возможные форматы:

Чтобы добавить отрицание (negation) в формат со строкой, нужно перед условием фильтрации добавить not, разделив условие и отрицание пробелом. Например, "not like %anything%".

TsQuery

Фильтрация атрибута ресурса по условие для полнотекстового поиска PostgreSQL. Условие фильтрации возвращает TRUE, если значение из атрибута соотвествует условию.
Операторы: '&' - И, '|' - ИЛИ, ':*' - начало слова, также возможно отрицание через добавление '!'. Допустимо использование логического объединения с помощью скобок '(' и ')'.

Поле Тип Обязательное Описание Значение по умолчанию Ограничения
tsquery string да Условия полнотекстового поиска для фильтрации.
kind "ts" да Тип фильтра. Может принимать только значение "ts".
negation bool нет Необходимость отрицания результата фильтрации: FALSE -> TRUE. false

В поле tsquery, помимо слов для условия, поддерживаются следующие операторы: & - И, | - ИЛИ, :* - начало слова, также возможно отрицание через добавление ! перед словом.
Допустимо использование логического объединения с помощью скобок ( и ).

Возможные форматы:

Чтобы добавить отрицание (negation) в формат со строкой, нужно перед условием фильтрации добавить not, разделив условие и отрицание пробелом. Например, "not ts !Митя".

RangeQuery

Фильтрация атрибута ресурса по условию вхождения в интервал из значения фильтра. Условие фильтрации: from <= targetValue <= to.

Поле Тип Обязательное Описание Значение по умолчанию Ограничения
from long нет Значение, с которого начинается интервал для фильтрации (входит в интервал).
to long нет Значение, с которым заканчивается интервал для фильтрации (входит в интервал).
kind "range" да Тип фильтра. Может принимать только значение "range".
negation bool нет Необходимость отрицания результата фильтрации: FALSE -> TRUE. false

Если поля from и to не указаны, то условие всегда вернет true.

Возможные форматы:

Чтобы добавить отрицание (negation) в формат со строкой, нужно перед условием фильтрации добавить not, разделив условие и отрицание пробелом. Например, "not _12".

Sorting

Sorting - параметры сортировки

Поле Тип Обязательное Описание
fieldName String Да Название поля для сортировки
order String Да Направление сортировки. Допустимые значения: asc и desc для сортировки по возрастанию и убыванию соответственно

Paging

Paging - параметры пейджинга

Поле Тип Обязательное Описание
page Integer Да Номер запрашиваемой страницы. Страницы нумеруются с 1
count Integer Да Количество элементов на странице

Page

Страница списка элементов (часть списка с примененным пейджингом)

Поле Тип Описание
items Array of objects Список элементов на запрошенной странице
total Integer Общее количество объектов в БД

AuthorizationResult

Результат выполнения запроса авторизации

Поле Тип Обязательное Описание
allow Bool Да Разрешен ли доступ
entityFilters String Нет Фильтры для сущности, которые нужно применить если "allow = true". Формат фильтров описан на странице Condition

AttributeWithValues

Результат выполнения запроса авторизации

Поле Тип Обязательное Описание
id String Да Идентификатор атрибута
cat String Да Идентификатор категории атрибута
values List[String] Да Список значений атрибута

В качестве значения поля "cat" может быть использована любая строка (нет ограничений), но в данный момент мы используем только следующие значения:

UserId

ID пользователя. Соответствует типу UUID.

GroupId

ID группы. Соответствует типу String.

UserStatus

Список вариантов статуса пользователя в системе. Имеет тип String.

Название Описание
Pending Пользователь, ожидающий подтверждения регистрации
Activated Обычный пользователь системы (выполнивший все условия/требования после регистрации)
Deactivated Заблокированный пользователь системы

CommandRequest

Структура для описания запроса на выполнение команды

Поле Тип Обязательное Описание
commandName CommandName Да Название команды
context RequestContext Да Контекст запроса. Содержит информацию о пользователе, который отправил запрос, и другие дополнительные параметры
payload Json Нет Данные для команды, которые она получит в качестве аргументов. Обычно идентично содержимому body запроса.

RequestContext

Контекст запроса выполнения команды.

Поле Тип Обязательное Описание
commandId CommandId Да ID связанной команды
tracing TracingContext Нет Данные для логирования
parameters Map[String, String] Да Дополнительные параметры. Значение по ключу может быть в любом формате, но должно передаваться как String. Сейчас используется для передачи данных о пользователе, которые затем можно превратить в UserContext
isInternal boolean Да Флаг, указывающий, что данный вызов команды внутренний (т.е. не требует авторизации). Значение по умолчанию false.

UserContext

Данные пользователя необходимые для передачи в контексте запроса каждой команды

Поле Тип Обязательное Описание
id UserId Да Идентификатор пользователя.
emailOpt String Нет Уникальный email пользователя (опционален, т.к. отсутствует у анонимного пользователя).
groupIds List[GroupId] Да Список идентификаторов групп пользователя.
passwordExpirationDateOpt TimeStamp Нет Опциональная дата завершения действия пароля от учетной записи пользователя. Если значение не установлено, то пароль считается бессрочным.

UserContextWithInvalidations

Данные пользователя необходимые для обработки запроса каждой команды

Поле Тип Обязательное Описание
userContext UserContext Да Контекст пользователя
userStatus UserStatus Да Статус пользователя
jwtInvalidation List[JwtInvalidation] Да Список правил для инвалидации JWT пользователя
deactivateAt TimeStamp Нет Ограничение на срок действия учетной записи пользователя

EntityObjectEventAdditionalData

Один из нескольких вариантов:

PluginBackLinksAdditionalData

Поле Тип Обязательное Значение по умолчанию Описание Ограничения
topic String Да Нет Топик для шага Plugin
fieldId String Да Нет Поле сущности, где хранится файл для индексации

EntityObjectEvent

Поле Тип Обязательное Значение по умолчанию Описание Ограничения
entityObject EntityObject Да Нет Передаваемая сущность из data-model
additionalData Option[EntityObjectEventAdditionalData] Нет нет Дополнительные данные, передаваемые с событием

EntityTypeId

Соответствует типу String. Содержит идентификатор, который, чаще всего, имеет формат UUID, но это не является обязательным требованием.

FieldId

Соответствует типу String.

ObjectFileId

Соответствует типу UUID.

AdditionalFieldName

Соответствует типу String.

StepProgress

Поле Тип Обязательное Значение по умолчанию Описание Ограничения
step Step c payload Plugin Шаг сервиса индексации
entityObject EntityObject Сущность сервиса data-model, обработка полей которой происходит
files Map[FieldId, Seq[ObjectFile]] Соответствие между полем в entityObject, которое нужно обработать, и описанием файла, который хранится в этом поле. StepProgress, попадающий в plugin, содержит в files только те поля, которые содержатся в step.payload.fields
generated Map[AdditionalFieldName\, Seq[GeneratedFile]] Соответствие между полем, сгенерированным предыдущими шагами, и описанием сгенерированного файла, который хранится в этом поле. StepProgress, попадающий в plugin, содержит в generated только те поля, которые содержатся в step.payload.fields
attempts Int Количество попыток, которое было сделано для обработки данного шага индексации. Всегда меньше APP_MAX_STEP_ATTEMPTS (переменная окружения сервиса indexation)
correlationId String Id индексации, породившей этот StepProgress: UUID в виде строки(массовая индексация) или строка "event"+UUID(индексация события из data-model)
level Int Уровень, на котором находится step в индексации. Для индексации события из data-model всегда равен 0.
skipped Seq[ObjectFile] Описание файлов, которые были исключены из обработки с помощью ExtensionFilter. Сюда будут добавлены все файлы с неподходящим расширением, даже те, которые не содержатся в step.payload.fields. При это файлы с верным расширением, которые исключены из обработки плагинами, потому что их нет в step.payload.fields сюда включены не будут.

ObjectFile

Поле Тип Обязательное Значение по умолчанию Описание Ограничения
fileId ObjectFileId Да Нет Идентификатор файла
additional JsonObject Нет Нет Дополнительная информация по файлу. Сейчас здесь хранится JsonObject, представляющий из себя Map[additionalFileFieldName, url], где хранятся ссылки на файлы, сгенерированные в результате индексации. Сохраняется эта информация с помощью команды saveFilesAdditionalInfo
name String Да Нет Имя файла с расширением
url String Да Нет Url, по которому можно найти этот файл в s3

GeneratedFile

Поле Тип Обязательное Значение по умолчанию Описание Ограничения
originField FieldId Да Нет Название файлового поля сущности, в котором хранится файл, на основе которого был сгенерирован текущий
originFileId ObjectFileId Да Нет Id файла на основе которого был сгенерирован текущий(описание сгенерированного файла хранится в объекте оригинального файла в поле additional, не additionalData)
file String Нет Нет Url в s3 для содержимого сгенерированного файла

Настройка StreamingKafkaConsumer

StreamingKafkaConsumer предоставляет возможность создавать kafka-consumer и обрабатывать входящие сообщения с помощью передаваемой пользовательской функции. При этом один StreamingKafkaConsumer может обрабатывать сообщения из нескольких топиков с разными настройками и функциями-обработчиками. Для каждого вызова consumeWithFlow создается отдельный org.apache.kafka.clients.consumer.KafkaConsumer, а также akka-граф получения и обработки сообщений указанного топика. Эти графы запускаются независимо, но делят между собой один KafkaConsumerControlActor. StreamingKafkaConsumer может вести себя по-разному и для настройки его поведения нужно использовать KafkaConsumerSettings

KafkaConsumerSettings

Поле Тип Обязательное Описание Значение по умолчанию Ограничения
group string да Название группы потребителей, к которой принадлежит данный экземпляр сервиса
topic KafkaTopicSettings да Настройки для топика
restart RestartConfiguration нет Настройки перезапуска потребителя Kafka
perMessageRestart PerMessageRestartConfiguration нет Настройки перепрочтения сообщений, обработка которых завершается ошибкой

Иногда в процессе применения пользовательской функции к сообщению может быть выброшено исключение и тогда, то как поведет себя стрим, определяется настройками KafkaConsumerSettings.restart и KafkaConsumerSettings.perMessageRestart. KafkaConsumerSettings.restart используется в общем KafkaConsumerControlActor, поэтому они всегда будут общими для всех вызовов consumeWithFlow, а KafkaConsumerSettings.perMessageRestart, KafkaConsumerSettings.group, KafkaConsumerSettings.topic принимаются в вызове consumeWithFlow, поэтому можно сделать их разными для разных вызовов consumeWithFlow.

RestartConfiguration

KafkaConsumerSettings.restart отвечает за то, сколько раз в случае возникновения исключения во время обработки стоит перезапустить консьюмер и связанный с ним akka-граф, прежде чем объявить сервис больным. Если настройки не указаны, то в KafkaConsumerControlActor используются значения по умолчанию. Задержка перед перезапуском увеличивается пропорционально количествам перезапусков начиная от minBackoff вплоть до maxBackoff.

Поле Тип Обязательное Описание Значение по умолчанию (в сервиса verdi-cursor) Значение по умолчанию (в KafkaConsumerControlActor) Ограничения
minBackoff FiniteDuration да Минимальная задержка перед перезапуском. 1 second 3.seconds меньше или равно maxBackoff
maxBackoff FiniteDuration да Максимально возможная задержка перед перезапуском. 30 seconds 1.minute больше или равно minBackoff
randomFactor double нет Коэффициент величины дополнительной случайной задержки (jitter) относительно основной задержки:0.0 - без случайной задержки, 1.0 - до 100% задержки. Если после умножения задержки на randomFactor получится меньше 1 миллисекунды, то jitter будет приравнен к нулю. 0.2 0 от 0 до 1
maxRestarts int да Максимальное количество перезапусков в заданный период времени. После превышения этого числа сервис будет объявлен больным 5 20 больше 0 и больше perMessageRestart.maxRestarts
maxRestartsWithin FiniteDuration да Период времени, в течении которого копится счетчик перезапусков 5 minutes 2 * maxBackoff

PerMessageRestartConfiguration

Иногда нам хочется в таком случае не объявлять сервис больным, а вместо этого спустя несколько перезапусков пропустить сообщение kafka, обработка которого вызывает ошибку. Именно за такое поведение отвечает PerMessageRestartConfiguration. Если PerMessageRestartConfiguration не указаны или PerMessageRestartConfiguration.maxRestarts < 0, то вызывающие ошибку сообщения не будут пропущены, а сервис просто будет объявлен больным в соответствии с RestartConfiguration. Для каждого сообщения счетчик перепрочтений хранится в кэше.

Поле Тип Обязательное Описание Значение по умолчанию (в сервиса verdi-cursor) Ограничения
failureCacheCapacity long да Максимальное количество значений в кэше. 1 second меньше или равно maxBackoff
failureCacheTTL FiniteDuration нет Максимальное время жизни элемента в кэше. В случае отсутствия значения время жизни элемента не будет ограничено. 30 seconds больше или равно minBackoff
maxRestarts int да Максимальное количество раз, которое консьюмер перезапустится прежде чем проигнорировать сообщение, при чтении которого происходит ошибка 5 больше 0

Счетчики рестартов

Для того чтобы обеспечить функционал рестартов консьюмера в ходе работы поддерживается 2 вида счетчиков:

  1. Счетчик рестартов, индивидуальный для каждого сообщения. Этот счетчик реализован через кэш CacheApi и поддерживается только при наличии настроек KafkaConsumerSettings.perMessageRestart. Кэш этих счетчиков является индивидуальным для каждого запуска consumeFlow. Он считает сколько раз сервис был перезапущен из-за возникновения ошибки в ходе обработки конкретного сообщения.
  2. Глобальный счетчик рестартов. Этот счетчик является индивидуальным для каждого запуска consumeFlow, но увеличивается при ЛЮБОМ рестарте, а не только в случае если сообщение было пропущено. То есть даже при наличии настроек KafkaConsumerSettings.perMessageRestart, КАЖДЫЙ перезапуск из-за определенного сообщения будет увеличивать глобальный счетчик. При достижении этим счетчиком значения KafkaConsumerSettings.restart.maxRestarts сервис будет объявлен больным вне зависимости от наличия настроек KafkaConsumerSettings.perMessageRestart. Поэтому при использовании perMessageRestart нужно указывать KafkaConsumerSettings.restart.maxRestarts > KafkaConsumerSettings.perMessageRestart.maxRestarts или не указывать KafkaConsumerSettings.perMessageRestart.maxRestarts совсем.

Периоды

Оба вида счетчиков дают возможность обнулить их после прошествия определенного периода времени. Глобальный счетчик рестартов обнуляется после прошествия maxRestartsWithin, а счетчик рестартов, индивидуальный для каждого сообщения, спустя failureCacheTTL. При этом failureCacheTTL никак не влияет на глобальный счетчик. То есть даже если индивидуальный счетчик сообщения уже обнулен, глобальный счетчик НЕ будет уменьшен на то количество перезапусков, которые произошли из-за этого сообщения.

Особенности произведения рестарта

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

Роуты для информирования статусов сервисов

Для получения информации о статусе сервиса существует интерфейс com.embedika.verdi.senderlib.ServiceHealthApi.

Сервис позволяет хранить и обрабатывать текущий статус сервиса. Есть 2 состояния которые можно узнать у сервиса: isHealth и isReady.

Статус Health сообщает о том что сервис работает и у него нет проблем. По умолчанию статус считается Health и в случае технических проблем он изменяется на Ill.

Cтатус Ready сообщает о том что сервис готов принимать команды и обрабатывать их. Статус по умолчанию NotReady и необходимо установить его вручную на последней стадии инициализации проекта методом ServiceHealthApi::markReady().

Для Akka scala HealthRouteImpl.route(healthApi)()

Для Tapir / ZIO scala val makeAPI: URIO[Env, List[ZServerEndpoint[Clock, _, _, _]]] = for { serviceHealthApi <- ZIO.service[ServiceHealthApi] serviceAPI <- serviceAPI } yield { implicit val ff: FromFuture[RIO[Clock, *]] = new FromFuture[RIO[Clock, *]] { override def apply[A](futureMaking: => Future[A]): RIO[Clock, A] = ZIO.fromFuture(_ => futureMaking) } serviceAPI ++ HealthRoute.route[RIO[Clock, *]](serviceHealthApi) }

val makeAPI: URIO[Env, List[ZEndpoint]] = for {
  serviceHealthApi        <- ZIO.service[ServiceHealthApi]
  serviceAPI              <- serviceAPI
} yield {
  implicit val ff: FromFuture[Task] = new FromFuture[Task] {
    override def apply[A](futureMaking: => Future[A]): Task[A] = ZIO.fromFuture(_ => futureMaking)
  }
  serviceAPI ++ HealthRoute.route[Task](serviceHealthApi)
}

Для добавления в проект достаточно добавить роуты с помощью метода HealthRoute::route:

Функционал фильтров и сортировки

Для некоторых команд можно передавать параметры запроса в виде объекта Search, который содержит информацию о том как нужно отфильтровать, отсортировать запрос и как разделить его на страницы.

Фильтрация

  {
  "query": "count && (created || modified)",
  "context": {
    "count": "1_1000",
    "created": "1630326000_",
    "modified": "_1630327000"
  }
}

Фильтрация состоит из двух полей:

Query поддерживает операторы && и || + скобки.
В Context-е можно описать несколько видов проверок для полей:

1) Условие равенства переданному значению.

   {
     "context": {
       "fieldName": "какое-то значение"
     }
   }

2) Условие равенства какому-то одному значению из предоставленного списка.

   {
     "context": {
       "fieldName": "[первое значение, второе, другое]"
     }
   }

или

   {
     "context": {
       "fieldName": "any[первое значение, второе, другое]"
     }
   }

3) Условие наличия всех значений из предоставленного списка в массиве всех значений objectFieldName, которые присутствуют в объектах поля arrayFieldName. Работает только для полей arrayFieldName, содержащих массив. Предоставленный в запросе список должен содержать не менее двух значений.

   {
     "context": {
       "arrayFieldName.objectFieldName": "all[первое значение, второе, другое]"
     }
   }

4) Условие соответствия паттерну
Значение поля обязательно должно начинаться со слова like.

   {
     "context": {
       "fieldName": "like какое%значен__"
     }
   }

5) Условие вхождения значения в заданный диапазон. В данный момент, поддерживаются только целые числа. Начало и конец диапазона разделяются знаком _. Оба конца диапазона опциональны и они включаются в диапазон. Если передать просто _, то результатом будет пустой диапазон, в который не входит ни один элемент и ответ тоже будет пустой.

6) Условие текствого поиска PGSQL
Значение поля обязательно должно начинаться со слова ts.

   {
     "context": {
       "fieldName": "ts (this | that) & the:*"
     }
   }

Сортировка

{
  "sorting": {
    "fieldName": "number",
    "order": "desc"
  }
}

Сортировка определяется двумя полями:

Настройки логеров

Конфигурация для логера указывается в файле src/main/resources/logback.xml (или logback-test.xml). Если такого файла нет, то будет использована "базовая" конфигурация с выводом лога в консоль (stdout) в следующем формате:
%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} -%kvp- %msg%n.

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

Пример:
В документации приведена общая переменная окружения для уровня логирования LOG_LEVEL, но у сервиса "Oberto" для всех переменных окружения используется префикс OBERTO_. Поэтому, чтобы настроить общий уровень логирования для сервиса " Oberto", нужно использовать переменную OBERTO_LOG_LEVEL вместо LOG_LEVEL.

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

Натуральная сортировка (natural sorting)

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

Сортировка осуществляется с помощью локали en@colNumeric=yes.

Примеры результатов сортировки:

Описание Пример
Строки с числами 0
3
21
56
123
Числами внутри слов a2b
a10b
a20b
Версия некоторых библиотек v2.5.0
v2.10.0
v10.1.0
v10.12.0
Главы книг Глава 2
Глава 2.2
Глава 2.012
Глава 13
Глава 13.1

LOG_OUTPUT

Задает, куда будет выводиться сообщения лога. Может принимать следующие значения:
STDOUT - обычный лог в консоль.
STDOUT_CEF - лог в формате CEF в консоль.
STDOUT_CEF_JSON - лог в формате JSON в консоль, но со структурой сообщений CEF.
FILE - обычный лог в файл.
FILE_CEF - лог в формате CEF в файл.
FILE_CEF_JSON - лог в формате JSON в файл, но со структурой сообщений CEF.
SYSLOG - обычный лог в SYSLOG.
SYSLOG_CEF - лог в формате CEF в SYSLOG.
SYSLOG_CEF_JSON - лог в формате JSON в SYSLOG, но со структурой сообщений CEF.

Данный параметр может принимать несколько значений через любой разделитель (например, через пробел "STDOUT FILE_CEF"). Если указано несколько значений с одним типом вывода, то будет учитываться только вывод в формате CEF.
Например: если присутствуют "STDOUT" + "STDOUT_CEF", то учитывается только "STDOUT_CEF"; "FILE" + "FILE_CEF" = " FILE_CEF"; "SYSLOG" + "SYSLOG_CEF" = "SYSLOG_CEF".

LOG_LEVEL

Стандартный уровень логирования, который будет считаться значением по умолчанию для логеров, у которых уровень логирования не задается в отдельной переменной.
Значения в переменной характеризуют, насколько детальными будут сообщения в логе.
Может принимать следующие значения:
TRACE - максимально подробные сообщения.
DEBUG - менее подробные сообщения, чем в TRACE, но достаточные для debug-а.
INFO - логирование основных событий во время работы приложения. Считается стандартным уровнем логирования.
WARN - логирование только важных событий.
ERROR - логирование только сообщений об ошибках.
OFF - отключение лога.

Каждый уровень включает в себя все последующие, поэтому TRACE наиболее подробный, т.к. содержит все возможные сообщения, а WARN менее подробный, т.к. содержит только сообщения об ошибках и других важных событиях, но не содержит "стандартные" события из уровня INFO.

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

Переменные для указания уровня логирования конкретных логеров

В каждом сервисе/приложении по своему настроены логеры, которые будут привязаны к какой-то из переменных. Далее будут описаны лишь общий смысл переменных и какого вида сообщения можно ожидать от привязанных логеров.

LOG_LEVEL_HTTP - логер для HTTP сервера/клиента, отображающий события во время обработки HTTP вызова. Значение по умолчанию "INFO".
LOG_LEVEL_NIOSOCKET - логер для бекенда HTTP сервера/клиента, отображающий низкоуровневые события во время обработки HTTP вызова. Значение по умолчанию "WARN".

LOG_LEVEL_AKKA - логер для системы акторов, отображающий специфичные для Akka сообщения (из тред пула, из стримов, из акторов). Значение по умолчанию "INFO".
LOG_LEVEL_LIQUIBASE - логер для liquibase (миграции БД). Почти не используются, только если миграции не вызываются во время работы сервиса (как в data-model). Значение по умолчанию "INFO".

LOG_LEVEL_SLICK_STATEMENT - логер для slick (вывод sql запросов). Значение по умолчанию "WARN".
LOG_LEVEL_SLICK_BENCHMARK - логер для slick (вывод времени подготовки sql запросов). Значение по умолчанию " OFF".
DATA_MODEL_LOG_LEVEL_SLICK_QUERY_COMPILER - логер для slick (вывод времени подготовки sql запросов с разделением по стадиям). Значение по умолчанию "OFF".

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

LOG_LEVEL_KAFKA, LOG_LEVEL_KAFKA_PRODUCER, LOG_LEVEL_KAFKA_CONSUMER - логер для Kafka клиентов (продюсер и консьюмер). Обычно используется или общая переменная, или по одной для консьюмера и продюсера. Значение по умолчанию " WARN".
LOG_LEVEL_KAFKA_HTTP - логер для HTTP бекенда Kafka клиентов. Значение по умолчанию "WARN".
LOG_LEVEL_KAFKA_INTERNAL - логер для внутренних сообщений Kafka клиентов (metadata). Значение по умолчанию " INFO".
LOG_LEVEL_KAFKA_SELECTOR - логер для общего сетевой библиотеки всех клиента Kafka (логирует SSL handshake). Значение по умолчанию "INFO".
LOG_LEVEL_KAFKA_NETWORK_CLIENT - логер для общего сетевой библиотеки всех клиента Kafka (низкоуровневый клиент). Значение по умолчанию "INFO".
LOG_LEVEL_KAFKA_STREAMING_PRODUCER - логер для Kafka producer. Значение по умолчанию "INFO".
LOG_LEVEL_ZIO_KAFKA - логер для ZIO версии Kafka producer. Значение по умолчанию "INFO".

LOG_LEVEL_AKKAHTTPSENDER - логер для отправки команд по HTTP. Значение по умолчанию "WARN".
LOG_LEVEL_KAFKASENDER - логер для отправки команд по Kafka. Значение по умолчанию "TRACE".
LOG_LEVEL_COMMANDSTATUS_CLIENT - логер для клиента CommandStatus. Значение по умолчанию "WARN".
LOG_LEVEL_AUTHZCLIENT - логер для клиента авторизации (к authzfroce или oberto). Значение по умолчанию "ERROR".
LOG_LEVEL_LICENSE - логер для операций проверки лицензий. Параметр применим к сервисам Oberto, Mon, Api Gateway. На уровне логирования DEBUG логируется информация об используемой лицензии. Значение по умолчанию "INFO".
LOG_LEVEL_COMMANDLOGGER - логер для трассировки запросов, класс com.embedika.verdi.CommandLogger. Логируется информация о текущем запросе.
Значение по умолчанию "INFO".
LOG_JSON_SPACES - определяет форматирование JSON-а в сообщениях логера:
noSpaces - без переносов строк и отступов,
spaces2 - с переносами строк и с отступами в два пробела.
Значение по умолчанию "noSpaces".

Параметры для настройки логирования в формате CEF.

У логов есть возможность включить формат CEF для логирования по следующему шаблону:
2022-12-14T16:56:31+0500 CEF:Version|Device Vendor|Device Product|Device Version|EventClassId|Message|Severity|src=? dst=? shost=? suid=? suser=? msg=? end=currentTimeMillis|.

Чтобы включить логирование в формате CEF, нужно задать в переменной LOG_OUTPUT значение с постфиксом, который содержит _CEF ( например, LOG_OUTPUT = STDOUT_CEF или LOG_OUTPUT = FILE_CEF_JSON).

В каждом logback.xml файле есть свойство, которое задает "main class" всего приложения. Этот класс нужен для получения параметров записи сообщений в формате CEF.
У данного свойства нет переменной окружения, но его можно поменять прямо в файле.
Значение (value) свойства зависит от сервиса, но обычно оно задано как
<property scope="context" name="projectMainClassPath" value="com.embedika.Main"/>

В каждом application.conf файле указаны параметры для логирования в формате CEF, которые по умолчанию не заданы.
Если логи пишутся в формате CEF, то необходимо задать следующие переменные:

  1. LOGGING_SRC_IP Параметр SRC (источник/source, на который ссылается событие) для логов в формате CEF. Если не установлена, src=notFound. Требуемый формат: IPv4, например "192.168.10.1".

  2. LOGGING_SRC_HOST Параметр SHOST (источник/source, на который ссылается событие) для логов в формате CEF. Если не установлена, shost=notFound. Требуемый формат: fully qualified domain name (FQDN), например "host" или " host.domain.com".

  3. LOGGING_DST_IP Параметр DST (получатель/destination, на который ссылается событие) для логов в формате CEF. Если не установлена, dst=notFound. Требуемый формат: IPv4, например "192.168.10.1".

  4. LOGGING_CEF_VER Версия формата CEF: либо 0, либо 1. Рекомендуется использовать 0.
    Значение по умолчанию "0".

Параметры для настройки логирования в формате SYSLOG

В конфиге есть возможность настроить отправку логов в какой-нибудь SYSLOG сервер. Для отправки логов используется Syslog4j.

Чтобы включить логирование в SYSLOG, нужно задать в переменной LOG_OUTPUT значение с префиксом SYSLOG_ ( например, LOG_OUTPUT = SYSLOG_CEF).

  1. LOG_SYSLOG_TYPE Протокол взаимодействия с SYSLOG сервером. Может принимать значения "UDP", "TCP" или "TLS".
    Значение по умолчанию "UDP".
    Значения из переменной LOG_SYSLOG_TYPE конвертируются в классы Syslog4j:
        TSL -> org.productivity.java.syslog4j.impl.net.tcp.ssl.SSLTCPNetSyslogConfig
        TCP -> org.productivity.java.syslog4j.impl.net.tcp.TCPNetSyslogConfig
        UDP -> org.productivity.java.syslog4j.impl.net.udp.UDPNetSyslogConfig

    Если задано значение TLS, то необходимо еще настроить и параметры для SSL
    Документацию по Java KeyStore и Truststore https://docs.oracle.com/cd/E19509-01/820-3503/ggffo/index.html

    LOG_SYSLOG_KEYSTORE
        Путь до файла KEYSTORE

    LOG_SYSLOG_KEYSTORE_PASS
        Пароль для файла в LOG_SYSLOG_KEYSTORE

    LOG_SYSLOG_TRUSTSTORE
        Путь до файла TRUSTSTORE

    LOG_SYSLOG_TRUSTSTORE_PASS
        Пароль для файла в LOG_SYSLOG_TRUSTSTORE

  2. LOG_SYSLOG_PATTERN
    Шаблон для сообщений. Не учитывается для "LOG_OUTPUT = SYSLOG_CEF", т.к. используется шаблон для CEF.
    Документация по шаблонам https://logback.qos.ch/manual/layouts.html#ClassicPatternLayout.
    Значение по умолчанию [%level] [%logger] [%thread] - %msg%n.

  3. LOG_SYSLOG_HOST
    Хост SYSLOG сервиса в формате IPv4. Требуемый формат: IPv4.
    Значение по умолчанию "127.0.0.1".

  4. LOG_SYSLOG_PORT
    Порт SYSLOG сервиса. Может принимать любое положительное число.
    Значение по умолчанию "514".

  5. LOG_SYSLOG_FACILITY
    К сожалению, LOG_SYSLOG_FACILITY задается только через int код, а не string.
    Список кодов для переменной:
    KERN = 0
    USER = 8
    MAIL = 16
    DAEMON = 24
    AUTH = 32
    SYSLOG = 40
    LPR = 48
    NEWS = 56
    UUCP = 64
    CRON = 72
    AUTHPRIV = 80
    FTP = 88

    LOCAL0 = 128
    LOCAL1 = 136
    LOCAL2 = 144
    LOCAL3 = 152
    LOCAL4 = 160
    LOCAL5 = 168
    LOCAL6 = 176
    LOCAL7 = 184

    Значение по умолчанию "8".

  6. LOG_SYSLOG_IDENT
    Идентификатор SYSLOG клиента. Может принимать любую строку.
    Значение по умолчанию зависит от сервиса и обычно является названием сервиса ("mon", "oberto" и т.п.).

  7. LOG_SYSLOG_MAX_MSG_SIZE
    Максимальны размер одного сообщения лога в байтах. Может принимать любое число.
    Значение по умолчанию "65536".

Скрипт для формирования ROOT logger-а для logback.xml

В репозитории сервисов Verdi был добавлен скрипт "logback_config_generation.sc" для формирования ROOT логера. Этот скрипт можно запустить, например, в scala worksheet.

Объявление root логера в конфиге может быть достаточно большим, если количество уникальных вариантов вывода лога больше трех или четырех, т.к. мы должны учитывать все способы вывода из переменной LOG_OUTPUT.
В таком случае, добавление новых опций для вывода становится проблематичным (требует какого-то времени), тогда и может пригодиться данный скрипт.
В конце выполнения, скрипт делает println с получившимся XML-ом, который можно просто вставить в файл с конфигом.

Внутренние команды (Internal command)

Любая команда может быть указанна внутренней (т.е. не требующей авторизации) при задании признака isInternal в передаваемом контексте RequestContext. Механизм обеспечивается логикой LiveObertoClient, поэтому при использовании кастомной имплементации Authorizer стоит обратить внимание на корректность учитывания атрибута.

Задать атрибут isInternal можно 2 способами:

  1. Для конкретного случая отправки команды, напрямую проинициализировав RequestContext и отправив команду через апи VerdiDispatcherImpl

Инициализация RequestContext

val dispatcher: VerdiDispatcherImpl = ???
val cmdName: CommandName = ???
val payload: Json = ???

implicit val internalCtx = RequestContext.builder().withIsInternal(isInternal = true).build()
dispatcher.sendCommandSync(cmdName, payload)
  1. Глобально для всего приложения: необходимо задать в конфиге приложения параметр senderlib.considerAllCommandsAsInternal=true и стандартно проинициализировать VerdiFactory/VerdiTF[F[_]], которые создадут Dispatcher, автоматически устанавливающий атрибут isInternal=true для контекстов всех отправляемых комманд.

ВАЖНО: В реальной инсталляции мы считаем все сервисы (кроме api-gateway) недоступными из публичной сети. Т.е. обращения внешних клиентов обязательно должны проходить авторизацию.

Adapter-folder: адаптер сетевой папки

Основное

Адаптер сетевой папки позволяет экспортировать в систему на основе Verdi (используя data-model) все содержимое указанной папки и в дальнейшем синхронизировать состояние (удалять из Verdi удаленные из папки файлы, доэкспортировать новые и обновлять измененные).

Экспорт осуществляется в виде объекта для сервиса data-model указанного в конфигурации вида, который должен содержать обязательное поле бинарного файла (тип file), а также может содержать часть (или все) из нижеперечисленных полей:

Поддерживаются:

Экспорт происходит при старте адаптера, и далее перезапускается через указанный промежуток времени. Кроме того, адаптер предоставляет HTTP API для вызова внепланового экспорта и восстановления.

Конфигурирование адаптера сетевой папки

Требования к запуску адаптера сетевой папки

Для корректной минимальной работы адаптера требуется:

Список переменных окружения адаптера сетевой папки

Обязательные параметры выделены жирным

Настройки PostgreSQL:

Переменная Описание Значение по умолчанию
ADAPTER_FOLDER_DB_THREADS Количество потоков в пуле потоков для соединения с БД 10
ADAPTER_FOLDER_DB_QUEUE_SIZE Размер очереди для действий базы данных, которые не могут быть выполнены немедленно, когда все потоки заняты. За пределами этого значения новые действия немедленно завершаются неудачей 300
ADAPTER_FOLDER_DB_CONN_MAX Максимальное количество одновременных подключений к БД 10
ADAPTER_FOLDER_DB_CONN_TIMEOUT Максимальное время ожидания ответа для соединения к БД. Если это время превышено, а соединение не становится доступным, будет брошено исключение SQLException. 1000 мс — минимальное значение. 20 second
ADAPTER_FOLDER_DB_ISOLATION Уровень изоляции транзакций для новых подключений. Допустимые значения: NONE, READ_COMMITTED, READ_UNCOMMITTED, REPEATABLE_READ, SERIALIZABLE. "READ_COMMITTED"
ADAPTER_FOLDER_DB_READONLY Read-only SQL транзакция может изменять только временные таблицы. Этот параметр управляет статусом «только для чтения» по умолчанию для каждой новой транзакции. false
ADAPTER_FOLDER_DB_CONN_MIN Минимальное количество одновременных подключений к БД = DB_THREADS
ADAPTER_FOLDER_DB_VALIDATION_TIMEOUT Максимальное время, в течение которого соединение будет проверяться на работоспособность. 1000 мс — минимальное значение. 1 seconds
ADAPTER_FOLDER_DB_IDLE_TIMEOUT Максимальное время, в течение которого соединению разрешено простаивать в пуле. Значение 0 означает, что простаивающие соединения никогда не удаляются из пула. 10 minutes
ADAPTER_FOLDER_DB_MAX_LIFETIME Максимальное время жизни соединения в пуле. Когда простаивающее соединение достигает этого времени ожидания, даже если оно недавно использовалось, оно будет удалено из пула. Значение 0 указывает на отсутствие максимального срока службы. 30 minutes
ADAPTER_FOLDER_DB_INITIALIZATION_FAIL_FAST Deprecated, начиная с версии Slick 3.3.0. Определяет, будет ли пул «быстро выходить из строя», если пул не может быть успешно заполнен начальными соединениями. Если соединения не могут быть созданы во время запуска пула, будет выдано исключение RuntimeException. Это свойство не имеет никакого эффекта, если minConnections равно 0. false
ADAPTER_FOLDER_DB_LEAK_DETECTION_THRESHOLD Время, в течение которого соединение может находиться вне пула, прежде чем будет зарегистрировано сообщение, указывающее на возможную утечку соединения. Значение 0 означает, что обнаружение утечек отключено. Наименьшее приемлемое значение для включения обнаружения утечек составляет 10 с. 0
ADAPTER_FOLDER_DB_CONNECTION_TEST_QUERY Выражение, которое будет выполнено непосредственно перед получением соединения из пула для проверки того, что соединение с базой данных все еще активно. Оно зависит от базы данных и должно представлять собой запрос, требующий минимальной обработки базой данных (например, «VALUES 1»). Если этот параметр не установлен, вместо него используется метод JDBC4 Connection.isValid(). "SELECT 1"
ADAPTER_FOLDER_DB_AUTO_COMMIT Это свойство определяет то, как будут вести себя по умолчанию возвращаемые соединения относительно autocommit-а. true
ADAPTER_FOLDER_DB_SCHEMA Устанавливает schema по умолчанию "public"
ADAPTER_FOLDER_DB_ISOLATE_INTERNAL_QUERIES Определяет то, изолируются ли с помощью транзакций внутренние запросы пула(например запрос connection alive test). Свойство применяется только если autoCommit выключен. false
ADAPTER_FOLDER_DB_INITIALIZATION_FAIL_TIMEOUT Работает, начиная с версии Slick 3.3.0. Определяет, будет ли пул «быстро выходить из строя», если пул не может быть успешно заполнен начальными соединениями. Любое положительное число считается числом миллисекунд для попытки получить начальное соединение;поток приложения будет заблокирован в течение этого периода. Если соединение не может быть получено до истечения этого времени,будет брошено исключение. Данный таймаут применяется после периода connectionTimeout. Если значение равно нулю (0),HikariCP попытается получить и проверить подключение. Если соединение получено,но проверка не пройдена, будет брошено исключение, и пул не будет запущен. Однако,если соединение не может быть получено, пул запустится,но последующие попытки получить соединение могут потерпеть неудачу.Значение меньше нуля пройдет любую первоначальную попытку подключения, и пул немедленно запустится,пытаясь получить соединения в фоновом режиме.Следовательно, последующие попытки получить соединение могут потерпеть неудачу. 1
ADAPTER_FOLDER_DB_REGISTER_MBEANS Зарегистрированы ли JMX Management Beans («MBeans») false

Настройки адаптера:

Переменная Описание Значение по умолчанию
ADAPTER_FOLDER_HTTP_HOST Хост для API адаптера "0.0.0.0"
ADAPTER_FOLDER_HTTP_PORT Порт для API адаптера 9515
ADAPTER_FOLDER_SOURCE_IDENTITY Любой (свой) ID адаптера. Если используется несколько адаптеров, их ID должны различаться -
ADAPTER_FOLDER_EXPORT_DELAY Время между окончанием предыдущей синхронизации и запуском следующей 24 hours
ADAPTER_FOLDER_RECOVER_ON_START Нужен ли запуск восстановления состояния; см. соответствующий раздел false

Настройки рабочей папки:

Переменная Описание Значение по умолчанию
ADAPTER_FOLDER_SOURCE_URI URI до рабочей папки. См формат ниже -
ADAPTER_FOLDER_SOURCE_LOGIN Логин для сетевой папки, если требуется -
ADAPTER_FOLDER_SOURCE_PASSWORD Пароль для сетевой папки, если требуется -
ADAPTER_FOLDER_SOURCE_DOMAIN Домен (WORKGROUP) для сетевой папки, если требуется -
ADAPTER_FOLDER_SOURCE_SMB_MIN_VER Минимальная версия используемого клиентом протокола SMB. См ниже SMB1
ADAPTER_FOLDER_SOURCE_SMB_MAX_VER Максимальная версия используемого клиентом протокола SMB. См ниже SMB210

Настройки обработки файлов:

Переменная Описание Значение по умолчанию
ADAPTER_FOLDER_SOURCE_FILE_ALLOW_HIDDEN Использовать ли скрытые файлы false
ADAPTER_FOLDER_SOURCE_FILE_PRESERVE_EXTENSION Оставлять ли расширение в имени файла false
ADAPTER_FOLDER_SOURCE_FILE_SIZE_LIMIT_KB Максимальный размер отправляемых файлов (не должен превышать INTEGRATION_FS_SIZE_LIMIT_KB сервиса импорта) -

Общие настройки взаимодействия с Verdi:

Переменная Описание Значение по умолчанию
ADAPTER_FOLDER_VERDI_URI Полная ссылка на HTTP API интеграций Verdi (например https://verdiapp/integration/api/external) -
ADAPTER_FOLDER_VERDI_AUTH_TOKEN Токен доступа клиента, от которого используется адаптер -
ADAPTER_FOLDER_VERDI_MAXCON Максимальное количество одновременных запросов от адаптера к Verdi. Максимум - 64. 16
ADAPTER_FOLDER_VERDI_RETRY_MAX_COUNT Максимальное количество ретраев одного запроса к Verdi в случае ошибки 10
ADAPTER_FOLDER_VERDI_RETRY_DELAY Задержка между ретраями запросов к Verdi 10 second
ADAPTER_FOLDER_AKKA_HTTP_CLIENT_IDLE_TIMEOUT Время ожидания ответа от Verdi 5 minutes
ADAPTER_FOLDER_VERDI_TEMP_BINARY_EXPIRATION Время жизни бинарных файлов, не связанных ни с одним объектом, в Verdi 24 hours

Настройки модели данных файла и взаимодействия с Verdi по данной модели (если код какого-либо поля не указан, и настройка этого кода является необязательной, поле не используется в объекте):

Переменная Описание Значение по умолчанию
ADAPTER_FOLDER_FILE_ENTITY_TYPE Код вида сущности из data-model, которая описывает файл -
ADAPTER_FOLDER_FILE_SEND_PER_REQUEST Количество создаваемых (обновляемых, удаляемых) объектов за один запрос 10
ADAPTER_FOLDER_FILE_GET_PER_REQUEST Количество запрашиваемых объектов за раз (в режиме восстановления) 50
ADAPTER_FOLDER_FILE_MAPPING_BINARY_FILE Код поля бинарного файла в модели данных -
ADAPTER_FOLDER_FILE_MAPPING_PATH Код поля пути до файла в модели данных -
ADAPTER_FOLDER_FILE_MAPPING_NAME Код поля названия файла в модели данных -
ADAPTER_FOLDER_FILE_MAPPING_CREATED Код поля времени создания файла в модели данных -
ADAPTER_FOLDER_FILE_MAPPING_MODIFIED Код поля времени изменения файла в модели данных -
ADAPTER_FOLDER_FILE_MAPPING_OWNER Код поля владельца файла в модели данных -
ADAPTER_FOLDER_FILE_MAPPING_OWNER_UNKNOWN_PLACEHOLDER Значение "по умолчанию" для поля владельца файла; используется если владелец неизвестен -

Формат ADAPTER_FOLDER_SOURCE_URI

Для локальных папок используется формат File URI. Примеры:

Для папок, доступных по протоколу сетевых папок SMB, используется следующий формат: smb://server[:port]/share/[path/]. Примеры:

Версии SMB

При использовании протокола SMB, из-за разницы между используемыми клиентом и сервером версий протокола, может возникнуть ошибка подключения.
Переменные ADAPTER_FOLDER_SOURCE_SMB_MIN_VER (по умолчанию SMB1) и ADAPTER_FOLDER_SOURCE_SMB_MAX_VER (по умолчанию SMB2.1) позволяют изменить используемые версии протокола на стороне клиента. Поддерживаемые значения: SMB1, SMB202, SMB210, SMB300, SMB302, SMB311

Состояние и восстановление состояния

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

Для восстановления состояния при перезапуске используется "режим восстановления". Если переменная ADAPTER_FOLDER_RECOVER_ON_START будет указана как true, то при запуске адаптера сначала ( единоразово) будет выполнена синхронизация состояния файлов с состянием в data-model, и только потом запущен плановый экспорт.
Кроме того, режим восстановления может быть запущен в любой момент (когда адаптер не выполняет других задач).

Внеплановый запуск

Адаптер предоставляет HTTP API для внепланового запуска задач (при условии, что в данный момент адаптер не занят другой задачей):

Хост и порт сервера API указываются в конфигурации (см. выше).

Каждый запрос может либо вернуть 423 Locked, если адаптер сейчас занят другой задачей, либо запустить задачу и сразу вернуть 202 Accepted.

Alexandrina-client: клиент для сервиса Alexandrina

Библиотека предоставляет интерфейс и реализацию клиента для сервиса Alexandrina.

Пример создания Alexandrina-client

Пример внедрения зависимости:

make[AlexandrinaClient[F]].from {
  (dispatcher: Dispatcher, ec: ExecutionContext @Id("ec-services"), fromFuture: FromFuture[F]) =>
    implicit val implicitEc: ExecutionContext = ec
    implicit val implicitFf: FromFuture[F] = fromFuture
    new AlexandrinaClientImpl[F](dispatcher)
}

Для того чтобы использовать библиотеку alexandrina-client, нужно добавить зависимость "com.embedika.verdi" %% "alexandrina-client" % verdiVersion.

Все классы находятся в пакете com.embedika.verdi.alexandrina.client.

Основной интерфейс для взаимодействия AlexandrinaClient[F[_]].

Реализация интерфейса AlexandrinaClientImpl[F[_]: FromFuture].

Предоставляемый функционал Alexandrina-client

Alexandrina-client предоставляет методы вызова соответствующих команд сервиса Alexandrina. Формат входных и выходных данных методов Alexandrina-client аналогичен формату входных и выходных данных команд сервиса Alexandrina.

Изменение справочников

Получение справочников

Изменение элементов справочников

Получение элементов справочников

Парсинг, импорт и экспорт справочников

Alexandrina: сервис справочников

Сервис справочников.

Bibliotheca Alexandrina (лат.) - Александрийская библиотека. Команды могут приходить как по HTTP, так и через Kafka в топик alexandrina_commands.

В сервисе реализованы следующие команды:

  1. Создать справочник
  2. Изменить справочник
  3. Удалить справочник
  4. Список справочников
  5. Список справочников по заданным фильтрам
  6. Получить данные справочника
  7. Получить данные справочника (внутренняя)
  8. Получить справочник по коду
  9. Получить справочник по коду (внутренняя)
  10. Экспорт справочников
  11. Экспорт справочников в формате xls
  12. Парсинг справочников
  13. Импорт справочников
  14. Ииформация о справочниках xls из zip-файла
  15. Создать элемент справочника
  16. Изменить элемент справочника
  17. Архивировать элемент справочника
  18. Удалить элемент справочника
  19. Удалить все элементы из справочника
  20. Список элементов справочника
  21. Список элементов справочника (внутренняя)
  22. Список элементов справочника по коду
  23. Список элементов справочника по коду (внутренняя)
  24. Получить данные элемента справочника
  25. Получить данные элемента справочника (внутренняя)
  26. Получить элемент справочника по его коду
  27. Получить элемент справочника по его коду (внутренняя)
  28. Получить данные элементов справочников по списку id
  29. Получить данные элементов справочников по списку id (внутренняя)

Optimistic Lock

У многих команд реализован механизм оптимистичных блокировок. Для этого в данных присутствует поле version. Задача оптимистичных блокировок - предотвратить одновременное редактирование объекта из двух открытых форм. Сначала фронтэнд запрашивает данные объекта и получает в ответе версию данных - поле version. Он прикладывает эту версию в ответе. Если на бэкэнде она совпадает с исходной (не было других модификаций), тогда данные сохраняются, а версия поднимается. Иначе сохранения не происходит, данные не перетираются.

Конфигурирование Alexandrina

Требования к запуску Alexandrina

Запуск сервиса осуществляется локально через sbt, на стенде в docker на jvm.

Для корректной минимальной работы сервиса требуется обязательное подключение к PostgreSQL, Kafka, Consul. Для настройки подключения к ним нужно заполнить обязательные переменные окружения из раздела ниже.

Для нормальной работы сервису дополнительно требуется окружение Verdi: CommandStatus и ApiGateway. В этом случае нужно уделить внимание настройкам, связанным с ServiceDiscovery и CommandDiscovery.

Список переменных окружения Alexandrina

Все доступные переменные окружения для настройки сервиса модели данных.

Переменная Тип Обяза-тельная Значение по умолчанию Описание
ALEXANDRINA_HTTP_HOST string нет "0.0.0.0" Хост, на котором слушает HTTP-сервер
ALEXANDRINA_HTTP_PORT int нет 8192 Порт, на котором слушает HTTP-сервер
ALEXANDRINA_KAFKA_SERVERS string да "localhost:9092" Адрес Kafka
ALEXANDRINA_KAFKA_TOPIC string нет "alexandrina_commands" Название кафка-топика для получения команд. Сервис получает кафка-команды по нему, но и также сам публикует это название в CommandDiscovery.
ALEXANDRINA_CATALOG_EVENTS_TOPIC string нет "catalogEvents" Название кафка-топика для публикации событий над каталогами
ALEXANDRINA_KAFKA_CONSUMER_GROUP string нет "alexandrina" Имя consumer-группы для чтения из кафка-топика команд. Не должна меняться и не должна быть пустой, иначе сервис перечитает свои команды при перезапуске.
ALEXANDRINA_KAFKA_COMMANDEVENT_TOPIC string да "commandevents" Название кафка-топика для отправки сообщений со статусами выполняемых команд. ОБЯЗАТЕЛЬНО должно соответствовать названию этого топика в сервисе статуса команд.
ALEXANDRINA_KAFKA_PARTITIONS int да 10 Количество партиций в топике команд.
ALEXANDRINA_KAFKA_CONSUMER_RESTART_MIN_BACKOFF duration string нет 1 second Минимальная задержка перед перезапуском.
ALEXANDRINA_KAFKA_CONSUMER_RESTART_MAX_BACKOFF duration string нет 30 seconds Максимально возможная задержка перед перезапуском.
ALEXANDRINA_KAFKA_CONSUMER_RESTART_RANDOM_FACTOR double нет 0.2 Коэффициент величины дополнительной случайной задержки(jitter) относительно основной задержки (При значении 0.2 задержка может быть до 20% больше, чем при 0). Если после умножения задержки на ALEXANDRINA_KAFKA_CONSUMER_RESTART_RANDOM_FACTOR получится меньше 1 миллисекунды, то jitter будет приравнен к нулю.
ALEXANDRINA_KAFKA_CONSUMER_RESTART_MAX_RESTARTS int нет 5 Максимальное количество перезапусков в заданный период времени. .После превышения этого числа сервис будет объявлен больным. Все рестарты для каждого отдельного сообщения увеличивают и общий счетчик рестартов консьюмера, поэтому при использовании ALEXANDRINA_KAFKA_CONSUMER_PER_MESSAGE_RESTART_MAX_RESTARTS нужно указывать ALEXANDRINA_KAFKA_CONSUMER_RESTART_MAX_RESTARTS > ALEXANDRINA_KAFKA_CONSUMER_PER_MESSAGE_RESTART_MAX_RESTARTS или не указывать ALEXANDRINA_KAFKA_CONSUMER_PER_MESSAGE_RESTART_MAX_RESTARTS совсем
ALEXANDRINA_KAFKA_CONSUMER_RESTART_MAX_RESTARTS_WITHIN duration string нет 5 minutes Период времени для ограничения перезапусков.
ALEXANDRINA_KAFKA_CONSUMER_PER_MESSAGE_RESTART_MAX_RESTARTS int нет 2 Максимальное количество раз, которое консьюмер перезапустится с неизменной очередью сообщений(в пределах DATA_MODEL_KAFKA_CONSUMER_RESTART_MAX_RESTARTS_WITHIN), прежде чем проигнорировать сообщение, на котором происходит ошибка (Указано количество рестартов, а не прочтений. Если ALEXANDRINA_KAFKA_CONSUMER_RESTART_MAX_RESTARTS = 2, то ошибочное сообщение будет обработано 3 раза, после чего произойдет 3ий рестарт и оно будет проигнорировано). Если указать 0, то перезапуск произойдет, но сообщение будет обработано только в первый раз, когда произошла ошибка. Если указать значение меньше 0, то перезапуски все равно будут происходить, но игнорирование сообщений, вызывающих ошибку, будет отключено.
ALEXANDRINA_KAFKA_CONSUMER_PER_MESSAGE_RESTART_CACHE_SIZE int нет 100 Для каждого сообщения счетчик перепрочтений хранится в кэше. Максимальное количество значений в этом кэше.
ALEXANDRINA_KAFKA_CONSUMER_PER_MESSAGE_RESTART_CACHE_TTL duration string нет 5 minutes Для каждого сообщения счетчик перепрочтений хранится в кэше.Максимальное время жизни элемента в этом кэше. В случае отсутствия значения время жизни элемента не будет ограничено.
ALEXANDRINA_KAFKA_CONSUMER_POLL_TIMEOUT duration string нет 10 milliseconds timeout запроса poll для kafka consumer
ALEXANDRINA_KAFKA_CONSUMER_POLL_INTERVAL duration string нет 100 milliseconds интервал между запросами poll для kafka consumer
ALEXANDRINA_KAFKA_CONSUMER_PROPS string нет "max.poll.records=500;max.partition.fetch.bytes=524288" дополнительные параметры для kafka consumer в формате "key1=value1;key2=value2"
ALEXANDRINA_KAFKA_PRODUCER_MESSAGE_MAX_BYTES int нет 1048576 Лимит в байтах для Kafka сообщений
ALEXANDRINA_KAFKA_AUTH_USER string нет "" Название учетной записи Kafka(в случае аутентификации в kafka с помощью пароля).
ALEXANDRINA_KAFKA_AUTH_PASSWORD string нет "" Пароль учетной записи Kafka(в случае аутентификации в kafka с помощью пароля).
ALEXANDRINA_KAFKA_AUTH_PRINCIPAL string нет "" Principal учетной записи Kafka в Kerberos(в случае аутентификации в kafka через Kerberos).
ALEXANDRINA_KAFKA_AUTH_KEYTAB_PATH string нет "" Путь до keytab-файла(в случае аутентификации в kafka через Kerberos).
ALEXANDRINA_KAFKA_AUTH_TRUSTSTORE_LOCATION string нет "" Путь до хранилища сертификатов (Java key store). Если путь не указан, то сертификат применяться не будет.
ALEXANDRINA_KAFKA_AUTH_TRUSTSTORE_PASSWORD string нет "" Пароль к хранилищу сертификатов.
ALEXANDRINA_KAFKA_AUTH_MODE string нет "" Режим аутентификации: static - одна учетная запись на все запросы, mapping - учетная запись зависит от запроса
ALEXANDRINA_KAFKA_AUTH_CONFIG string нет "" Настройки для аутентификации: если AuthMode = mapping, то необходим JSON с List[KafkaAuthConfig]. Переменная соответствует полю authConfig из KafkaAuthSettings.
ALEXANDRINA_KAFKA_AUTH_CACHE_SIZE int нет Максимальный размер кеша для Kafka producer (количество активных соединений).
ALEXANDRINA_KAFKA_CONNECTION_CHECK_TEST_MESSAGES_INTERVAL duration string нет 4 minutes Применяется только для producer-ов со способом аутентификации kerberos. Интервал отправки тестовых сообщений кафки в топик connectionCheck.testMessagesTopicName. Тестовые сообщения (null, service producer test) отправляются регулярно с этим интервалом.
ALEXANDRINA_KAFKA_CONNECTION_CHECK_INTERVAL duration string нет 60 seconds Применяется только для producer-ов со способом аутентификации kerberos. Интервал проверки того, сколько тестовых сообщений было отправлено за данный период. Если количество сообщений за этот период равно количеству сообщений за прошлый период, то начинается отсчет периода без сообщений.
ALEXANDRINA_KAFKA_CONNECTION_CHECK_FAILED_AFTER_INTERVAL duration string нет 5 minutes Применяется только для producer-ов со способом аутентификации kerberos. Максимальная продолжительность периода без успешно отправленных тестовых сообщений. По ее достижении сервис будет объявлен больным.
ALEXANDRINA_KAFKA_AUTH_CACHE_TTL duration string нет Время жизни Kafka producer в кеше.
ALEXANDRINA_CONSUL_ADDR url string да "http://localhost:8500" Адрес Сonsul.
ALEXANDRINA_CONSUL_AUTH_USER string нет "" Название учетной записи Сonsul. Если название не указано, то настройки авторизации не будут применены.
ALEXANDRINA_CONSUL_AUTH_PASSWORD string нет "" Пароль учетной записи Сonsul.
ALEXANDRINA_TRACE_DURATION boolean нет false Признак необходимости трассировки выполнения команд
ALEXANDRINA_DISCOVERABLE_ID string нет "alexandrina_instance" ID сервиса в ServiceDiscovery
ALEXANDRINA_DISCOVERABLE_NAME string нет "alexandrina" Имя сервиса в ServiceDiscovery
ALEXANDRINA_DISCOVERABLE_HOST string да "localhost" Хост, публикуемый в ServiceDiscovery. По нему на данный сервис будут обращаться другие через HTTP. Указанный адрес должен быть виден другим сервисам. Пример: имя kubernetes/docker_swarm service
ALEXANDRINA_DISCOVERABLE_PORT int нет Порт, публикуемый в ServiceDiscovery. По нему на данный сервис будут обращаться другие через HTTP. По умолчанию указывается порт, который слушает HTTP-сервер.
ALEXANDRINA_DISCOVERABLE_LIVETIME duration string нет 2 minutes Период после последней отправки health check, в течение которого ServiceDiscovery считает данный сервис живым.
ALEXANDRINA_DISCOVERABLE_HEALTHPASS string нет 1 minute Периодичность отправки health check в ServiceDiscovery
ALEXANDRINA_AKKA_HTTP_CLIENT_MAXCON int нет 512 Максимальное число одновременных исходящих HTTP-соединений
ALEXANDRINA_AKKA_HTTP_CLIENT_MAXREQ int нет 1024 Максимальное число одновременных исходящих HTTP-запросов
ALEXANDRINA_AKKA_HTTP_SERVER_MAXCON int нет 1024 Максимальное число одновременных входящих HTTP-соединений
ALEXANDRINA_INTERNALCMD_ALLOW bool нет false Можно ли сервису отправлять внутрисистемные команды
ALEXANDRINA_SENDERLIB_COMMANDS_CACHE_UPDATEPERIOD duration string нет 10 minutes Время кэширования данных по командам из CommandDiscovery
ALEXANDRINA_SENDERLIB_SERVICES_CACHE_UPDATEPERIOD duration string нет 30 seconds Время кэширования данных по сервисам из ServiceDiscovery
ALEXANDRINA_DB_HOST string да Хост БД
ALEXANDRINA_DB_PORT int да Порт БД
ALEXANDRINA_DB_NAME string да Имя базы в БД
ALEXANDRINA_DB_URL jdbc url string нет JDBC-url для соединения с БД. По умолчанию собирается из других обязательных переменных. Можно указать только его, если не хочется отдельно указывать хост/порт/имя базы.
ALEXANDRINA_DB_USER string да Пользователь БД
ALEXANDRINA_DB_PASSWORD string да Пароль пользователя БД
ALEXANDRINA_DB_THREADS int нет 10 Количество потоков в пуле потоков для соединения с БД
ALEXANDRINA_DB_QUEUE_SIZE int нет 300 Размер очереди для действий базы данных, которые не могут быть выполнены немедленно, когда все потоки заняты. За пределами этого значения новые действия немедленно завершаются неудачей
ALEXANDRINA_DB_CONN_MAX int нет 10 Максимальное количество одновременных подключений к БД
ALEXANDRINA_DB_CONN_TIMEOUT duration string нет 20 second Максимальное время ожидания ответа для соединения к БД. Если это время превышено, а соединение не становится доступным, будет брошено исключение SQLException. 1000 мс — минимальное значение.
ALEXANDRINA_DB_ISOLATION string нет "READ_COMMITTED" Уровень изоляции транзакций для новых подключений. Допустимые значения: NONE, READ_COMMITTED, READ_UNCOMMITTED, REPEATABLE_READ, SERIALIZABLE.
ALEXANDRINA_DB_READONLY boolean нет false Read-only SQL транзакция может изменять только временные таблицы. Этот параметр управляет статусом «только для чтения» по умолчанию для каждой новой транзакции.
ALEXANDRINA_DB_CONN_MIN int нет = DB_THREADS Минимальное количество одновременных подключений к БД
ALEXANDRINA_DB_VALIDATION_TIMEOUT duration string нет 1 seconds Максимальное время, в течение которого соединение будет проверяться на работоспособность. 1000 мс — минимальное значение.
ALEXANDRINA_DB_IDLE_TIMEOUT duration string нет 10 minutes Максимальное время, в течение которого соединению разрешено простаивать в пуле. Значение 0 означает, что простаивающие соединения никогда не удаляются из пула.
ALEXANDRINA_DB_MAX_LIFETIME duration string нет 30 minutes Максимальное время жизни соединения в пуле. Когда простаивающее соединение достигает этого времени ожидания, даже если оно недавно использовалось, оно будет удалено из пула. Значение 0 указывает на отсутствие максимального срока службы.
ALEXANDRINA_DB_INITIALIZATION_FAIL_FAST string нет false Deprecated, начиная с версии Slick 3.3.0. Определяет, будет ли пул «быстро выходить из строя», если пул не может быть успешно заполнен начальными соединениями. Если соединения не могут быть созданы во время запуска пула, будет выдано исключение RuntimeException. Это свойство не имеет никакого эффекта, если minConnections равно 0.
ALEXANDRINA_DB_LEAK_DETECTION_THRESHOLD int нет 0 Время, в течение которого соединение может находиться вне пула, прежде чем будет зарегистрировано сообщение, указывающее на возможную утечку соединения. Значение 0 означает, что обнаружение утечек отключено. Наименьшее приемлемое значение для включения обнаружения утечек составляет 10 с.
ALEXANDRINA_DB_CONNECTION_TEST_QUERY string нет "SELECT 1" Выражение, которое будет выполнено непосредственно перед получением соединения из пула для проверки того, что соединение с базой данных все еще активно. Оно зависит от базы данных и должно представлять собой запрос, требующий минимальной обработки базой данных (например, «VALUES 1»). Если этот параметр не установлен, вместо него используется метод JDBC4 Connection.isValid().
ALEXANDRINA_DB_AUTO_COMMIT boolean нет true Это свойство определяет то, как будут вести себя по умолчанию возвращаемые соединения относительно autocommit-а.
ALEXANDRINA_DB_SCHEMA string нет "public" Устанавливает schema по умолчанию
ALEXANDRINA_DB_ISOLATE_INTERNAL_QUERIES boolean нет false Определяет то, изолируются ли с помощью транзакций внутренние запросы пула(например запрос connection alive test). Свойство применяется только если autoCommit выключен.
ALEXANDRINA_DB_INITIALIZATION_FAIL_TIMEOUT int нет 1 Работает, начиная с версии Slick 3.3.0. Определяет, будет ли пул «быстро выходить из строя», если пул не может быть успешно заполнен начальными соединениями. Любое положительное число считается числом миллисекунд для попытки получить начальное соединение;поток приложения будет заблокирован в течение этого периода. Если соединение не может быть получено до истечения этого времени,будет брошено исключение. Данный таймаут применяется после периода connectionTimeout. Если значение равно нулю (0),HikariCP попытается получить и проверить подключение. Если соединение получено,но проверка не пройдена, будет брошено исключение, и пул не будет запущен. Однако,если соединение не может быть получено, пул запустится,но последующие попытки получить соединение могут потерпеть неудачу.Значение меньше нуля пройдет любую первоначальную попытку подключения, и пул немедленно запустится,пытаясь получить соединения в фоновом режиме.Следовательно, последующие попытки получить соединение могут потерпеть неудачу.
ALEXANDRINA_DB_REGISTER_MBEANS boolean нет false Зарегистрированы ли JMX Management Beans («MBeans»)
ALEXANDRINA_TEMP_BUCKET string нет temp Бакет в файловом хранилище для временных файлов, загружаемых на gateway
ALEXANDRINA_EXPORT_BUCKET string нет export Бакет в файловом хранилище для генерируемых экспортом файлов
ALEXANDRINA_READABLE_NAME string нет "Сервис справочников" Читаемое название этого сервиса
ALEXANDRINA_DESCRIPTION string нет "Сервис хранения данных справочников" Читаемое описание этого сервиса
ALEXANDRINA_FS_URI url string нет "http://localhost:9000" Адрес для подключения к хранилищу файлов по S3-API
ALEXANDRINA_FS_ACCESS_KEY_ID string нет minioadmin Ключ доступа для хранилища файлов (aka логин)
ALEXANDRINA_FS_SECRET_ACCESS_KEY string нет minioadmin Секретный ключ для хранилища файлов (aka пароль)
ALEXANDRINA_FS_UPLOAD_PARALLELISM int нет 4 Параллелизм для загрузки файлов
ALEXANDRINA_FS_AUTH_MODE string нет static Режим аутентификации: static - одна учетная запись на все запросы, mapping - учетная запись зависит от запроса
ALEXANDRINA_FS_AUTH_CONFIG string нет "" Настройки для аутентификации: если AuthMode = mapping, то необходим JSON с маппингом учетных записей
ALEXANDRINA_FS_CACHE_SIZE int нет 1 Максимальный размер кеша клиентов для хранилища файлов (количество активных соединений).
ALEXANDRINA_FS_CACHE_TTL duration string нет Время жизни клиента в кеше
ALEXANDRINA_FS_RETRY_ATTEMPTS int нет 5 Количество ретраев, которое будет произведено в случае Exception-а в операции FSClient-а и при вычитывании стрима в get операциях FSClient-а.
ALEXANDRINA_FS_RETRY_DELAY duration string нет 10 millis Задержка между ретраями операций FSClient-а.
ALEXANDRINA_FS_ZIO_SHORT_MESSAGE_MODE boolean нет false Флаг включения режима сохранения ошибок работы с файловым хранилищем в сервисе журналирования nestor. При включении режима ошибки в логах будут отображаться в сокращенном формате: Short zio message mode. ExceptionType: ТИП ОШИБКИ, Exception id: 'СГЕНЕРИРОВАННЫЙ UUID' added to journal. Указанный id будет фиксироваться в event записи nestor'а в поле data.id
ALEXANDRINA_SENDERLIB_COMMANDS_HTTP_RETRY_ATTEMPTS int нет 5 Поле attempts из RetrySettings
ALEXANDRINA_SENDERLIB_COMMANDS_HTTP_RETRY_DELAY duration string нет "5 seconds" Поле delay из RetrySettings
ALEXANDRINA_SENDERLIB_COMMANDS_HTTP_RETRY_KIND string нет "OnSomeExceptions(ConnectException)" CommandResultRetryConditionKind
ALEXANDRINA_SENDERLIB_CONSUL_CONNECTION_RETRY_MAX int нет 5 Количество попыток переподключения к Consul
ALEXANDRINA_SENDERLIB_CONSUL_CONNECTION_RETRY_DELAY duration string нет "1 second" Задержка при попытках переподключения к Consul
ALEXANDRINA_JOURNAL_MODE string нет WriteToJournal Режим журналирования Nestor. Допустимые значения: WriteToJournal (Отправка в сервис журналирования), WriteToTopic (Отправка события в очередь)
ALEXANDRINA_JOURNAL_TOPIC string да, если переменная ALEXANDRINA_JOURNAL_MODE = WriteToTopic "" Название очереди журналирования. Для режима WriteToJournal значение игнорируется.

Команды для сервиса Alexandrina

Список реализованных в сервисе команд, моделей EntityType и действий Actions, которые можно использовать при настройке авторизации. Не все поля EntityType доступны для использования в настройке авторизации. Если указан прочерк "-", то данное значение не влияет на авторизацию:

Название команды EntityType Actions
createCatalog Catalog CreateCatalog
updateCatalog Catalog UpdateCatalog
removeCatalog Catalog DeleteCatalog
listCatalogs Catalog ReadCatalogs
searchCatalogs Catalog ReadCatalogs
getCatalog Catalog ReadCatalog
internalGetCatalog - -
getCatalogByCode Catalog ReadCatalog
internalGetCatalogByCode - -
exportCatalogs Catalog CatalogsExport
exportCatalogsXls Catalog CatalogsExport
parseCatalogs Catalog CatalogsParse
parseCatalogsXls Catalog CatalogsParse
importCatalogs Catalog CatalogsImport
createCatalogItem CatalogItem CreateCatalogItem
updateCatalogItem CatalogItem UpdateCatalogItem
archiveCatalogItem CatalogItem ArchiveCatalogItem
removeCatalogItem CatalogItem DeleteCatalogItem
removeItemsFromCatalog CatalogItem DeleteCatalogItems
listItemsByCatalog CatalogItem ReadCatalogItems
internalListItemsByCatalog - -
listItemsByCatalogCode CatalogItem ReadCatalogItems
internalListItemsByCatalogCode - -
getCatalogItem CatalogItem ReadCatalogItem
internalGetCatalogItem - -
getCatalogItemByCode CatalogItem ReadCatalogItem
internalGetCatalogItemByCode - -
getCatalogItemBatch CatalogItem ReadCatalogsItems
internalGetCatalogItemBatch - -

CreateCatalog (Alexandrina)

На входе данные справочника

{
  "code": "cities",
  "title": "Города",
  "metadata": {},
  "isProtected": false
}

На выходе строка с id созданного справочника

"0effa436-06c2-42cc-befe-8ebec417fc5a"

Создание справочника. Отправляет событие о создании справочника.

Имя вызова команды: createCatalog.
Поддерживается асинхронный и синхронный вызов.
Результат выполнения команды журналируется.

UpdateCatalog (Alexandrina)

На входе данные справочника

{
  "id": "0effa436-06c2-42cc-befe-8ebec417fc5a",
  "code": "cities",
  "title": "Города",
  "metadata": {},
  "version": 2,
  "isProtected": false
}

На выходе количество обновленных записей

0

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

Имя вызова команды: updateCatalog.
Поддерживается асинхронный и синхронный вызов.
Результат выполнения команды журналируется.

RemoveCatalog (Alexandrina)

На входе ID справочника

"0effa436-06c2-42cc-befe-8ebec417fc5a"

На выходе признак успешности

true

Удаление справочника и всех его элементов. Отправляет событие об удалении справочника и всех его элементов.

Имя вызова команды: removeCatalog.
Поддерживается асинхронный и синхронный вызов.
Результат выполнения команды журналируется.

ListCatalogs (Alexandrina)

Входных данных нет

На выходе список справочников

[
  {
    "id": "0effa436-06c2-42cc-befe-8ebec417fc5a",
    "code": "cities",
    "title": "Города",
    "metadata": {},
    "modified": 1632978484446,
    "version": 1,
    "items": 4,
    "isProtected": false
  }
]

Получение списка всех справочников. Пока без пейджинга, сортировки, и т.п.

Имя вызова команды: listCatalogs.
Поддерживается только синхронный вызов.
Результат выполнения команды не журналируется.

SearchCatalogs (Alexandrina)

На входе параметры для поиска справочников

{
  "query": "",
  "context": {},
  "sorting": {
    "fieldName": "title",
    "order": "asc"
  },
  "paging": {
    "page": 1,
    "count": 10
  }
}

На выходе список справочников в структуре Page

{
  "items": [
    {
      "id": "0effa436-06c2-42cc-befe-8ebec417fc5a",
      "code": "cities",
      "title": "Города",
      "metadata": {},
      "modified": 1632978484446,
      "version": 1,
      "items": 4,
      "isProtected": false
    }
  ],
  "total": 1
}

Получение списка справочников с возможностью фильтрации, сортировки и пагинации.

Имя вызова команды: searchCatalogs.
Поддерживается только синхронный вызов.
Результат выполнения команды не журналируется.

По умолчанию сортировка производится по полю code.

Запрос принимает параметры сортировки, фильтров и пейджинга в параметре search с типом Search. Применяется к полям модели Catalog.

Доступные поля для фильтрации и виды фильтров по ним:

Поле Виды фильтров
code InSetQuery, LikeQuery
title InSetQuery, LikeQuery

Доступные поля для сортировки:

Поле
code
title

GetCatalog (Alexandrina)

На входе ID справочника

"0effa436-06c2-42cc-befe-8ebec417fc5a"

На выходе данные справочника

{
  "id": "0effa436-06c2-42cc-befe-8ebec417fc5a",
  "code": "cities",
  "title": "Города",
  "metadata": {},
  "modified": 1632978484446,
  "version": 1,
  "items": 4,
  "isProtected": false
}

Получение данных справочника по ID.

Имя вызова команды: getCatalog.
Поддерживается только синхронный вызов.
Результат выполнения команды не журналируется.

InternalGetCatalog (Alexandrina)

На входе ID справочника

"0effa436-06c2-42cc-befe-8ebec417fc5a"

На выходе данные справочника

{
  "id": "0effa436-06c2-42cc-befe-8ebec417fc5a",
  "code": "cities",
  "title": "Города",
  "metadata": {},
  "modified": 1632978484446,
  "version": 1,
  "items": 4,
  "isProtected": false
}

Получение данных справочника по ID.

Имя вызова команды: internalGetCatalog.
Поддерживается только синхронный вызов.
Результат выполнения команды не журналируется.

Внутренняя команда не требующая авторизацию.

GetCatalogByCode (Alexandrina)

На входе код справочника

"cities"

На выходе данные справочника

{
  "id": "0effa436-06c2-42cc-befe-8ebec417fc5a",
  "code": "cities",
  "title": "Города",
  "metadata": {},
  "modified": 1632978484446,
  "version": 1,
  "items": 4,
  "isProtected": false
}

Получение данных справочника по коду.

Имя вызова команды: getCatalogByCode.
Поддерживается только синхронный вызов.
Результат выполнения команды не журналируется.

InternalGetCatalogByCode (Alexandrina)

На входе код справочника

"cities"

На выходе данные справочника

{
  "id": "0effa436-06c2-42cc-befe-8ebec417fc5a",
  "code": "cities",
  "title": "Города",
  "metadata": {},
  "modified": 1632978484446,
  "version": 1,
  "items": 4,
  "isProtected": false
}

Получение данных справочника по коду.

Имя вызова команды: internalGetCatalogByCode.
Поддерживается только синхронный вызов.
Результат выполнения команды не журналируется.

Внутренняя команда не требующая авторизацию.

ExportCatalogs (Alexandrina)

На входе ID справочников и признак исключения из выгрузки (опциональный)

{
  "ids": [
    "ac94000f-3b61-4327-b2db-2ed0c2f01b38",
    "0c69afa4-2a1f-45ad-8269-a9d14d7b7a7d"
  ],
  "exclude": false
}

На выходе URL сформированного JSON-файла

"export/71ab0531-f916-4b46-9bb5-e7684940d3df"

Выгрузка массива справочников в хранилище файлов в формате JSON. Результат команды - url этого файла, который можно передать в метод /download. Параметр exclude: false позволяет выгрузить справочники с переданными ID (по умолчанию), true - все справочники, кроме справочников с переданными ID.

Имя вызова команды: exportCatalogs.
Поддерживается только синхронный вызов.
Результат выполнения команды не журналируется.

ExportCatalogsXls (Alexandrina)

На входе ID справочников и признак исключения из выгрузки (опциональный)

{
  "ids": [
    "ac94000f-3b61-4327-b2db-2ed0c2f01b38",
    "0c69afa4-2a1f-45ad-8269-a9d14d7b7a7d"
  ],
  "exclude": false
}

На выходе URL сформированного zip-файла

"export/71ab0531-f916-4b46-9bb5-e7684940d3df"

Выгрузка массива справочников (в виде xls файлов) в хранилище файлов в формате Zip. Результат команды - url этого файла, который можно передать в метод /download. Параметр exclude: false позволяет выгрузить справочники с переданными ID (по умолчанию), true - все справочники, кроме справочников с переданными ID.

Имя вызова команды: exportCatalogsXls.
Поддерживается только синхронный вызов.
Результат выполнения команды не журналируется.

ParseCatalogs (Alexandrina)

На входе ID файла

"71ab0531-f916-4b46-9bb5-e7684940d3df"

Пример JSON файла с указанным ID

{
  "version": "1.0",
  "dataType": "catalogs",
  "data": [
    {
      "code": "cities",
      "title": "Города",
      "metadata": {},
      "items": [
        {
          "code": "Moscow",
          "title": "Москва",
          "archived": false,
          "metadata": {
            "status": "federal"
          },
          "isProtected": false
        },
        {
          "code": "Tyumen",
          "title": "Тюмень",
          "archived": false,
          "metadata": {},
          "isProtected": false
        }
      ],
      "isProtected": false
    },
    {
      "code": "countries",
      "title": "Страны",
      "metadata": {},
      "items": [],
      "isProtected": false
    }
  ]
}

На выходе массив справочников с элементами и признаком наличия

[
  {
    "code": "cities",
    "title": "Города",
    "metadata": {},
    "items": [
      {
        "code": "Moscow",
        "title": "Москва",
        "archived": false,
        "metadata": {
          "status": "federal"
        }
      },
      {
        "code": "Tyumen",
        "title": "Тюмень",
        "archived": false,
        "metadata": {}
      }
    ],
    "present": true
  },
  {
    "code": "countries",
    "title": "Страны",
    "metadata": {},
    "items": [],
    "present": false
  }
]

Парсинг JSON-файла со справочниками.

Параметр present: true - справочник с таким кодом существует, false - отсутствует.

Имя вызова команды: parseCatalogs.
Поддерживается только синхронный вызов.
Результат выполнения команды не журналируется.

ImportCatalogs (Alexandrina)

На входе массив справочников с элементами

[
  {
    "code": "countries",
    "title": "Страны",
    "metadata": {},
    "isProtected": false,
    "ignoreProtection": true,
    "items": [
      {
        "code": "Russia",
        "title": "Россия",
        "archived": false,
        "metadata": {},
        "isProtected": false
      }
    ]
  }
]

На выходе количество обновленных/добавленных справочников

{
  "failedImport": [
    {
      "code": "countries",
      "items": [
        {
          "code": "Russia"
        }
      ]
    }
  ]
}

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

Имя вызова команды: importCatalogs.
Поддерживается асинхронный и синхронный вызов.
Результат выполнения команды журналируется.

ParseCatalogsXls (Alexandrina)

На входе

{
  "fileUrl": "export/241f94cd-e4ef-4191-a7c9-c96352eeb5dc",
  "startRow": 2,
  "targetFileNames": [
    "Профессия.xls"
  ]
}

На выходе содержимое zip файла

{
  "importData": [
    {
      "fileName": "Профессия.xls",
      "extension": "xls",
      "title": "Профессия",
      "code": "proffff",
      "present": true,
      "metadata": {},
      "items": [
        {
          "code": "proffff-1",
          "title": "Аналитик",
          "archived": false,
          "metadata": {},
          "isProtected": true
        },
        {
          "code": "proffff-2",
          "title": "Разработчик",
          "archived": false,
          "metadata": {},
          "isProtected": true
        },
        {
          "code": "proffff-3",
          "title": "Тестировщик",
          "archived": false,
          "metadata": {},
          "isProtected": true
        }
      ]
    }
  ],
  "rejectedFiles": []
}

Структура обязательного содержимого в таблице xls.

Колонка 1 - Код - string.

Колонка 2 - Наименование - string.

Колонка 3 - Метаданные - json.

Колонка 4 - Архивирован - "Да", "Нет", "ЛОЖЬ", "ИСТИНА", "Актуально", "Неактуально".

Колонка 5 - Защищен - "Да", "Нет", "ЛОЖЬ", "ИСТИНА", "Актуально", "Неактуально".

Колонки могут быть в разных позициях, информация считывается не по позиции в таблице, а по имени колонки.

Пример содержимого таблицы в xls файле.

Код Наименование Метаданные Архивирован Защищен Создан Изменен ID
proffff-1 Аналитик object[] Да Нет 1,72891E+12 1,72891E+12 0ea026f1-d065-47e4-9dbf-5a4555c6247e
proffff-2 Разработчик object[] Да Нет 1,72891E+12 1,72891E+12 0ea026f1-d065-47e4-9dbf-5a4555c6247e
proffff-3 Тестировщик object[] Да Нет 1,72891E+12 1,72891E+12 0ea026f1-d065-47e4-9dbf-5a4555c6247e

Другие варианты структур будут парситься неверно.

Роут работает в связке с роутом ExportCatalogsXls, который формирует zip с xls файлом внутри.

Задача команды - предоставить информацию о содержимом файлов, что содержатся в переданном zip-архиве, либо содержимом переданного файла xls или xlsx. Файлы других расширений игнорируются. Если в строчках xls/xlsx данные не распарсились, берем информацию из базы данных.

Имя вызова команды: parseCatalogsXls.
Поддерживается синхронный вызов.
Результат выполнения команды не журналируется.

CreateCatalogItem (Alexandrina)

На входе данные элемента справочника

{
  "catalogId": "0effa436-06c2-42cc-befe-8ebec417fc5a",
  "code": "moscow",
  "title": "Москва",
  "metadata": {},
  "isProtected": false
}

На выходе строка с ID созданного элемента справочника

"cee05b97-ca41-4355-8565-d667c6807cbd"

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

Имя вызова команды: createCatalogItem.
Поддерживается асинхронный и синхронный вызов.
Результат выполнения команды журналируется.

UpdateCatalogItem (Alexandrina)

На входе данные элемента справочника

{
  "id": "cee05b97-ca41-4355-8565-d667c6807cbd",
  "code": "moscow",
  "title": "Москва",
  "metadata": {},
  "version": 2,
  "isProtected": false
}

На выходе количество измененных записей

0

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

Имя вызова команды: updateCatalogItem.
Поддерживается асинхронный и синхронный вызов.
Результат выполнения команды журналируется.

ArchiveCatalogItem (Alexandrina)

На входе ID элемента справочника и признак архивности

{
  "id": "cee05b97-ca41-4355-8565-d667c6807cbd",
  "archived": true
}

На выходе признак успешности

true

Архивирование элемента справочника. Отправляет событие об обновлении элемента справочника.

Имя вызова команды: archiveCatalogItem.
Поддерживается асинхронный и синхронный вызов.
Результат выполнения команды не журналируется.

RemoveCatalogItem (Alexandrina)

На входе ID элемента справочника

"cee05b97-ca41-4355-8565-d667c6807cbd"

На выходе признак успешности

true

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

Имя вызова команды: removeCatalogItem.
Поддерживается асинхронный и синхронный вызов.
Результат выполнения команды журналируется.

RemoveItemsFromCatalog (Alexandrina)

На входе ID справочника

"0effa436-06c2-42cc-befe-8ebec417fc5a"

На выходе количество удаленных элементов справочника

15

Удаление всех элементов из справочника.

Имя вызова команды: removeItemsFromCatalog.
Поддерживается асинхронный и синхронный вызов.
Результат выполнения команды журналируется.

ListItemsByCatalog (Alexandrina)

На входе параметры для поиска элементов справочника, ID которого указан

{
  "data": "0effa436-06c2-42cc-befe-8ebec417fc5a",
  "search": {
    "query": "",
    "context": {},
    "sorting": {
      "fieldName": "title",
      "order": "asc"
    },
    "paging": {
      "page": 1,
      "count": 10
    }
  }
}

На выходе список элементов справочника

{
  "items": [
    {
      "id": "cee05b97-ca41-4355-8565-d667c6807cbd",
      "catalogId": "0effa436-06c2-42cc-befe-8ebec417fc5a",
      "code": "moscow",
      "title": "Москва",
      "archived": false,
      "metadata": {},
      "created": 1632978484446,
      "modified": 1632979205601,
      "version": 2,
      "isProtected": false
    }
  ],
  "total": 1
}

Получение списка всех элементов указанного справочника.

Имя вызова команды: listItemsByCatalog.
Поддерживается только синхронный вызов.
Результат выполнения команды не журналируется.

По умолчанию сортировка производится по полю title.

Запрос принимает параметры сортировки, фильтров и пейджинга в параметре search с типом Search. Применяется к полям модели CatalogItem.

Доступные поля для фильтрации и виды фильтров по ним:

Поле Виды фильтров
id InSetQuery, LikeQuery
catalogId InSetQuery, LikeQuery
code InSetQuery, LikeQuery
title InSetQuery, LikeQuery
archived InSetQuery
created InSetQuery, LikeQuery, RangeQuery
modified InSetQuery, LikeQuery, RangeQuery

Если поле для фильтрации имеет вид metadata.something, то фильтрация идет по содержимому соответствующего поля в metadata. Для этих фильтров поддерживаются виды AllInSetQuery (только для вложенных полей-массивов), InSetQuery, LikeQuery, RangeQuery (только для вложенных полей-чисел).

В случае если название поля не совпадает с одним из названий из таблицы выше и не имеет префикса metadata (например, поле something), будет возвращена ошибка.

В случае если запрос InSetQuery или LikeQuery производится по содержимому поля json-объекта, которое не является строкой, то объект будет приведен к строке, содержащей json, и поиск будет произведен по ней.

В случае если запрос AllInSetQuery производится по содержимому поля json-объекта, которое не является массивом, то вернется ошибка. В случае если запрос RangeQuery производится по содержимому поля json-объекта, которое не является числом, то вернется ошибка.

Доступные поля для сортировки:

Поле
code
created
modified
metadata.*

Для полей metadata.* реализована натуральная сортировка.

InternalListItemsByCatalog (Alexandrina)

На входе параметры для поиска элементов справочника, ID которого указан

{
  "data": "0effa436-06c2-42cc-befe-8ebec417fc5a",
  "search": {
    "query": "",
    "context": {},
    "sorting": {
      "fieldName": "title",
      "order": "asc"
    },
    "paging": {
      "page": 1,
      "count": 10
    }
  }
}

На выходе список элементов справочника

{
  "items": [
    {
      "id": "cee05b97-ca41-4355-8565-d667c6807cbd",
      "catalogId": "0effa436-06c2-42cc-befe-8ebec417fc5a",
      "code": "moscow",
      "title": "Москва",
      "archived": false,
      "metadata": {},
      "created": 1632978484446,
      "modified": 1632979205601,
      "version": 2,
      "isProtected": false
    }
  ],
  "total": 1
}

Получение списка всех элементов указанного справочника.

Имя вызова команды: internalListItemsByCatalog.
Поддерживается только синхронный вызов.
Результат выполнения команды не журналируется.

Команда только внутренняя (нельзя вызвать через Api Gateway), не требует аутентификации.

По умолчанию сортировка производится по полю title.

Запрос принимает параметры сортировки, фильтров и пейджинга в параметре search с типом Search. Применяется к полям модели CatalogItem.

Доступные поля для фильтрации и виды фильтров по ним:

Поле Виды фильтров
id InSetQuery, LikeQuery
catalogId InSetQuery, LikeQuery
code InSetQuery, LikeQuery
title InSetQuery, LikeQuery
archived InSetQuery
created InSetQuery, LikeQuery, RangeQuery
modified InSetQuery, LikeQuery, RangeQuery

Если поле для фильтрации имеет вид metadata.something, то фильтрация идет по содержимому соответствующего поля в metadata. Для этих фильтров поддерживаются виды AllInSetQuery (только для вложенных полей-массивов), InSetQuery, LikeQuery, RangeQuery (только для вложенных полей-чисел).

В случае если название поля не совпадает с одним из названий из таблицы выше и не имеет префикса metadata (например, поле something), будет возвращена ошибка.

В случае если запрос InSetQuery или LikeQuery производится по содержимому поля json-объекта, которое не является строкой, то объект будет приведен к строке, содержащей json, и поиск будет произведен по ней.

В случае если запрос AllInSetQuery производится по содержимому поля json-объекта, которое не является массивом, то вернется ошибка. В случае если запрос RangeQuery производится по содержимому поля json-объекта, которое не является числом, то вернется ошибка.

Доступные поля для сортировки:

Поле
code
created
modified
metadata.*

Для полей metadata.* реализована натуральная сортировка.

ListItemsByCatalogCode (Alexandrina)

На входе параметры для поиска элементов справочника, код которого указан

{
  "data": "cities",
  "search": {
    "query": "",
    "context": {},
    "sorting": {
      "fieldName": "title",
      "order": "asc"
    },
    "paging": {
      "page": 1,
      "count": 10
    }
  }
}

На выходе список элементов справочника

{
  "items": [
    {
      "id": "cee05b97-ca41-4355-8565-d667c6807cbd",
      "catalogId": "0effa436-06c2-42cc-befe-8ebec417fc5a",
      "code": "moscow",
      "title": "Москва",
      "archived": false,
      "metadata": {},
      "created": 1632978484446,
      "modified": 1632979205601,
      "version": 2,
      "isProtected": false
    }
  ],
  "total": 1
}

Получение списка всех элементов указанного справочника по коду справочника.

Имя вызова команды: listItemsByCatalogCode.
Поддерживается только синхронный вызов.
Результат выполнения команды не журналируется.

По умолчанию сортировка производится по полю title.

Запрос принимает параметры сортировки, фильтров и пейджинга в параметре search с типом Search. Применяется к полям модели CatalogItem.

Доступные поля для фильтрации и виды фильтров по ним:

Поле Виды фильтров
id InSetQuery, LikeQuery
catalogId InSetQuery, LikeQuery
code InSetQuery, LikeQuery
title InSetQuery, LikeQuery
archived InSetQuery
created InSetQuery, LikeQuery, RangeQuery
modified InSetQuery, LikeQuery, RangeQuery

Если поле для фильтрации имеет вид metadata.something, то фильтрация идет по содержимому соответствующего поля в metadata. Для этих фильтров поддерживаются виды AllInSetQuery (только для вложенных полей-массивов), InSetQuery, LikeQuery, RangeQuery (только для вложенных полей-чисел).

В случае если название поля не совпадает с одним из названий из таблицы выше и не имеет префикса metadata (например, поле something), будет возвращена ошибка.

В случае если запрос InSetQuery или LikeQuery производится по содержимому поля json-объекта, которое не является строкой, то объект будет приведен к строке, содержащей json, и поиск будет произведен по ней.

В случае если запрос AllInSetQuery производится по содержимому поля json-объекта, которое не является массивом, то вернется ошибка. В случае если запрос RangeQuery производится по содержимому поля json-объекта, которое не является числом, то вернется ошибка.

Доступные поля для сортировки:

Поле
code
created
modified
metadata.*

Для полей metadata.* реализована натуральная сортировка.

InternalListItemsByCatalogCode (Alexandrina)

На входе параметры для поиска элементов справочника, код которого указан

{
  "data": "cities",
  "search": {
    "query": "",
    "context": {},
    "sorting": {
      "fieldName": "title",
      "order": "asc"
    },
    "paging": {
      "page": 1,
      "count": 10
    }
  }
}

На выходе список элементов справочника

{
  "items": [
    {
      "id": "cee05b97-ca41-4355-8565-d667c6807cbd",
      "catalogId": "0effa436-06c2-42cc-befe-8ebec417fc5a",
      "code": "moscow",
      "title": "Москва",
      "archived": false,
      "metadata": {},
      "created": 1632978484446,
      "modified": 1632979205601,
      "version": 2,
      "isProtected": false
    }
  ],
  "total": 1
}

Получение списка всех элементов указанного справочника по коду справочника.

Имя вызова команды: internalListItemsByCatalogCode.
Поддерживается только синхронный вызов.
Результат выполнения команды не журналируется.

Команда только внутренняя (нельзя вызвать через Api Gateway), не требует аутентификации.

По умолчанию сортировка производится по полю title.

Запрос принимает параметры сортировки, фильтров и пейджинга в параметре search с типом Search. Применяется к полям модели CatalogItem.

Доступные поля для фильтрации и виды фильтров по ним:

Поле Виды фильтров
id InSetQuery, LikeQuery
catalogId InSetQuery, LikeQuery
code InSetQuery, LikeQuery
title InSetQuery, LikeQuery
archived InSetQuery
created InSetQuery, LikeQuery, RangeQuery
modified InSetQuery, LikeQuery, RangeQuery

Если поле для фильтрации имеет вид metadata.something, то фильтрация идет по содержимому соответствующего поля в metadata. Для этих фильтров поддерживаются виды AllInSetQuery (только для вложенных полей-массивов), InSetQuery, LikeQuery, RangeQuery (только для вложенных полей-чисел).

В случае если название поля не совпадает с одним из названий из таблицы выше и не имеет префикса metadata (например, поле something), будет возвращена ошибка.

В случае если запрос InSetQuery или LikeQuery производится по содержимому поля json-объекта, которое не является строкой, то объект будет приведен к строке, содержащей json, и поиск будет произведен по ней.

В случае если запрос AllInSetQuery производится по содержимому поля json-объекта, которое не является массивом, то вернется ошибка. В случае если запрос RangeQuery производится по содержимому поля json-объекта, которое не является числом, то вернется ошибка.

Доступные поля для сортировки:

Поле
code
created
modified
metadata.*

Для полей metadata.* реализована натуральная сортировка.

GetCatalogItem (Alexandrina)

На входе ID элемента справочника

"cee05b97-ca41-4355-8565-d667c6807cbd"

На выходе данные элемента

{
  "id": "cee05b97-ca41-4355-8565-d667c6807cbd",
  "catalogId": "0effa436-06c2-42cc-befe-8ebec417fc5a",
  "code": "moscow",
  "title": "Москва",
  "archived": false,
  "metadata": {},
  "created": 1632979205601,
  "modified": 1632979205601,
  "version": 1,
  "isProtected": false
}

Получение данных по элементу справочника.

Имя вызова команды: getCatalogItem.
Поддерживается только синхронный вызов.
Результат выполнения команды не журналируется.

InternalGetCatalogItem (Alexandrina)

На входе ID элемента справочника

"cee05b97-ca41-4355-8565-d667c6807cbd"

На выходе данные элемента

{
  "id": "cee05b97-ca41-4355-8565-d667c6807cbd",
  "catalogId": "0effa436-06c2-42cc-befe-8ebec417fc5a",
  "code": "moscow",
  "title": "Москва",
  "archived": false,
  "metadata": {},
  "created": 1632979205601,
  "modified": 1632979205601,
  "version": 1,
  "isProtected": false
}

Получение данных по элементу справочника.

Имя вызова команды: internalGetCatalogItem.
Поддерживается только синхронный вызов.
Результат выполнения команды не журналируется.

Внутренняя команда не требующая авторизацию.

GetCatalogItemByCode (Alexandrina)

На входе код справочника и элемента

{
  "catalogCode": "cities",
  "itemCode": "moscow"
}

На выходе данные элемента

{
  "id": "cee05b97-ca41-4355-8565-d667c6807cbd",
  "catalogId": "0effa436-06c2-42cc-befe-8ebec417fc5a",
  "code": "moscow",
  "title": "Москва",
  "archived": false,
  "metadata": {},
  "created": 1632979205601,
  "modified": 1632979205601,
  "version": 1,
  "isProtected": false
}

Получение элемента справочника по коду.

Имя вызова команды: getCatalogItemByCode.
Поддерживается только синхронный вызов.
Результат выполнения команды не журналируется.

InternalGetCatalogItemByCode (Alexandrina)

На входе код справочника и элемента

{
  "catalogCode": "cities",
  "itemCode": "moscow"
}

На выходе данные элемента

{
  "id": "cee05b97-ca41-4355-8565-d667c6807cbd",
  "catalogId": "0effa436-06c2-42cc-befe-8ebec417fc5a",
  "code": "moscow",
  "title": "Москва",
  "archived": false,
  "metadata": {},
  "created": 1632979205601,
  "modified": 1632979205601,
  "version": 1,
  "isProtected": false
}

Получение элемента справочника по коду.

Имя вызова команды: internalGetCatalogItemByCode.
Поддерживается только синхронный вызов.
Результат выполнения команды не журналируется.

Внутренняя команда не требующая авторизацию.

GetCatalogItemBatch (Alexandrina)

На входе список ID элементов справочников

[
  "cee05b97-ca41-4355-8565-d667c6807cbd",
  "4a2424df-acf2-410f-8ed5-65b90675d5f1"
]

На выходе список запрашиваемых элементов

[
  {
    "id": "cee05b97-ca41-4355-8565-d667c6807cbd",
    "catalogId": "0effa436-06c2-42cc-befe-8ebec417fc5a",
    "code": "moscow",
    "title": "Москва",
    "archived": false,
    "metadata": {},
    "created": 1632979205601,
    "modified": 1632979205601,
    "version": 1,
    "isProtected": false
  },
  {
    "id": "4a2424df-acf2-410f-8ed5-65b90675d5f1",
    "catalogId": "0effa436-06c2-42cc-befe-8ebec417fc5a",
    "code": "Tyumen",
    "title": "Тюмень",
    "archived": false,
    "metadata": {},
    "created": 1632979205601,
    "modified": 1632979205601,
    "version": 1,
    "isProtected": false
  }
]

Получение данных по элементам справочников по их id. Батчевая версия простого вызова данных одного элемента. При переданном пустом списке вернет все элементы всех справочников в базе.

Имя вызова команды: getCatalogItemBatch.
Поддерживается только синхронный вызов.
Результат выполнения команды не журналируется.

InternalGetCatalogItemBatch (Alexandrina)

На входе список ID элементов справочников

[
  "cee05b97-ca41-4355-8565-d667c6807cbd",
  "4a2424df-acf2-410f-8ed5-65b90675d5f1"
]

На выходе список запрашиваемых элементов

[
  {
    "id": "cee05b97-ca41-4355-8565-d667c6807cbd",
    "catalogId": "0effa436-06c2-42cc-befe-8ebec417fc5a",
    "code": "moscow",
    "title": "Москва",
    "archived": false,
    "metadata": {},
    "created": 1632979205601,
    "modified": 1632979205601,
    "version": 1
  },
  {
    "id": "4a2424df-acf2-410f-8ed5-65b90675d5f1",
    "catalogId": "0effa436-06c2-42cc-befe-8ebec417fc5a",
    "code": "Tyumen",
    "title": "Тюмень",
    "archived": false,
    "metadata": {},
    "created": 1632979205601,
    "modified": 1632979205601,
    "version": 1
  }
]

Получение данных по элементам справочников по их id. Батчевая версия простого вызова данных одного элемента. При переданном пустом списке вернет все элементы всех справочников в базе.

Имя вызова команды: internalGetCatalogItemBatch.
Поддерживается только синхронный вызов.
Результат выполнения команды не журналируется.

Внутренняя команда не требующая авторизацию.

Публикуемые события

События публикуются в ALEXANDRINA_CATALOG_EVENTS_TOPIC.

eventType payloadType payloadId Описание
catalogUpsert catalog Id каталога Каталог создан или обновлен
catalogItemUpsert catalogItem Id элемента каталога Элемент каталога создан или обновлен
catalogRemoval removeCatalog Id каталога Каталог удален
catalogItemRemoval removeCatalogItem Id элемента каталога Элемент каталога удален

Модели сервиса Alexandrina

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

CreateCatalogDTO (Alexandrina)

Создание справочника

Поле Тип Обязательное Значение по умолчанию Описание
code string да Строковый код справочника (32 символов)
title string да Человекочитаемое название справочника (200 символов)
metadata json object да Дополнительные данные справочника - объект JSON
isProtected boolean нет true Признак защиты записи от изменений

UpdateCatalogDTO (Alexandrina)

Обновление справочника

Поле Тип Обязательное Значение по умолчанию Описание
id uuid string да ID справочника
code string да Строковый код справочника (32 символов)
title string да Человекочитаемое название справочника (10000 символов)
metadata json object да Дополнительные данные справочника - объект JSON
version integer да Версия, полученная при запросе данных справочника. Нужна для оптимистичных блокировок
isProtected boolean нет true Признак защиты записи от изменений

Catalog (Alexandrina)

Справочник

Поле Тип Обязательное Значение по умолчанию Описание
id uuid string да ID справочника
code string да Строковый код справочника (32 символов)
title string да Человекочитаемое название справочника (200 символов)
metadata json object да Дополнительные данные справочника - объект JSON
modified TimeStamp нет TimeStamp.now Дата последнего изменения справочника
version integer нет 1 Версия данных. Нужна для оптимистичных блокировок
items integer нет 0 Количество элементов справочника (вычисляемое)
isProtected boolean нет false Признак защиты записи от изменений

CreateCatalogItemDTO (Alexandrina)

Создание элемента справочника

Поле Тип Обязательное Значение по умолчанию Описание
catalogId uuid string да ID справочника
code string да Строковый код элемента (32 символов)
title string да Человекочитаемое название элемента (10000 символов)
metadata json object да Дополнительные данные справочника - объект JSON
isProtected boolean нет true Признак защиты записи от изменений

UpdateCatalogItemDTO (Alexandrina)

Обновление элемента справочника

Поле Тип Обязательное Значение по умолчанию Описание
id uuid string да ID элемента справочника
code string да Строковый код элемента (32 символов)
title string да Человекочитаемое название элемента (10000 символов)
metadata json object да Дополнительные данные справочника - объект JSON
version integer да Версия данных элемента. Нужна для оптимистичных блокировок
isProtected boolean нет true Признак защиты записи от изменений

CatalogItem (Alexandrina)

Элемент справочника

Поле Тип Обязательное Значение по умолчанию Описание
id uuid string да ID элемента справочника
catalogId uuid string да ID справочника
code string да Строковый код элемента (32 символов)
title string да Человекочитаемое название элемента (10000 символов)
archived boolean да Признак архивности
metadata json object да Дополнительные данные справочника - объект JSON
created TimeStamp нет TimeStamp.now Дата создания элемента справочника
modified TimeStamp нет TimeStamp.now Дата последнего изменения элемента справочника
version integer нет 1 Версия данных элемента. Нужна для оптимистичных блокировок
isProtected boolean нет false Признак защиты записи от изменений

GetCatalogItemDTO (Alexandrina)

Получение элемента справочника по коду

Поле Тип Обязательное Значение по умолчанию Описание
catalogCode string да Код справочника
itemCode string да Код элемента справочника

ArchiveCatalogItemDTO (Alexandrina)

Данные для архивации/разархивации элемента справочника

Поле Тип Обязательное Значение по умолчанию Описание
id uuid string да ID элемента справочника
archived boolean да Признак архивности
isProtected boolean нет true Признак защиты записи от изменений

ExportParams (Alexandrina)

Данные для экспорта справочника

Поле Тип Обязательное Значение по умолчанию Описание
ids uuid array да Массив ID справочников
exclude boolean нет false Признак исключения из выгрузки (опциональный, по умолчанию - false)

CatalogExchangeDTO (Alexandrina)

Данные справочника для обмена

Поле Тип Обязательное Значение по умолчанию Описание
code string да Строковый код справочника (32 символов)
title string да Человекочитаемое название справочника (200 символов)
metadata json object да Дополнительные данные справочника - объект JSON
items CatalogItemExchangeDTO array да Массив элементов справочника
isProtected boolean нет true Признак защиты записи от изменений
ignoreProtection boolean нет false Игнорировать признак защиты записи от изменений при загрузке данных

CatalogItemExchangeDTO (Alexandrina)

Данные элемента справочника для обмена

Поле Тип Обязательное Значение по умолчанию Описание
code string да Строковый код элемента (32 символов)
title string да Человекочитаемое название элемента (10000 символов)
archived boolean да Признак архивности
metadata json object да Дополнительные данные справочника - объект JSON
isProtected boolean нет true Признак защиты записи от изменений

CatalogParseDTO (Alexandrina)

Данные парсинга справочника

Поле Тип Обязательное Значение по умолчанию Описание
code string да Строковый код справочника (32 символов)
title string да Человекочитаемое название справочника (200 символов)
metadata json object да Дополнительные данные справочника - объект JSON
items CatalogItemExchangeDTO array да Массив элементов справочника
present boolean да Признак наличия справочника
isProtected boolean нет true Признак защиты записи от изменений
ignoreProtection boolean нет false Игнорировать признак защиты записи от изменений при загрузке данных

ExchangeTemplate (Alexandrina)

Данные JSON-файла со справочниками

Поле Тип Обязательное Значение по умолчанию Описание
version string да Версия файла
dataType string да Тип данных файла (всегда catalogs)
data CatalogParseDTO array да Массив справочников

ImportResultDTO (Alexandrina)

Результат импорта данных

Поле Тип Обязательное Значение по умолчанию Описание
failedImport FailedImportResultDTO array да Список сущностей

FailedImportResultDTO (Alexandrina)

Провальный импорт каталога

Поле Тип Обязательное Значение по умолчанию Описание
code string да Строковый код справочника (32 символов)
items FailedImportItemResultDTO array да Массив элементов справочника

FailedImportItemResultDTO (Alexandrina)

Провальный импорт каталога

Поле Тип Обязательное Значение по умолчанию Описание
code string да Строковый код элемента (32 символов)

ListBy[CatalogId] (Alexandrina)

Параметры для запроса списка элементов по идентификатору каталога

Поле Тип Обязательное Значение по умолчанию Описание
data String да Идентификатор каталога
search Search да Параметры поиска для списка элементов.

ListBy[CatalogCode] (Alexandrina)

Параметры для запроса списка элементов по коду каталога

Поле Тип Обязательное Значение по умолчанию Описание
data String да Код каталога
search Search да Параметры поиска для списка элементов.

ParseCatalogsXlsDTO (Alexandrina)

Параметры для запроса информации о справочниках xls

Поле Тип Обязательное Значение по умолчанию Описание
fileUrl string да Путь до файла в s3
startRow int нет 2 Строка, с которой начинаются данные в файлах (строчки начинаются с 1)
targetFileNames string array нет Название конкретного файла из zip, данные которого хотим получить

ParseCatalogsXlsResultDTO (Alexandrina)

Ответ запроса информации о справочниках xls

Поле Тип Обязательное Значение по умолчанию Описание
importData ImportDataEntity array да Информация о файлах
rejectedFiles string array да Названия файлов, с которыми не смогли работать

ImportDataEntity (Alexandrina)

Структура для ответа в ParseCatalogsXlsResultDTO

Поле Тип Обязательное Значение по умолчанию Описание
fileName string да Название файла
extension string да Расширение файла
title string да Имя файла (без расширения)
code string да Код каталога
present boolean да Существует ли каталог с code
metadata json object да Метадата каталога
items CatalogItemExchangeDTO да Содержимое файла

Api-gateway: сервис маршрутизации

Сервис является точкой входа в систему. Все общение между front-end и back-end происходит через этот сервис. Выполняет маршрутизацию команды в нужный сервис, а также обеспечивает извлечение из запроса необходимых данных, например, для авторизации.

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

Имеет следующие URL для взаимодействия с системой и командами:

Конфигурирование Api Gateway

Требования к запуску Api Gateway

Запуск сервиса осуществляется локально через sbt, на стенде в docker на jvm.

Для корректной минимальной работы сервиса требуется обязательное подключение к Kafka и Consul. Для настройки подключения к ним нужно заполнить обязательные переменные окружения из раздела ниже.

Обеспечивает работу окружения Verdi. Требует еще CommandStatus для работы этого окружения.

Список переменных окружения Api Gateway

Переменная Тип Обязательная Значение по умолчанию Описание
APIGATEWAY_HTTP_HOST String Нет "0.0.0.0" Хост, на котором слушает HTTP-сервер
APIGATEWAY_HTTP_PORT Int Нет 8080 Порт, на котором слушает HTTP-сервер
APIGATEWAY_KAFKA_SERVERS String Да "localhost:9092" Адрес Kafka
APIGATEWAY_KAFKA_COMMANDEVENT_TOPIC String Да commandevents Название кафка-топика для отправки сообщений со статусами выполняемых команд. ОБЯЗАТЕЛЬНО должно соответствовать названию этого топика в сервисе статуса команд.
APIGATEWAY_KAFKA_AUTH_USER String Нет "" Название учетной записи Kafka. Если название не указано, то настройки авторизации не будут применены.
APIGATEWAY_KAFKA_AUTH_PASSWORD String Нет "" Пароль учетной записи Kafka.
APIGATEWAY_KAFKA_AUTH_PRINCIPAL String Нет "" Principal учетной записи Kafka в Kerberos(в случае соединения с kafka через Kerberos).
APIGATEWAY_KAFKA_AUTH_KEYTAB_PATH String Нет "" Путь до keytab-файла(в случае соединения с kafka через Kerberos).
APIGATEWAY_KAFKA_AUTH_TRUSTSTORE_LOCATION String Нет "" Путь до хранилища сертификатов (Java key store). Если путь не указан, то сертификат применяться не будет.
APIGATEWAY_KAFKA_AUTH_TRUSTSTORE_PASSWORD String Нет "" Пароль к хранилищу сертификатов.
APIGATEWAY_KAFKA_AUTH_MODE String Нет "static" Режим аутентификации: static - одна учетная запись на все запросы, mapping - учетная запись зависит от запроса
APIGATEWAY_KAFKA_AUTH_CONFIG String Нет "" Настройки для аутентификации: если AuthMode = mapping, то необходим JSON с List[KafkaAuthConfig]. Переменная соответствует полю authConfig из KafkaAuthSettings.
APIGATEWAY_KAFKA_AUTH_CACHE_SIZE Int Нет Максимальный размер кеша для Kafka producer (количество активных соединений).
APIGATEWAY_KAFKA_AUTH_CACHE_TTL Duration String Нет Время жизни Kafka producer в кеше.
APIGATEWAY_KAFKA_PRODUCER_PROPS String Нет "max.request.size=1048576" Дополнительные параметры для Kafka producer. Заполняются по шаблону "key1=value1;key2=value2".
APIGATEWAY_CONSUL_ADDR URL Нет "http://localhost:8500" Адрес Consul
APIGATEWAY_CONSUL_AUTH_USER String Нет "" Название учетной записи Сonsul. Если название не указано, то настройки авторизации не будут применены.
APIGATEWAY_CONSUL_AUTH_PASSWORD String Нет "" Пароль учетной записи Сonsul.
APIGATEWAY_CONSUL_RETRY_MAX Int Нет 20 Количество попыток переподключения к Consul
APIGATEWAY_CONSUL_RETRY_DELAY Duration String Нет 3 second Задержка при попытках переподключения к Consul
APIGATEWAY_ANONYMOUS_ACCESS_MODE String Нет any Режим доступа к командам для анонимных пользователей: any - все команды доступны; some - доступны команды из списка команд; none - ни одна команда не доступна
APIGATEWAY_ANONYMOUS_ACCESS_COMMANDS String Нет "" Строка названиями команд, перечисленных через запятую ","
APIGATEWAY_TOKEN_HANDLING String Нет "Authorization=mon_http_UserCommandContextData_OauthAccessToken" Настройки получения информации о пользователе НЕ с помощью JWT. Содержит строку с парами (хедер из запроса, который нужно передать команде; команда, которую нужно вызвать с пустым телом и данным хедером, чтобы получить данные о пользователе). Формат строки: "headerName1=commandName1;headerName2=commandName2;" headerName и commandName при этом не должны содержать = и ;.
Хедеры обрабатываются по очереди в алфавитном порядке. Если в конфиге хедеру соответствует несколько команд, то команды с одним и тем же хедером вызываются в порядке возникновения пары с этой командой в строке с настройками.

Для указания cookie можно использовать формат "Cookie:target_name1=commandName1;Cookie:target_name2=commandName2". В значении cookie ожидается формат "TOKEN_TYPE%20TOKEN" (пробел запрещен в cookie и заменен на %20) или просто "TOKEN". Поддерживаемые типы токенов: "Basic", "Bearer", "DPoP", "mac", "unknown", "N_A".

Значение cookie будет отправлено как значение HTTP заголовка "Authorization": "TOKEN_TYPE%20TOKEN" преобразуется в "TOKEN_TYPE TOKEN", "TOKEN" будет передан как есть ("TOKEN").

В качестве информации о пользователе используется первый успешный вызов команды.
APIGATEWAY_TRACE_DURATION Boolean Нет false Проводить ли трассировку вызова команд (логировать временные метки)
APIGATEWAY_STACKTRACE_SHOW Boolean Нет false Выводить ли stack trace в ошибках
APIGATEWAY_POLL_STATUS_TIMEOUT Duration String Нет 3 seconds Максимальное время ожидания для команды PollStatus. Ограничивает минимально возможное значение для параметра строки запроса "timeout".
APIGATEWAY_POLL_STATUS_TIMEOUT_MAX Duration String Нет 3 minutes Ограничивает максимально возможное значение для параметра строки запроса "timeout" для ожидания статуса команды PollStatus. Самая верхняя граница для значений: 65535 секунд.
APIGATEWAY_OPENAPI_TITLE String Нет API Gateway Заголовок генерируемого OpenAPI
APIGATEWAY_OPENAPI_VERSION String Нет 0.5 Версия, отображаемая в генерируемом OpenAPI
APIGATEWAY_OPENAPI_URLPREFIX String Нет Префикс для всех url, публикуемых в генерируемом OpenAPI
APIGATEWAY_FS_REQUIRE Boolean Нет false Требуется ли использовать файловое хранилище. Если false, тогда не будут создаваться http-routes для работы с файлами
APIGATEWAY_JWT_SIGNATURE String Нет "my very secret string for signature" Сигнатура для подписи и расшифровки jwt-токенов, используемых для аутентификации
APIGATEWAY_AKKA_HTTP_PARSING_MAX_BYTES Size String Нет 50m Максимальный размер данных из http-запроса, который может быть принят и распаршен
APIGATEWAY_AKKA_HTTP_PARSING_MAX_CHUNK_SIZE Size String Нет 10m Максимальный размер одной части http-запроса, который может быть принят и распаршен
APIGATEWAY_AKKA_HTTP_PARSING_MAX_HEADER_COUNT Int Нет 64 Максимальное количество заголовков http-запроса, который может быть принят и распаршен
APIGATEWAY_AKKA_HTTP_PARSING_MAX_HEADER_NAME_SIZE Int Нет 64 Максимальный размер названия заголовка из http-запроса, который может быть принят и распаршен
APIGATEWAY_AKKA_HTTP_PARSING_MAX_HEADER_VALUE_SIZE Size String Нет 8k Максимальный размер значения заголовка из http-запроса, который может быть принят и распаршен
APIGATEWAY_AKKA_HTTP_CLIENT_MAXCON Int Нет 512 Максимальное количество входящих http-соединений
APIGATEWAY_AKKA_HTTP_CLIENT_MAXREQ Int Нет 1024 Максимальное количество одновременно обслуживаемых запросов
APIGATEWAY_AKKA_HTTP_CLIENT_RESP_SUBSCR_TIMEOUT Duration String Нет 1 second Таймаут, за который нужно подписаться на обработку тела http-запроса после обработки заголовков запроса
APIGATEWAY_AKKA_HTTP_CLIENT_IDLE_TIMEOUT Duration String Нет 1 minute Максимальное время на исходящий http-запрос (в какой-либо сервис)
APIGATEWAY_AKKA_HTTP_HOST_CONN_POOL_CLIENT_IDLE_TIMEOUT Duration String Нет равно APIGATEWAY_AKKA_HTTP_CLIENT_IDLE_TIMEOUT Позволяет отдельно настроить максимальное время на исходящий http-запрос, использующий пул соединений (т.е. для синхронной отправки синхронной команды)
APIGATEWAY_AKKA_HTTP_HOST_CONN_POOL_IDLE_TIMEOUT Duration String Нет 30 second Максимальное время жизни пула соединений (с каким-либо сервисом) при отсутствии исходящих соединений
APIGATEWAY_AKKA_HTTP_SERVER_MAXCON Int Нет 1024 Максимальное количество входящих http-соединений
APIGATEWAY_AKKA_HTTP_SERVER_IDLE_TIMEOUT Duration String Нет 5 minutes Максимальное время жизни входящего http-соединения
APIGATEWAY_AKKA_HTTP_SERVER_REQUEST_TIMEOUT Duration String Нет 5 minutes Максимальное время обработки входящего http-запроса. Должно быть не больше предыдущего значения, иначе входящее соединение оборвется по таймауту времени жизни запроса
APIGATEWAY_INTERNALCMD_ALLOW Boolean Нет false Позволять ли выполнять внутренние команды, не предназначенные для вызова с UI
APIGATEWAY_SENDERLIB_COMMANDS_CACHE_UPDATEPERIOD Duration String Нет 10 minutes Время жизни кэша команд, получаемых из Consul
APIGATEWAY_SENDERLIB_SERVICES_CACHE_UPDATEPERIOD Duration String Нет 30 seconds Время жизни кэша service discovery для данных адресов сервисов, получаемых из Consul
APIGATEWAY_SENDERLIB_KAFKA_POLLING_PERIOD Duration String Нет 1 second Период опроса статуса kafka-команды. Нужно для синхронного выполнения асинхронных команд
APIGATEWAY_SENDERLIB_KAFKA_POLLING_TIMEOUT Duration String Нет 10 seconds Таймаут для синхронного выполнения асинхронной kafka-команды
APIGATEWAY_FS_URI URL Нет "http://localhost:9000" Адрес для подключения к хранилищу файлов по S3-API
APIGATEWAY_FS_ACCESS_KEY_ID String Нет minioadmin Ключ доступа для хранилища файлов (aka логин)
APIGATEWAY_FS_SECRET_ACCESS_KEY String Нет minioadmin Секретный ключ для хранилища файлов (aka пароль)
APIGATEWAY_FS_UPLOAD_PARALLELISM Int Нет 4 Параллелизм для загрузки файлов
APIGATEWAY_FS_AUTH_MODE String Нет static Режим аутентификации: static - одна учетная запись на все запросы, mapping - учетная запись зависит от запроса
APIGATEWAY_FS_AUTH_CONFIG String Нет "" Настройки для аутентификации: если AuthMode = mapping, то необходим JSON с маппингом учетных записей
APIGATEWAY_FS_CACHE_SIZE Int Нет 1 Максимальный размер кеша клиентов для хранилища файлов (количество активных соединений).
APIGATEWAY_FS_CACHE_TTL Duration String Нет Время жизни клиента в кеше
APIGATEWAY_FS_RETRY_ATTEMPTS Int Нет 5 Количество ретраев, которое будет произведено в случае Exception-а в операции FSClient-а и при вычитывании стрима в get операциях FSClient-а.
APIGATEWAY_FS_RETRY_DELAY Duration String Нет 10 millis Задержка между ретраями операций FSClient-а.
APIGATEWAY_FS_ZIO_SHORT_MESSAGE_MODE Boolean Нет false Флаг включения режима сохранения ошибок работы с файловым хранилищем в сервисе журналирования nestor. При включении режима ошибки в логах будут отображаться в сокращенном формате: Short zio message mode. ExceptionType: ТИП ОШИБКИ, Exception id: 'СГЕНЕРИРОВАННЫЙ UUID' added to journal. Указанный id будет фиксироваться в event записи nestor'а в поле data.id
APIGATEWAY_TEMP_BUCKET String Нет temp Бакет в файловом хранилище для временных файлов, загружаемых на gateway
APIGATEWAY_TEMP_USERCACHE_INIT_SIZE Int Нет 16 Изначальный размер кэша, хранящего сведения о том, какой пользователь загрузил какой временный файл (далее TEMP_USERCACHE).
APIGATEWAY_TEMP_USERCACHE_MAX_SIZE Int Нет 1000 Максимально допустимый размер кэша TEMP_USERCACHE
APIGATEWAY_TEMP_USERCACHE_DURATION Duration String Нет 60 seconds Время жизни записи с данными пользователя в кэше TEMP_USERCACHE
APIGATEWAY_CACHE_USERINFO_MAX_SIZE Int Нет 1000 Максимально допустимый размер кэша CACHE_USERINFO
APIGATEWAY_CACHE_USERINFO_DURATION Duration String Нет 60 seconds Время жизни записи с данными пользователя в кэше CACHE_USERINFO
APIGATEWAY_KAFKA_CONSUMER_GROUP String Нет api-gateway Имя consumer-группы для чтения из кафка-топиков.
APIGATEWAY_KAFKA_USEREVENT_TOPIC String Нет userEvents Название кафка-топика для получения событий пользователей
APIGATEWAY_KAFKA_USEREVENT_PARTITIONS Int Нет 1 Число читаемых партиций из кафка-топика событий пользователей.
APIGATEWAY_KAFKA_CONSUMER_RESTART_MIN_BACKOFF Duration String Нет 1 second Изначальная задержка до рестарта консьюмера после падения (увеличивается в 2 раза после каждого рестарта)
APIGATEWAY_KAFKA_CONSUMER_RESTART_MAX_BACKOFF Duration String Нет 30 seconds Максимальное задержка до рестарта консьюмера после падения
APIGATEWAY_KAFKA_CONSUMER_RESTART_RANDOM_FACTOR Double Нет 0.2 Коэффициент величины дополнительной случайной задержки(jitter) относительно основной задержки (При значении 0.2 задержка может быть до 20% больше, чем при 0). Если после умножения задержки на APIGATEWAY_KAFKA_CONSUMER_RESTART_RANDOM_FACTOR получится меньше 1 миллисекунды, то jitter будет приравнен к нулю.
APIGATEWAY_KAFKA_CONSUMER_RESTART_MAX_RESTARTS Int Нет 5 Максимальное число рестартов консьюмера после падения (в пределах APIGATEWAY_KAFKA_CONSUMER_RESTART_MAX_RESTARTS_WITHIN) .После превышения этого числа сервис будет объявлен больным. Все рестарты для каждого отдельного сообщения увеличивают и общий счетчик рестартов консьюмера, поэтому при использовании APIGATEWAY_KAFKA_CONSUMER_PER_MESSAGE_RESTART_MAX_RESTARTS нужно указывать APIGATEWAY_KAFKA_CONSUMER_RESTART_MAX_RESTARTS > APIGATEWAY_KAFKA_CONSUMER_PER_MESSAGE_RESTART_MAX_RESTARTS или не указывать APIGATEWAY_KAFKA_CONSUMER_PER_MESSAGE_RESTART_MAX_RESTARTS совсем
APIGATEWAY_KAFKA_CONSUMER_RESTART_MAX_RESTARTS_WITHIN Duration String Нет 5 minutes Временной отрезок, в который APIGATEWAY_KAFKA_CONSUMER_RESTART_MAX_RESTARTS ограничивает число рестартов
APIGATEWAY_KAFKA_CONSUMER_PER_MESSAGE_RESTART_MAX_RESTARTS Int Нет 2 Максимальное количество раз, которое консьюмер перезапустится с неизменной очередью сообщений(в пределах DATA_MODEL_KAFKA_CONSUMER_RESTART_MAX_RESTARTS_WITHIN), прежде чем проигнорировать сообщение, на котором происходит ошибка (Указано количество рестартов, а не прочтений. Если APIGATEWAY_KAFKA_CONSUMER_RESTART_MAX_RESTARTS = 2, то ошибочное сообщение будет обработано 3 раза, после чего произойдет 3ий рестарт и оно будет проигнорировано). Если указать 0, то перезапуск произойдет, но сообщение будет обработано только в первый раз, когда произошла ошибка. Если указать значение меньше 0, то перезапуски все равно будут происходить, но игнорирование сообщений, вызывающих ошибку, будет отключено.
APIGATEWAY_KAFKA_CONSUMER_PER_MESSAGE_RESTART_CACHE_SIZE Int Нет 100 Для каждого сообщения счетчик перепрочтений хранится в кэше. Максимальное количество значений в этом кэше.
APIGATEWAY_KAFKA_CONSUMER_PER_MESSAGE_RESTART_CACHE_TTL Duration String Нет 5 minutes Для каждого сообщения счетчик перепрочтений хранится в кэше.Максимальное время жизни элемента в этом кэше. В случае отсутствия значения время жизни элемента не будет ограничено.
APIGATEWAY_KAFKA_CONSUMER_POLL_TIMEOUT Duration String Нет 10 milliseconds timeout запроса poll для kafka consumer
APIGATEWAY_KAFKA_CONSUMER_POLL_INTERVAL Duration String Нет 100 milliseconds интервал между запросами poll для kafka consumer
APIGATEWAY_KAFKA_CONSUMER_PROPS String Нет "max.poll.records=500;max.partition.fetch.bytes=524288" дополнительные параметры для kafka consumer в формате "key1=value1;key2=value2"
APIGATEWAY_KAFKA_PRODUCER_PROPS String Нет "batch.size=524288;linger.ms=10;max.request.size=1048576" дополнительные параметры для kafka producer в формате "key1=value1;key2=value2"
APIGATEWAY_SENDERLIB_COMMANDS_HTTP_RETRY_ATTEMPTS Int Нет 5 Поле attempts из RetrySettings
APIGATEWAY_SENDERLIB_COMMANDS_HTTP_RETRY_DELAY Duration String Нет "5 seconds" Поле delay из RetrySettings
APIGATEWAY_SENDERLIB_COMMANDS_HTTP_RETRY_KIND String Нет "OnSomeExceptions(ConnectException)" CommandResultRetryConditionKind
APIGATEWAY_LICENSE_PATH String Да "" Путь до файла с лицензией (только binary format). Можно указать несколько лицензий, перечислив пути через запятую. Количество и порядок лицензий должны совпадать с количеством и порядком ключей для лицензий (APIGATEWAY_LICENSE_KEY).
APIGATEWAY_LICENSE_KEY String Да "" Путь до файла с публичным ключом лицензии. Можно указать несколько ключей, перечислив пути через запятую. Количество и порядок ключей должны совпадать с количеством и порядком лицензий (APIGATEWAY_LICENSE_PATH).
APIGATEWAY_LICENSE_PATH_PRIORITY String Нет "" Порядок использования лицензий. При пустом значении - порядок будет соответствовать порядку путей до файлов лицензий (APIGATEWAY_LICENSE_PATH). Строка должна содержать приоритет для каждой лицензии, приоритеты разделяются запятой (например, 1,5,2) - лицензии будут обрабатываться в порядке возрастания приоритета.
LOG_LEVEL_JWT String Нет "WARN" Уровень логирования операций во время валидации jwt
LOG_LEVEL_LICENSE String Нет "INFO" Уровень логирования операций с лицензиями

Контроль доступа к командам

Анонимный доступ

Отправка запросов для анонимных пользователей контролируется переменными окружения: APIGATEWAY_ANONYMOUS_ACCESS_MODE и APIGATEWAY_ANONYMOUS_ACCESS_COMMANDS.
Проверка доступа к командам осуществляется при каждой обработке запроса (sync/async отправка, проверка статуса, загрузка и скачивание файлов).

На уровне ApiGateway только пользователь изначально без JWT будет считаться анонимным.

На уровне системы, анонимами также могут считаться пользователи, которые состоят в группе "Anonymous", даже если у них и есть валидный JWT. Это влияет только на проверку прав.

HTTP status 403
{ "message": "Anonymous access is not allowed", "businessError": null, "data": null, "stackTrace": null }

HTTP status 401
{ "message": null, "businessError": "SES001", "data": null, "stackTrace": null }

JWT не является валидным, если:

  1. нарушен его формат
  2. не совпадает подпись
  3. его срок действия истек
  4. он был инвалидирован apigateway в соответствии с правилами инвалидации и состоянием пользователя

Инвалидация JWT производится apigateway, если:

  1. Истек срок действия пароля пользователя и вызываемая команда не mon_http_ChangeUserPassword (этот тип инвалидации JWT возвращает другую ошибку, описанную в секции Время действия пароля).
  2. Статус пользователя = Deactivated
  3. Сервис mon вернул для пользователя контекст, содержащий дату деактивации deactivateAt и она прошла
  4. Сервис mon вернул для пользователя контекст, содержащий правило инвалидации, условие в которым выполнилось для текущего пользователя.
    На данный момент работа с правилами инвалидации производится с помощью команд сервиса mon mon_http_CloseAllUserSessions и mon_http_DeleteJwtInvalidation

Время действия пароля

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

HTTP status 401
{ "message": "Password lifespan has been exceeded", "businessError": "PWD001", "data": null, "stackTrace": null }

Синхронный запрос

Отправляем команду на выполнение

import com.embedika.verdi.senderlib.Dispatcher
import com.embedika.verdi.models.command.CommandName
import com.embedika.verdi.models.RequestContext
import io.circe.Json

implicit val rc: RequestContext = RequestContext.builder().build()

val dispatcher: Dispatcher = VerdiFactory.dispatcher
dispatcher.sendCommandSync(CommandName("pingpong_ping_post"), Some(Json.obj("value" -> Json.fromString("ping"))))
POST /send/sync/pingpong_ping_post
{
  "value": "ping"
}

Синхронно получаем результат выполнения команды

import com.embedika.verdi.models.command.{CommandAggregatedStatus, CommandName}
import com.embedika.verdi.models.error.ErrorResponse
import com.embedika.verdi.models.RequestContext
import io.circe.Json
import scala.concurrent.Future
import io.circe.syntax._

implicit val rc: RequestContext = RequestContext.builder().build()

val commandResponse: Future[Either[ErrorResponse, CommandAggregatedStatus]] =
  dispatcher.sendCommandSync(CommandName("pingpong_ping_post"), Some(Json.obj("value" -> Json.fromString("ping"))))
val result = commandResponse.map { r => // Future response
  r.map { cs => // Either command status
    cs.value.as[PingResponse] // Option Json
  }
}
{
  "bodyLength": 172,
  "value": "pong"
}

Отправляет команду на синхронное исполнение. Результат такого запроса возвращается сразу в ответе от Api Gateway. Запрос висит открытым все время обработки команды, пока не сформируется ответ. Применяется для простых команд, не требующих долгого выполнения. Например, запросы на чтение данных удобнее делать с помощью синхронных запросов.

Отправка команды

Чтобы синхронно выполнить команду необходимо знать ее название и формат данных, которые она принимает. Для этого нужно отправить POST-запрос, где в URL передать название команды в {command_name}:

POST /send/sync/{command_name}

Формат тела запроса зависит от формата данных, которые принимает команда. Подразумевается, что при вызове команды мы знаем, какой формат данных принимает команда.

Результат

Результат выполнения команды будет доступен сразу в ответе. Тип ответа - JSON или файл, зависит от типа команды. Формат JSON зависит от конкретной выполняемой команды. Подразумевается, что при вызове команды мы знаем, какой формат данных возвращает команда.

Синхронный запрос через GET

GET /get/CommandName?data=%7B%22foo%22%3A123%2C%22bar%22%3A%22parameter%22%7D

Отправка команды

Тело запроса принимается в query параметре data как закодированный в urlencode json.

Например, при таком json

{
  "foo": 123,
  "bar": "parameter"
}

Запрос будет выглядеть так

GET /get/CommandName?data=%7B%22foo%22%3A123%2C%22bar%22%3A%22parameter%22%7D

Результат

Аналогичен результату синхронного запроса

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

Асинхронный запрос

Отправляем команду на выполнение

import com.embedika.verdi.senderlib.Dispatcher
import com.embedika.verdi.models.error.ErrorResponse
import com.embedika.verdi.models.command.{CommandAggregatedStatus, CommandId, CommandName, CommandStatus}
import com.embedika.verdi.models.RequestContext
import scala.concurrent.Future
import io.circe.Json

implicit val rc: RequestContext = RequestContext.builder().build()

val dispatcher: Dispatcher = VerdiFactory.dispatcher
val commandIdF: Future[Either[ErrorResponse, CommandId]] =
  dispatcher.sendCommandAsync(CommandName("pingpong_ping_kafka"), Some(Json.obj("value" -> Json.fromString("ping"))))
POST /send/async/pingpong_ping_kafka
{
  "value": "ping"
}

Получаем в ответе id созданной команды

import com.embedika.verdi.senderlib.Dispatcher
import com.embedika.verdi.models.error.ErrorResponse
import com.embedika.verdi.models.command.{CommandAggregatedStatus, CommandId, CommandName, CommandStatus}
import com.embedika.verdi.models.RequestContext
import scala.concurrent.Future
import io.circe.Json

implicit val rc: RequestContext = RequestContext.builder().build()

val dispatcher: Dispatcher = VerdiFactory.dispatcher
val commandIdF: Future[Either[ErrorResponse, CommandId]] =
  dispatcher.sendCommandAsync(CommandName("pingpong_ping_kafka"), Some(Json.obj("value" -> Json.fromString("ping"))))
"cd6fe966-9296-43bb-828d-7662cffb0c09"

Отправляет команду на асинхронное исполнение. Результат такого выполнения команды возвращается не сразу, а запрашивается дополнительно через некоторое время с помощью метода получения статуса. Запрос сразу возвращает id созданной команды и не висит открытым на протяжении всего выполнения команды. Применяется для сложных команд, выполнение которых может занять некоторое ощутимое время. Например, запросы на модификацию данных со сложными проверками, импорты, формирование документов, и т.п.

Отправка команды

Чтобы асинхронно выполнить команду необходимо знать ее название и формат данных, которые она принимает. Для этого нужно отправить POST-запрос, где в URL передать название команды в {command_name}:

POST /send/async/{command_name}

Формат тела запроса зависит от формата данных, которые принимает команда. Подразумевается, что при вызове команды мы знаем, какой формат данных принимает команда.

Результат

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

Получение статуса

Запрашиваем статус GET-запросом, указывая id в URL

import com.embedika.verdi.senderlib.Dispatcher
import com.embedika.verdi.models.error.ErrorResponse
import com.embedika.verdi.models.command.{CommandAggregatedStatus, CommandId, CommandName, CommandStatus}
import com.embedika.verdi.models.RequestContext
import scala.concurrent.Future
import io.circe.Json

implicit val rc: RequestContext = RequestContext.builder().build()

val commandId: CommandId = ???
val dispatcher: Dispatcher = VerdiFactory.dispatcher

dispatcher.status(commandId)
}
GET /status/eee8f8d3-6e28-462a-be42-7e3d13b3bec3

Получаем описание текущего состояния команды

import com.embedika.verdi.senderlib.Dispatcher
import com.embedika.verdi.models.error.ErrorResponse
import com.embedika.verdi.models.command.{CommandAggregatedStatus, CommandId, CommandName, CommandStatus}
import com.embedika.verdi.models.RequestContext
import scala.concurrent.Future
import io.circe.Json

implicit val rc: RequestContext = RequestContext.builder().build()

val commandId: CommandId = ???
val dispatcher: Dispatcher = VerdiFactory.dispatcher

val status: Future[Either[ErrorResponse, Option[CommandAggregatedStatus]]] = dispatcher.status(commandId)

status.flatMap {
  case Right(Some(CommandAggregatedStatus(CommandStatus.Completed, _, jsonValue, _))) =>
    // команда выполнилась
    doSomeUsefulAction()
  case Right(Some(CommandAggregatedStatus(CommandStatus.InProcess, _, jsonValue, _))) =>
    // команда еще выполнеяется
    Future.successful(true)
  case _ =>
    Future.successful(false)
}
// команда еще выполняется
{
  "status": "InProcess",
  "timestamp": "2021-03-23T09:00:15.674384Z"
}
// команда выполнилась
{
  "status": "Completed",
  "timestamp": "2021-03-23T09:01:20.190815Z",
  "value": {
    "value": "pong"
  }
}

Для запущенной команды получает ее текущий статус выполнения. Применяется для асинхронных запросов. Клиент, вызвавший команду асинхронно, должен на своей стороне организовать пуллинг состояний с помощью этого вызова. Пуллинг должен продолжаться до тех пор, пока не вернется состояние команды Completed. В этом случае в поле value будут данные с ответом по команде.

Также нужно иметь в виду, что если вызвать status сразу же после ответа async-запроса, то status может вернуть ошибку 404. Это вызвано тем, что статус команды не успевает дойти до сервиса CommandStatus через kafka. Механизм пуллинга должен это учитывать.

Получение статуса с задержкой

GET /pollStatus/eee8f8d3-6e28-462a-be42-7e3d13b3bec3?timeout=30

Работа с данной командой аналогична работе с командой status

Для запущенной команды получает ее текущий статус выполнения. Если результат выполнения еще не доступен, то команда ждет некоторое время (это время можно настроить с помощью переменной окружения). Если по прошествию этого времени результат все еще не доступен, то вместо него возвращается последний статус команды. Если нет никакого статуса (например, указан несуществующий ID команды), то команда точно так же ждет некоторое время, а потом выдает либо появившийся статус, либо ошибку 404. Таким образом, эта команда может быть использована как альтернатива "пуллингу" для быстрых команд.

Формат запроса статуса команды

command_id: обязательный параметр

Для получения статуса запущенной команды нужно вызвать GET-запрос, в котором в URL передать id запущенной команды в {command_id}:

GET /status/{command_id}

GET /pollStatus/{command_id}

timeout: необязательный параметр

Дополнительно можно передать в параметрах строки запроса таймаут в секундах для пулинга timeout:

GET /pollStatus/{command_id}?timeout=30

Ограничение для значений параметра timeout:

Формат ответа со статусом команды

В ответе будет JSON с состоянием команды, временем последнего изменения этого состояния и значение, которое вернула команда. Это значение будет отсутствовать, если состояние команды отлично от Created.

Поля в JSON ответа:

Поле Тип Описание
status Строка Код текущего состояния команды. Список кодов смотри ниже
timestamp Instant Строковое представление даты последнего изменения состояния команды в UTC, соответствующее java-типу java.time.Instant
value Json Опциональное значение произвольного формата. Обычно некоторый JSON-объект. Зависит от вызываемой команды

Статусы команды

Код статуса Описание
Created Команда только что создана и не начата исполняться
InProcess Сервис принял команду и начал ее выполнять
Completed Команда успешно выполнена
Failed Команда выполнена с ошибкой
TimedOut Команда не успела выполниться за отведенное ей время

Выполнение команд с OpenId connect Access token вместо JWT

При каждом выполнении команд пользователь предоставляет опциональный JWT, который он получает от сервиса Mon после прохождения операции "Login". Когда стороннему сервису требуется работать с системой, не всегда есть возможность проходить через "Login" для получения JWT. Чаще удобнее использовать общеизвестные протоколы (например, OpenId connect) и передавать токены.

Процесс выполнения команд в системе и для стороннего сервиса, и для пользователя почти не будет отличаться. Разница лишь в том, как клиент получает токен: пользователь в сервисе Mon, а сторонний сервис в общеизвестном авторизационном сервисе.

При выполнении команд аутентификация с Access token также проходит через сервис Mon, который валидирует токен во внешнем авторизационном сервисе.

Для простоты далее будут использоваться следующие сокращения:

Общий алгоритм выглядит следующим образом:

  1. AuxService авторизуется в IdentityProvider и получает Access token (возможны и другие варианты реализации данного пункта (через grant_type = authorization_code), но главное получить Access token).
    1. Отправка POST запроса на "/protocol/openid-connect/token" с необходимыми данными (login, password, grant_type = password, client_id, client_secret и т.п.)
    2. Передаются "login" и "password" для пользователя, под которым впоследствии будут выполняться команды. Для него выдается Access token.
    3. Передаются "client_id" и "client_secret" для AuxService, который выполняет действия от имени пользователя.
  2. AuxService отправляет запрос на "какое-то действие" в сервис интеграции (внешнее API для AuxService). Access token должен передаваться в "Authorization" заголовке HTTP запроса с типом токена "Bearer".
  3. Сервис интеграции формирует CommandRequest из запроса от AuxService и отправляет его в ApiGateway.
  4. ApiGateway не находит JWT, но находит Access token. Отправляет запрос данных о пользователе с Access token в сервис Mon.
  5. Сервис Mon запрашивает от IdentityProvider профиль пользователя по Access token, тем самым валидируя токен. По полученному профилю в БД сервиса Mon ищется пользователь. Если пользователя нет (первое обращение к системе), то пользователь будет автоматически создан в системе.
  6. Сервис Mon отправляет найденные данные пользователя обратно в ApiGateway.
  7. ApiGateway обогащает CommandRequest данными пользователя и отправляет его в целевой сервис. Если данные пользователя не были получены (вернулась ошибка), то будет использованы данные для анонимного пользователя.
  8. ApiGateway получает ответ от целевого сервиса, куда отправлялась команда, и отвечает в сервис интеграции либо с ErrorResponse, либо со структурой ответа команды.

OpenAPI

{
  "openapi": "3.0.3",
  "info": {
    "title": "API Gateway",
    "version": "0.4"
  },
  "paths": {
    "/sync/UpdateObjectByCode/accessMatrixRoleRBAM/{entityId}": {
      "post": {
        "description": "Обновляет объект по его Code",
        "operationId": "postSyncUpdateobjectbycodeAccessmatrixrolerbamEntityid",
        "parameters": [
          {
            "name": "entityId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "description": "Command arguments as JSON object",
          "content": {
            "text/plain": {
              "schema": {
                "type": "string"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Command execution result as JSON object",
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                }
              }
            }
          }
        }
      }
    }
  }
}
// не применимо

По url /openapi.json доступна спецификация OpenAPI описывающая все доступные команды в виде разных URL. Применяется для интеграции Api Gateway с различными системами. Кроме того, полезно при разработке фронта.

Upload

Загрузка файла

POST /upload
// не применимо

Результат вызова

{
  "fileId": "1c689788-9617-4c93-bcee-6eae8909a0ba",
  "url": "temp/1c689788-9617-4c93-bcee-6eae8909a0ba"
}
// не применимо

Загрузить файл в систему. Загруженный файл помещается во временный бакет APIGATEWAY_TEMP_BUCKET. Файл передается в multipart-formdata в поле file. Принимается запрос POST на url /upload. На выходе возвращается объект, содержащий id загруженного файла и относительный URL, по которому доступен этот файл. Далее можно использовать этот id для передачи в сервисы.

При каждой загрузке, файл "привязывается" к текущему пользователю на уровне данных FileMeta (ожидается, что в заголовках запроса будет Cookie с JWT или access token в header/cookie). В дальнейшем информация об этой привязке будет использоваться для определения начилия доступа к получению данных как самого файла, так и его метаданных. Если файл был загружен до появления функционала "привязки", то он считается доступным всем.


Анонимные пользователи воспринимаются как один и тот же пользователь, т.е. любой анонимный пользователь имеет доступ ко всем файлам, что были загружены другими анонимными пользователями.
В текущей реализации, анонимный пользователь отличается от "залогиненого", т.е. "залогиненый" пользователь не имеет доступа к файлам от "анонимов". Чтобы получить такой доступ, нужно выйти из системы и обратиться к файлу в качестве "анонима". Чтобы разрешить анонимный доступ, при APIGATEWAY_ANONYMOUS_ACCESS_MODE не равном any, нужно добавить в * APIGATEWAY_ANONYMOUS_ACCESS_COMMANDS* значение apigw_uploadFile.

Download

При скачивании через этот метод не происходит проверки прав. Поэтому лучше использовать команду getFile синхронно.

Скачивание файла

GET /download/temp/1c689788-9617-4c93-bcee-6eae8909a0ba
// не применимо

Скачивание файла из системы. Для скачивания передается GET-запрос. В url после /download/ передать url файла. В этот url входит бакет, путь внутри бакета и id файла. HTTP-ответ формируется как файл.

При попытке обращения к файлу, происходит проверка наличия доступа у пользователя к файлу (ожидается, что в заголовках запроса будет Cookie с JWT или access token в header/cookie). Если доступа нет - возвращается статус 404 Not Found.
Детали предоставления и проверки доступа описаны в Загрузке файла в систему. Чтобы разрешить анонимный доступ, при APIGATEWAY_ANONYMOUS_ACCESS_MODE не равном any, нужно добавить в * APIGATEWAY_ANONYMOUS_ACCESS_COMMANDS* значение apigw_downloadFile.

После выполнения данного запроса http-клиент получит в ответе файл и хедер Content-Disposition, с помощью которого http-клиент сможет понять, какое имя файла предложить пользователю при сохранении.

Если имя файла содержит только ASCII-символы, то хедер будет иметь вид Content-Disposition: attachment; filename="MyFileName.pdf" и с большой вероятностью будет успешно распознан любым http-клиентом.

В случае если возвращаемый файл имеет в имени символы, не входящие в ASCII, то для корректной передачи имени будет использоваться дополнительное поле filename* и например для имени файла "файл.pdf" хедер будет иметь вид Content-Disposition: attachment; filename="????.pdf"; filename*=utf-8''%D1%84%D0%B0%D0%B9%D0%BB.pdf. Использование этого поля в хедере описано в RFC 6266, но не все http-клиенты и браузеры поддерживают filename*. Если http-клиент поддерживает filename*, то он предложит сохранить скачиваемый файл с именем, в котором будут отображены все содержащиеся в нем символы, но если http-клиент не поддерживает filename*(например Safari, Internet Explorer версии 8 и раньше), то скорее всего будет использовано имя из filename, где все не-ASCII символы будут заменены на ?.

Metadata

Получение метаданных файла

GET /metadata/temp/1c689788-9617-4c93-bcee-6eae8909a0ba
// не применимо

Результат с метаданными

{
  "fileId": "1c689788-9617-4c93-bcee-6eae8909a0ba",
  "name": "Текстовый документ.pdf",
  "size": 301,
  "url": "temp/1c689788-9617-4c93-bcee-6eae8909a0ba",
  "md5": "953c3ff8a7afa87d759fb606eabc8438",
  "contentType": "application/pdf"
}
// не применимо

Получение метаданных файла в системе. Передается GET-запрос. В url после /metadata/ передать url файла. В этот url входит бакет, путь внутри бакета и id файла. Возвращается json с метаданными файла.

При попытке обращения к метаданным файла, происходит проверка наличия доступа у пользователя к файлу (ожидается, что в заголовках запроса будет Cookie с JWT или access token в header/cookie). Если доступа нет - возвращается статус 404 Not Found.
Детали предоставления и проверки доступа описаны в Загрузке файла в систему. Чтобы разрешить анонимный доступ, при APIGATEWAY_ANONYMOUS_ACCESS_MODE не равном any, нужно добавить в APIGATEWAY_ANONYMOUS_ACCESS_COMMANDS значение apigw_getFileMeta.

Archiver: сервис архивации файлов

Сервис архивации файлов из S3 в zip архив, который сохраняется в собственном топике S3. Хранит информацию о сохраненных файлах, для быстрой выдачи уже созданных архивов.

Состояние хранится в PostgreSQL. Команды могут приходить как по HTTP, так и через Kafka в топик archiver_commands.

Сервис разбит на несколько модулей, в виде sbt проектов:

Локальный запуск

При запуске сервиса ожидается, что уже развернута необходимая инфраструктура:

Запуск из консоли с помощью SBT

ARCHIVER_DB_HOST=localhost ARCHIVER_DB_PORT=5432 ARCHIVER_DB_NAME=archiver_db ARCHIVER_DB_USER=postgres ARCHIVER_DB_PASSWORD=12345 sbt boot/run

Список переменных окружения сервиса Archiver

Все доступные переменные окружения для настройки сервиса.

Переменная Тип Обязательная Значение по умолчанию Описание
ARCHIVER_HTTP_HOST String Нет "0.0.0.0" Хост, на котором слушает HTTP-сервер
ARCHIVER_HTTP_PORT Int Нет 8193 Порт, на котором слушает HTTP-сервер
ARCHIVER_KAFKA_SERVERS String Да "localhost:9092" Адрес Kafka
ARCHIVER_KAFKA_TOPIC String Нет "archiver_commands" Название кафка-топика для получения команд. Сервис получает кафка-команды по нему, но и также сам публикует это название в CommandDiscovery.
ARCHIVER_KAFKA_CONSUMER_GROUP String Нет "archiver_consumer_group" Имя consumer-группы для чтения из кафка-топика команд. Не должна меняться и не должна быть пустой, иначе сервис перечитает свои команды при перезапуске.
ARCHIVER_KAFKA_PARTITIONS Int Нет 10 Число читаемых партиций из кафка-топика команд.
ARCHIVER_KAFKA_CONSUMER_RESTART_MIN_BACKOFF Duration String Нет 1 second Изначальная задержка до рестарта консьюмера после падения (увеличивается в 2 раза после каждого рестарта)
ARCHIVER_KAFKA_CONSUMER_RESTART_MAX_BACKOFF Duration String Нет 30 seconds Максимальное задержка до рестарта консьюмера после падения
ARCHIVER_KAFKA_CONSUMER_RESTART_RANDOM_FACTOR Double Нет 0.2 Коэффициент величины дополнительной случайной задержки(jitter) относительно основной задержки (При значении 0.2 задержка может быть до 20% больше, чем при 0). Если после умножения задержки на ARCHIVER_KAFKA_CONSUMER_RESTART_RANDOM_FACTOR получится меньше 1 миллисекунды, то jitter будет приравнен к нулю.
ARCHIVER_KAFKA_CONSUMER_PER_MESSAGE_RESTART_MAX_RESTARTS Int Нет 2 Максимальное количество раз, которое консьюмер перезапустится с неизменной очередью сообщений(в пределах DATA_MODEL_KAFKA_CONSUMER_RESTART_MAX_RESTARTS_WITHIN), прежде чем проигнорировать сообщение, на котором происходит ошибка (Указано количество рестартов, а не прочтений. Если ARCHIVER_KAFKA_CONSUMER_RESTART_MAX_RESTARTS = 2, то ошибочное сообщение будет обработано 3 раза, после чего произойдет 3ий рестарт и оно будет проигнорировано). Если указать 0, то перезапуск произойдет, но сообщение будет обработано только в первый раз, когда произошла ошибка. Если указать значение меньше 0, то перезапуски все равно будут происходить, но игнорирование сообщений, вызывающих ошибку, будет отключено.
ARCHIVER_KAFKA_CONSUMER_PER_MESSAGE_RESTART_CACHE_SIZE Int Нет 100 Для каждого сообщения счетчик перепрочтений хранится в кэше. Максимальное количество значений в этом кэше.
ARCHIVER_KAFKA_CONSUMER_PER_MESSAGE_RESTART_CACHE_TTL Duration String Нет 5 minutes Для каждого сообщения счетчик перепрочтений хранится в кэше.Максимальное время жизни элемента в этом кэше. В случае отсутствия значения время жизни элемента не будет ограничено.
ARCHIVER_KAFKA_CONSUMER_RESTART_MAX_RESTARTS Int Нет 5 Максимальное число рестартов консьюмера после падения (в пределах ARCHIVER_KAFKA_CONSUMER_RESTART_MAX_RESTARTS_WITHIN).После превышения этого числа сервис будет объявлен больным. Все рестарты для каждого отдельного сообщения увеличивают и общий счетчик рестартов консьюмера, поэтому при использовании ARCHIVER_KAFKA_CONSUMER_PER_MESSAGE_RESTART_MAX_RESTARTS нужно указывать ARCHIVER_KAFKA_CONSUMER_RESTART_MAX_RESTARTS > ARCHIVER_KAFKA_CONSUMER_PER_MESSAGE_RESTART_MAX_RESTARTS или не указывать ARCHIVER_KAFKA_CONSUMER_PER_MESSAGE_RESTART_MAX_RESTARTS совсем.
ARCHIVER_KAFKA_CONSUMER_RESTART_MAX_RESTARTS_WITHIN Duration String Нет 5 minutes Временной отрезок, в который ARCHIVER_KAFKA_CONSUMER_RESTART_MAX_RESTARTS ограничивает число рестартов
ARCHIVER_KAFKA_CONSUMER_POLL_TIMEOUT Duration String Нет 10 milliseconds timeout запроса poll для kafka consumer
ARCHIVER_KAFKA_CONSUMER_POLL_INTERVAL Duration String Нет 100 milliseconds интервал между запросами poll для kafka consumer
ARCHIVER_KAFKA_CONSUMER_PROPS String Нет "max.poll.records=500;max.partition.fetch.bytes=524288" дополнительные параметры для kafka consumer в формате "key1=value1;key2=value2"
ARCHIVER_KAFKA_PRODUCER_PROPS String Нет "batch.size=524288;linger.ms=10;max.request.size=1048576" дополнительные параметры для kafka producer в формате "key1=value1;key2=value2"
ARCHIVER_KAFKA_COMMANDEVENT_TOPIC String Да "commandevents" Название кафка-топика для отправки сообщений со статусами выполняемых команд. ОБЯЗАТЕЛЬНО должно соответствовать названию этого топика в сервисе статуса команд.
ARCHIVER_KAFKA_AUTH_USER String Нет "" Название учетной записи Kafka. Если название не указано, то настройки авторизации не будут применены.
ARCHIVER_KAFKA_AUTH_PASSWORD String Нет "" Пароль учетной записи Kafka.
ARCHIVER_KAFKA_AUTH_TRUSTSTORE_LOCATION String Нет "" Путь до хранилища сертификатов (Java key store). Если путь не указан, то сертификат применятся не будет.
ARCHIVER_KAFKA_AUTH_TRUSTSTORE_PASSWORD String Нет "" Пароль к хранилищу сертификатов.
ARCHIVER_KAFKA_AUTH_MODE String Нет "" Режим аутентификации: static - одна учетная запись на все запросы, mapping - учетная запись зависит от запроса
ARCHIVER_KAFKA_AUTH_CONFIG String Нет "" Настройки для аутентификации: если AuthMode = mapping, то необходим JSON с List[KafkaAuthConfig]
ARCHIVER_KAFKA_AUTH_CACHE_SIZE Int Нет Максимальный размер кеша для Kafka producer (количество активных соединений).
ARCHIVER_KAFKA_AUTH_CACHE_TTL Duration String Нет Время жизни Kafka producer в кеше.
ARCHIVER_KAFKA_CONNECTION_CHECK_TEST_MESSAGES_INTERVAL Duration String Нет 4 minutes Применяется только для producer-ов со способом аутентификации kerberos. Интервал отправки тестовых сообщений кафки в топик connectionCheck.testMessagesTopicName. Тестовые сообщения (null, service producer test) отправляются регулярно с этим интервалом.
ARCHIVER_KAFKA_CONNECTION_CHECK_INTERVAL Duration String Нет 60 seconds Применяется только для producer-ов со способом аутентификации kerberos. Интервал проверки того, сколько тестовых сообщений было отправлено за данный период. Если количество сообщений за этот период равно количеству сообщений за прошлый период, то начинается отсчет периода без сообщений.
ARCHIVER_KAFKA_CONNECTION_CHECK_FAILED_AFTER_INTERVAL Duration String Нет 5 minutes Применяется только для producer-ов со способом аутентификации kerberos. Максимальная продолжительность периода без успешно отправленных тестовых сообщений. По ее достижении сервис будет объявлен больным.
ARCHIVER_KAFKA_PRODUCER_PROPS String Нет "max.request.size=1048576" Дополнительные параметры для Kafka producer. Заполняются по шаблону "key1=value1;key2=value2".
ARCHIVER_CONSUL_ADDR URL Нет "http://localhost:8500" Адрес Сonsul.
ARCHIVER_CONSUL_AUTH_USER String Нет "" Название учетной записи Сonsul. Если название не указано, то настройки авторизации не будут применены.
ARCHIVER_CONSUL_AUTH_PASSWORD String Нет "" Пароль учетной записи Сonsul.
ARCHIVER_TRACE_DURATION Boolean Нет false Признак необходимости трассировки выполнения команд
ARCHIVER_DISCOVERABLE_ID String Нет "another_ARCHIVER_service_instance" ID сервиса в ServiceDiscovery
ARCHIVER_DISCOVERABLE_NAME String Нет "archiver" Имя сервиса в ServiceDiscovery
ARCHIVER_DISCOVERABLE_HOST String Да "localhost" Хост, публикуемый в ServiceDiscovery. По нему на данный сервис будут обращаться другие через HTTP. Указанный адрес должен быть виден другим сервисам. Пример: имя kubernetes/docker_swarm service
ARCHIVER_DISCOVERABLE_PORT Int Нет Порт, публикуемый в ServiceDiscovery. По нему на данный сервис будут обращаться другие через HTTP. По умолчанию указывается порт, который слушает HTTP-сервер.
ARCHIVER_DISCOVERABLE_LIVETIME Duration String Нет 2 minutes Период после последней отправки health check, в течение которого ServiceDiscovery считает данный сервис живым.
ARCHIVER_DISCOVERABLE_HEALTHPASS String Нет 1 minute Периодичность отправки health check в ServiceDiscovery
ARCHIVER_SERVICE_TITLE String Нет "Archiver" Название сервиса для отображения
ARCHIVER_SERVICE_DESCRIPTION String Нет "Service ARCHIVER" Описание сервиса для отображения
ARCHIVER_AKKA_HTTP_CLIENT_MAXCON Int Нет 512 Максимальное число одновременных исходящих HTTP-соединений
ARCHIVER_AKKA_HTTP_CLIENT_MAXREQ Int Нет 1024 Максимальное число одновременных исходящих HTTP-запросов
ARCHIVER_AKKA_HTTP_SERVER_MAXCON Int Нет 1024 Максимальное число одновременных входящих HTTP-соединений
ARCHIVER_INTERNALCMD_ALLOW Boolean Нет false Можно ли сервису отправлять внутрисистемные команды
ARCHIVER_SENDERLIB_CONSIDER_ALL_COMMANDS_AS_INTERNAL Boolean Нет false Флаг, определяющий будут ли все обращения в другие сервисы являться внутренними (т.е. не требовать авторизацию). Детальное описание механизма: Внутренние команды.
ARCHIVER_SENDERLIB_COMMANDS_CACHE_UPDATEPERIOD Duration String Нет 10 minutes Время кэширования данных по командам из CommandDiscovery
ARCHIVER_SENDERLIB_SERVICES_CACHE_UPDATEPERIOD Duration String Нет 30 seconds Время кэширования данных по сервисам из ServiceDiscovery
ARCHIVER_SENDERLIB_CONSUL_CONNECTION_RETRY_MAX Int Нет 5 Количество попыток переподключения к Consul
ARCHIVER_SENDERLIB_CONSUL_CONNECTION_RETRY_DELAY Duration String Нет 1 second Задержка при попытках переподключения к Consul
ARCHIVER_DB_HOST String Да Хост БД
ARCHIVER_DB_PORT Int Да Порт БД
ARCHIVER_DB_NAME String Да Имя базы в БД
ARCHIVER_DB_URL JBDC URL Нет JDBC-url для соединения с БД. По умолчанию собирается из других обязательных переменных. Можно указать только его, если не хочется отдельно указывать хост/порт/имя базы.
ARCHIVER_DB_USER String Да Пользователь БД
ARCHIVER_DB_PASSWORD String Да Пароль пользователя БД
ARCHIVER_DB_THREADS Int Нет 10 Количество потоков в пуле потоков для соединения с БД
ARCHIVER_DB_QUEUE_SIZE Int Нет 300 Размер очереди для действий базы данных, которые не могут быть выполнены немедленно, когда все потоки заняты. За пределами этого значения новые действия немедленно завершаются неудачей
ARCHIVER_DB_CONN_MAX Int Нет 10 Максимальное количество одновременных подключений к БД
ARCHIVER_DB_CONN_TIMEOUT Duration String Нет 20 second Максимальное время ожидания ответа для соединения к БД. Если это время превышено, а соединение не становится доступным, будет брошено исключение SQLException. 1000 мс — минимальное значение.
ARCHIVER_DB_ISOLATION String Нет "READ_COMMITTED" Уровень изоляции транзакций для новых подключений. Допустимые значения: NONE, READ_COMMITTED, READ_UNCOMMITTED, REPEATABLE_READ, SERIALIZABLE.
ARCHIVER_DB_READONLY Boolean Нет false Read-only SQL транзакция может изменять только временные таблицы. Этот параметр управляет статусом «только для чтения» по умолчанию для каждой новой транзакции.
ARCHIVER_DB_CONN_MIN Int Нет = DB_THREADS Минимальное количество одновременных подключений к БД
ARCHIVER_DB_VALIDATION_TIMEOUT Duration String Нет 1 seconds Максимальное время, в течение которого соединение будет проверяться на работоспособность. 1000 мс — минимальное значение.
ARCHIVER_DB_IDLE_TIMEOUT Duration String Нет 10 minutes Максимальное время, в течение которого соединению разрешено простаивать в пуле. Значение 0 означает, что простаивающие соединения никогда не удаляются из пула.
ARCHIVER_DB_MAX_LIFETIME Duration String Нет 30 minutes Максимальное время жизни соединения в пуле. Когда простаивающее соединение достигает этого времени ожидания, даже если оно недавно использовалось, оно будет удалено из пула. Значение 0 указывает на отсутствие максимального срока службы.
ARCHIVER_DB_INITIALIZATION_FAIL_FAST String Нет false Deprecated, начиная с версии Slick 3.3.0. Определяет, будет ли пул «быстро выходить из строя», если пул не может быть успешно заполнен начальными соединениями. Если соединения не могут быть созданы во время запуска пула, будет выдано исключение RuntimeException. Это свойство не имеет никакого эффекта, если minConnections равно 0.
ARCHIVER_DB_LEAK_DETECTION_THRESHOLD Int Нет 0 Время, в течение которого соединение может находиться вне пула, прежде чем будет зарегистрировано сообщение, указывающее на возможную утечку соединения. Значение 0 означает, что обнаружение утечек отключено. Наименьшее приемлемое значение для включения обнаружения утечек составляет 10 с.
ARCHIVER_DB_CONNECTION_TEST_QUERY String Нет "SELECT 1" Выражение, которое будет выполнено непосредственно перед получением соединения из пула для проверки того, что соединение с базой данных все еще активно. Оно зависит от базы данных и должно представлять собой запрос, требующий минимальной обработки базой данных (например, «VALUES 1»). Если этот параметр не установлен, вместо него используется метод JDBC4 Connection.isValid().
ARCHIVER_DB_AUTO_COMMIT Boolean Нет true Это свойство определяет то, как будут вести себя по умолчанию возвращаемые соединения относительно autocommit-а.
ARCHIVER_DB_SCHEMA String Нет "public" Устанавливает schema по умолчанию
ARCHIVER_DB_ISOLATE_INTERNAL_QUERIES Boolean Нет false Определяет то, изолируются ли с помощью транзакций внутренние запросы пула(например запрос connection alive test). Свойство применяется только если autoCommit выключен.
ARCHIVER_DB_INITIALIZATION_FAIL_TIMEOUT Int Нет 1 Работает, начиная с версии Slick 3.3.0. Определяет, будет ли пул «быстро выходить из строя», если пул не может быть успешно заполнен начальными соединениями. Любое положительное число считается числом миллисекунд для попытки получить начальное соединение;поток приложения будет заблокирован в течение этого периода. Если соединение не может быть получено до истечения этого времени,будет брошено исключение. Данный таймаут применяется после периода connectionTimeout. Если значение равно нулю (0),HikariCP попытается получить и проверить подключение. Если соединение получено,но проверка не пройдена, будет брошено исключение, и пул не будет запущен. Однако,если соединение не может быть получено, пул запустится,но последующие попытки получить соединение могут потерпеть неудачу.Значение меньше нуля пройдет любую первоначальную попытку подключения, и пул немедленно запустится,пытаясь получить соединения в фоновом режиме.Следовательно, последующие попытки получить соединение могут потерпеть неудачу.
ARCHIVER_DB_REGISTER_MBEANS Boolean Нет false Зарегистрированы ли JMX Management Beans («MBeans»)
ARCHIVER_AUTHZFORCE_ADDR String Нет "http://localhost:8080/authzforce-ce" Адрес AuthZforce server
ARCHIVER_AUTHZFORCE_DOMAIN String Нет "" Доступный DomainID в AuthZforce server
ARCHIVER_AUTHZFORCE_CONNECT_TIMEOUT Duration String Нет 10 seconds Timeout присоединения к AuthZforce server
LOG_LEVEL String Нет INFO Общий уровень логирования в сервисе
LOG_LEVEL_AKKA String Нет INFO Уровень логирования для akka
LOG_LEVEL_LIQUIBASE String Нет INFO Уровень логирования для liquibase (миграции)
LOG_LEVEL_APPLICATION String Нет DEBUG Уровень логирования для application
LOG_LEVEL_SLICK_STATEMENT String Нет DEBUG Уровень логирования запросов, отправляемых slick в БД
LOG_LEVEL_SLICK_BENCHMARK String Нет OFF Уровень логирование бенчмарков выполнения запросов slick
LOG_LEVEL_KAFKA_PRODUCER String Нет WARN Уровень логирования конфига kafka-producer
LOG_LEVEL_KAFKA_CONSUMER String Нет WARN Уровень логирования конфига kafka-consumer
LOG_LEVEL_HTTP_SERVER String Нет WARN Уровень логирования HTTP-сервера
LOG_LEVEL_AKKAHTTPSENDER String Нет TRACE Уровень логирования для отправки команд через HTTP. На уровне INFO логируется трассировка, если она включена
LOG_LEVEL_KAFKASENDER String Нет TRACE Уровень логирования для отправки команд через Kafka. На уровне INFO логируется трассировка, если она включена
LOG_LEVEL_COMMANDSTATUSCLI String Нет TRACE Уровень логирования для проверки состояний команд в сервисе статусов
LOG_LEVEL_TEAM_ROUTES String Нет TRACE Уровень логирования для роутов /team
ARCHIVER_FS_URI URL Нет http://localhost:9000 Адрес S3 файлового хранилища
ARCHIVER_FS_ACCESS_KEY_ID String Нет minioadmin Идентификатор доступа к s3
ARCHIVER_FS_SECRET_ACCESS_KEY String Нет minioadmin Секретный ключ доступа к s3
ARCHIVER_FS_UPLOAD_PARALLELISM Int Нет 4 Параллелизм загрузки файлов в s3
ARCHIVER_FS_AUTH_MODE String Нет static Режим аутентификации: static - одна учетная запись на все запросы, mapping - учетная запись зависит от запроса
ARCHIVER_FS_AUTH_CONFIG String Нет "" Настройки для аутентификации: если AuthMode = mapping, то необходим JSON с List[FSBucketConfig] соответствует полю authConfig FSConfigRep
ARCHIVER_FS_CACHE_SIZE Int Нет 1 Максимальный размер кеша клиентов для хранилища файлов (количество активных соединений)
ARCHIVER_FS_CACHE_TTL Duration String Нет Время жизни клиента в кеше
ARCHIVER_FS_RETRY_ATTEMPTS Int Нет 5 Количество ретраев, которое будет произведено в случае Exception-а в операции FSClient-а и при вычитывании стрима в get операциях FSClient-а.
ARCHIVER_FS_RETRY_DELAY Duration String Нет 10 millis Задержка между ретраями операций FSClient-а.
ARCHIVER_FS_TEMP_BUCKET String Нет "temp" Название бакета в s3, в котором находятся временные файлы
ARCHIVER_FS_ARCHIVE_BUCKET String Нет "archive" Название бакета в s3, в котором находятся архивы
ARCHIVER_FS_ZIO_SHORT_MESSAGE_MODE Boolean Нет false Флаг включения режима сохранения ошибок работы с файловым хранилищем в сервисе журналирования nestor. При включении режима ошибки в логах будут отображаться в сокращенном формате: Short zio message mode. ExceptionType: ТИП ОШИБКИ, Exception id: 'СГЕНЕРИРОВАННЫЙ UUID' added to journal. Указанный id будет фиксироваться в event записи nestor'а в поле data.id
ARCHIVER_FS_CHUNK_SIZE Int Нет 8192 Размер буферов для обработки стримов из s3.
ARCHIVER_JOURNAL_MODE String Нет WriteToJournal Режим журналирования Nestor. Допустимые значения: WriteToJournal (Отправка в сервис журналирования), WriteToTopic (Отправка события в очередь)
ARCHIVER_JOURNAL_TOPIC String Да, если переменная ARCHIVER_JOURNAL_MODE = WriteToTopic "" Название очереди журналирования. Для режима WriteToJournal значение игнорируется.

Список команд сервиса Archiver

В описании команд используется путь/route для отправки команды в сам сервис, а не в ApiGateway. В качестве Input-а для команд, сервис всегда ожидает CommandRequest (как и любой другой сервис, принимающий команды), так что в описании команды указано лишь описание поля payload для CommandRequest.

В сервисе реализованно 4 команды:

Название команды EntityType Actions
Список архивов Archiver ViewArchiveRegistry
Архивация файлов из S3 Archiver CreateArchive
Архивация файлов из модели данных Archiver CreateArchive
Распаковка архива Archiver UnpackArchive

ListArchives

На входе

{
  "query": "",
  "context": {}
}

На выходе

{
  "items": [
    {
      "archiveUrl": "archive/archiveName.zip",
      "userId": "00000000-0000-0000-0000-000000000000",
      "status": "finished",
      "fileUrls": [
        "/temp/21b130ad-008d-43ef-a681-04fcdfe91afc"
      ],
      "entityObjectIdentities": null
    },
    {
      "archiveUrl": "archive/closed.zip",
      "userId": "00000000-0000-0000-0000-000000000000",
      "status": "closed",
      "fileUrls": [
        "sed-nmd-rc-datamodel/NmdPublish/a077e8dd-eb0f-4e82-aea9-be5596f0fb55",
        "sed-nmd-rc-datamodel/NmdPublish/c61f0c50-3b62-4f2c-bcfe-e15e38f5f317",
        "sed-nmd-rc-datamodel/NmdPublish/1d1249a3-ebfc-4df8-bd31-e1264c18da22",
        "sed-nmd-rc-datamodel/NmdPublish/276209fb-4d0b-4454-92fb-f19a4b8a5db8"
      ],
      "entityObjectIdentities": [
        {
          "entityType": "NmdPublish",
          "objectId": "deed5141-a45d-4931-866a-db3759124659"
        },
        {
          "entityType": "NmdPublish",
          "objectId": "b986085c-d80a-420f-b294-5a7ccff5ea49"
        },
        {
          "entityType": "NmdPublish",
          "objectId": "2688b889-b3ac-4d61-b7ca-ef10e5c03c7b"
        },
        {
          "entityType": "NmdPublish",
          "objectId": "414b92bd-b0a5-4a4e-a429-5a2c20062141"
        }
      ]
    },
    {
      "archiveUrl": "archive/empty.zip",
      "userId": "00000000-0000-0000-0000-000000000000",
      "status": "finished",
      "fileUrls": [],
      "entityObjectIdentities": null
    }
  ],
  "total": 3
}

Возвращает список всех архивов.

Результат выполнения команды не журналируется.

Команда Путь
archiver_http_listArchives HTTP POST "/archiver_http_listArchives"

ArchiveFromUrls

На входе

{
  "filesUrls": [
    "/temp/21b130ad-008d-43ef-a681-04fcdfe91afc",
    "/temp/21b130ad-008d-43ef-a681-04fcdfe91afc"
  ],
  "archiveName": "archiveName"
}

На выходе

{
  "archiveUrl": "archive/archiveName.zip",
  "status": "finished"
}

Архивация файлов из S3, переданных ссылками.

Результат выполнения команды не журналируется.

Команда Путь
archiver_kafka_archiveFromUrls Kafka Topic "archiver_commands"

ArchiveFromDataModelSearch

На входе

{
  "search": {
    "query": "entityType",
    "context": {
      "entityType": "NmdPublish"
    }
  },
  "archiveName": "archiveName",
  "includedFiles": "all",
  "additionalFilesFilter": [
    "pdf"
  ]
}

На выходе

{
  "archiveUrl": "archive/archiveName.zip",
  "status": "finished"
}

Архивация файлов из S3, привязанных к сущностям датамодела, найденым по переданному search.

Результат выполнения команды не журналируется.

Команда Путь
archiver_kafka_archiveFromDataModelSearch Kafka Topic "archiver_commands"

Unarchive

На входе

"temp/archiveName.zip"

На выходе

[
  {
    "fileId": "98ac926c-9b9a-4464-997f-5307b8a48abf",
    "name": "myFileName1.txt",
    "size": 9181759,
    "url": "temp/98ac926c-9b9a-4464-997f-5307b8a48abf",
    "md5": "E06273F88B2A9AF84C2A826C3AA97DA9",
    "contentType": "binary/octet-stream"
  },
  {
    "fileId": "41df8b0a-f742-4fae-80bc-c1a25052d3b9",
    "name": "myFileName2.txt",
    "size": 9181751,
    "url": "temp/41df8b0a-f742-4fae-80bc-c1a25052d3b9",
    "md5": "69BCDFC2BBE42DFE34610A924403381E",
    "contentType": "binary/octet-stream"
  }
]

Разархивация архива из S3, возвращает список файлов, которые были в архиве. Извлекаемые файлы сохраняются в 'ARCHIVER_FS_TEMP_BUCKET', при загрузке сохраняется ownerUserId от исходного файла.

Результат выполнения команды не журналируется.

Объекты сервиса Archiver

ArchiveDTO

Поле Тип Обязательное Описание
archiveUrl String да url архива в S3
userId UUID Нет UUID пользователя - автора
status String (finished, inProcess, closed, deleted) да Статус архива
fileUrls String[] да Список url собранных файлов в S3
entityObjectIdentities EntityObjectIdentity[] Нет Список связанных объектов модели данных

UrlsInputDTO

Поле Тип Обязательное Описание
archiveUrl String да url архива в S3
fileUrls String[] да Список url собранных файлов в S3

SearchInputDTO

Поле Тип Обязательное Значение по умолчанию Описание
archiveUrl String да - url архива в S3
search Search да - search объектов из модели данных
includedFiles String (all, main, additional) нет "main" Какого типа файлы включить в архив
additionalFilesFilter String[] нет - Из каких полей взять дополнительные файлы

OutputDTO

Поле Тип Обязательное Описание
archiveUrl String да url архива в S3
status String (finished, inProcess) да Статус архива

Attila-client: клиент для сервиса Attila

Предоставляемые методы: - TBD

Ключевые сущности: - TBD

Attila: сервис композитных правил

Данные сервиса хранятся в PostgreSQL. Команды могут приходить как по HTTP, так и по Kafka.

Сервис разбит на несколько модулей, в виде sbt проектов:

В сервисе реализованны следующие команды:

Локальный запуск сервиса Attila

При запуске сервиса ожидается, что уже развернута необходимая инфраструктура:

Запуск Attila из консоли с помощью SBT

ATTILA_DB_HOST=localhost ATTILA_DB_PORT=5432 ATTILA_DB_NAME=attila_db ATTILA_DB_USER=$ATTILA_DB_USER ATTILA_DB_PASSWORD=$ATTILA_DB_PASSWORD sbt boot/run

Список всех переменных окружения для сервиса Attila

Переменная Тип Обязательная Значение по умолчанию Описание
ATTILA_HTTP_HOST String Да "0.0.0.0" Хост для HttpListener
ATTILA_HTTP_PORT Int Да 8192 Порт для HttpListener
ATTILA_KAFKA_SERVERS String Да "localhost:9092" Адрес Kafka
ATTILA_KAFKA_TOPIC String Нет "attila_commands" Название топика для входящих команд
ATTILA_KAFKA_COMMANDEVENT_TOPIC String Нет "commandevents" Название топика для входящих/исходящих событий
ATTILA_KAFKA_CONSUMER_GROUP String Да Название группы для чтения топика событий
ATTILA_KAFKA_TOPIC_PARTITIONS Int Да 10 Количество партиций в топике команд.
ATTILA_KAFKA_CONSUMER_RESTART_MIN_BACKOFF Duration String Нет "1 second" Минимальная задержка перед перезапуском.
ATTILA_KAFKA_CONSUMER_RESTART_MAX_BACKOFF Duration String Нет "30 seconds" Максимально возможная задержка перед перезапуском.
ATTILA_KAFKA_CONSUMER_RESTART_RANDOM_FACTOR Double Нет 0.2 Коэффициент величины дополнительной случайной задержки (jitter) относительно основной задержки (При значении 0.2 задержка может быть до 20% больше, чем при 0). Если после умножения задержки на ATTILA_KAFKA_CONSUMER_RESTART_RANDOM_FACTOR получится меньше 1 миллисекунды, то jitter будет приравнен к нулю.
ATTILA_KAFKA_CONSUMER_RESTART_MAX_RESTARTS Int Нет 5 Максимальное количество перезапусков в заданный период времени. После превышения этого числа сервис будет объявлен больным. Все рестарты для каждого отдельного сообщения увеличивают и общий счетчик рестартов консьюмера, поэтому при использовании ATTILA_KAFKA_CONSUMER_PER_MESSAGE_RESTART_MAX_RESTARTS нужно указывать ATTILA_KAFKA_CONSUMER_RESTART_MAX_RESTARTS > ATTILA_KAFKA_CONSUMER_PER_MESSAGE_RESTART_MAX_RESTARTS или не указывать ATTILA_KAFKA_CONSUMER_PER_MESSAGE_RESTART_MAX_RESTARTS совсем
ATTILA_KAFKA_CONSUMER_RESTART_MAX_RESTARTS_WITHIN String Нет "5 minutes" Период времени для ограничения перезапусков.
ATTILA_KAFKA_CONSUMER_PER_MESSAGE_RESTART_MAX_RESTARTS Int Нет 2 Максимальное количество раз, которое консьюмер перезапустится с неизменной очередью сообщений (в пределах DATA_MODEL_KAFKA_CONSUMER_RESTART_MAX_RESTARTS_WITHIN), прежде чем проигнорировать сообщение, на котором происходит ошибка (Указано количество рестартов, а не прочтений. Если ATTILA_KAFKA_CONSUMER_RESTART_MAX_RESTARTS = 2, то ошибочное сообщение будет обработано 3 раза, после чего произойдет 3ий рестарт и оно будет проигнорировано). Если указать 0, то перезапуск произойдет, но сообщение будет обработано только в первый раз, когда произошла ошибка. Если указать значение меньше 0, то перезапуски все равно будут происходить, но игнорирование сообщений, вызывающих ошибку, будет отключено.
ATTILA_KAFKA_CONSUMER_PER_MESSAGE_RESTART_CACHE_SIZE Int Нет 100 Для каждого сообщения счетчик перепрочтений хранится в кэше. Максимальное количество значений в этом кэше.
ATTILA_KAFKA_CONSUMER_PER_MESSAGE_RESTART_CACHE_TTL Duration String Нет 5 minutes Для каждого сообщения счетчик перепрочтений хранится в кэше. Максимальное время жизни элемента в этом кэше. В случае отсутствия значения время жизни элемента не будет ограничено.
ATTILA_KAFKA_CONSUMER_POLL_TIMEOUT Duration String Нет 10 milliseconds timeout запроса poll для kafka consumer
ATTILA_KAFKA_CONSUMER_POLL_INTERVAL Duration String Нет 100 milliseconds интервал между запросами poll для kafka consumer
ATTILA_KAFKA_CONSUMER_PROPS String Нет "max.poll.records=500;max.partition.fetch.bytes=524288" дополнительные параметры для kafka consumer в формате "key1=value1;key2=value2"
ATTILA_KAFKA_AUTH_USER String Нет "" Название учетной записи Kafka. Если название не указано, то настройки авторизации не будут применены.
ATTILA_KAFKA_AUTH_PASSWORD String Нет "" Пароль учетной записи Kafka.
ATTILA_KAFKA_AUTH_PRINCIPAL String Нет "" Principal учетной записи Kafka в Kerberos(в случае соединения с kafka через Kerberos).
ATTILA_KAFKA_AUTH_KEYTAB_PATH String Нет "" Путь до keytab-файла (в случае соединения с kafka через Kerberos).
ATTILA_KAFKA_AUTH_TRUSTSTORE_LOCATION String Нет "" Путь до хранилища сертификатов (Java key store). Если путь не указан, то сертификат применяться не будет.
ATTILA_KAFKA_AUTH_TRUSTSTORE_PASSWORD String Нет "" Пароль к хранилищу сертификатов.
ATTILA_KAFKA_AUTH_MODE String Нет Режим аутентификации: static - одна учетная запись на все запросы, mapping - учетная запись зависит от запроса
ATTILA_KAFKA_AUTH_CONFIG String Нет Настройки для аутентификации: если AuthMode = mapping, то необходим JSON с List[KafkaAuthConfig]. Переменная соответствует полю authConfig из KafkaAuthSettings.
ATTILA_KAFKA_AUTH_CACHE_SIZE Int Нет Максимальный размер кеша для Kafka producer (количество активных соединений).
ATTILA_KAFKA_CONNECTION_CHECK_TEST_MESSAGES_INTERVAL Duration String Нет 4 minutes Применяется только для producer-ов со способом аутентификации kerberos. Интервал отправки тестовых сообщений кафки в топик connectionCheck.testMessagesTopicName. Тестовые сообщения (null, service producer test) отправляются регулярно с этим интервалом.
ATTILA_KAFKA_CONNECTION_CHECK_INTERVAL Duration String Нет 60 seconds Применяется только для producer-ов со способом аутентификации kerberos. Интервал проверки того, сколько тестовых сообщений было отправлено за данный период. Если количество сообщений за этот период равно количеству сообщений за прошлый период, то начинается отсчет периода без сообщений.
ATTILA_KAFKA_CONNECTION_CHECK_FAILED_AFTER_INTERVAL Duration String Нет 5 minutes Применяется только для producer-ов со способом аутентификации kerberos. Максимальная продолжительность периода без успешно отправленных тестовых сообщений. По ее достижении сервис будет объявлен больным.
ATTILA_KAFKA_AUTH_CACHE_TTL Duration String Нет Время жизни Kafka producer в кеше.
ATTILA_CONSUL_ADDR String Да "http://localhost:8500" Адрес Сonsul.
ATTILA_CONSUL_AUTH_USER String Нет "" Название учетной записи Сonsul. Если название не указано, то настройки авторизации не будут применены.
ATTILA_CONSUL_AUTH_PASSWORD String Нет "" Пароль учетной записи Сonsul.
ATTILA_TRACE_DURATION Boolean Нет false Нужно ли логировать длительность выполнения команд
ATTILA_DISCOVERABLE_ID String Нет "another_attila_instance" ID данного сервиса
ATTILA_DISCOVERABLE_NAME String Нет "attila" Название группы сервисов к которой принадлежит данный
ATTILA_DISCOVERABLE_HOST String Нет "localhost" Адрес текущего инстанса сервиса, который будет виден через ServiceDiscovery
ATTILA_DISCOVERABLE_PORT String Нет {ATTILA_HTTP_PORT} Адрес текущего инстанса сервиса, который будет виден через ServiceDiscovery
ATTILA_DISCOVERABLE_LIVETIME Duration String Нет "2 minutes" Время с последнего HeathCheck, в течении которого сервис считается "живым"
ATTILA_DISCOVERABLE_HEALTHPASS Duration String Нет "1 minute" Периодичность отправки HeathCheck
ATTILA_INTERNALCMD_ALLOW Boolean Нет true Возможно ли сервису отправлять "внутренние" команды
ATTILA_SENDERLIB_CONSIDER_ALL_COMMANDS_AS_INTERNAL Boolean Нет false Флаг, определяющий будут ли все обращения в другие сервисы являться внутренними (т.е. не требовать авторизацию). Детальное описание механизма: Внутренние команды.
ATTILA_SENDERLIB_COMMANDS_CACHE_UPDATEPERIOD Duration String Нет "10 minutes" Время на которое будут кешироваться данные о командах
ATTILA_SENDERLIB_SERVICES_CACHE_UPDATEPERIOD Duration String Нет "30 seconds" Время на которое будут кешироваться данные о сервисах
ATTILA_DB_HOST String Да Хост сервера базы данных
ATTILA_DB_PORT String Да Порт сервера базы данных
ATTILA_DB_NAME String Да Название базы
ATTILA_DB_USER String Да Пользователь для базы данных
ATTILA_DB_PASSWORD String Да Пароль для пользователь для базы данных
ATTILA_DB_THREADS Int Нет 10 Количество потоков в пуле потоков для соединения с БД
ATTILA_DB_QUEUE_SIZE Int Нет 300 Размер очереди для действий базы данных, которые не могут быть выполнены немедленно, когда все потоки заняты. За пределами этого значения новые действия немедленно завершаются неудачей
ATTILA_DB_CONN_MAX Int Нет 10 Максимальное количество одновременных подключений к БД
ATTILA_DB_CONN_TIMEOUT Duration String Нет 20 second Максимальное время ожидания ответа для соединения к БД. Если это время превышено, а соединение не становится доступным, будет брошено исключение SQLException. 1000 мс — минимальное значение.
ATTILA_DB_ISOLATION String Нет "READ_COMMITTED" Уровень изоляции транзакций для новых подключений. Допустимые значения: NONE, READ_COMMITTED, READ_UNCOMMITTED, REPEATABLE_READ, SERIALIZABLE.
ATTILA_DB_READONLY Boolean Нет false Read-only SQL транзакция может изменять только временные таблицы. Этот параметр управляет статусом «только для чтения» по умолчанию для каждой новой транзакции.
ATTILA_DB_CONN_MIN Int Нет = DB_THREADS Минимальное количество одновременных подключений к БД
ATTILA_DB_VALIDATION_TIMEOUT Duration String Нет 1 seconds Максимальное время, в течение которого соединение будет проверяться на работоспособность. 1000 мс — минимальное значение.
ATTILA_DB_IDLE_TIMEOUT Duration String Нет 10 minutes Максимальное время, в течение которого соединению разрешено простаивать в пуле. Значение 0 означает, что простаивающие соединения никогда не удаляются из пула.
ATTILA_DB_MAX_LIFETIME Duration String Нет 30 minutes Максимальное время жизни соединения в пуле. Когда простаивающее соединение достигает этого времени ожидания, даже если оно недавно использовалось, оно будет удалено из пула. Значение 0 указывает на отсутствие максимального срока службы.
ATTILA_DB_INITIALIZATION_FAIL_FAST String Нет false Deprecated, начиная с версии Slick 3.3.0. Определяет, будет ли пул «быстро выходить из строя», если пул не может быть успешно заполнен начальными соединениями. Если соединения не могут быть созданы во время запуска пула, будет выдано исключение RuntimeException. Это свойство не имеет никакого эффекта, если minConnections равно 0.
ATTILA_DB_LEAK_DETECTION_THRESHOLD Int Нет 0 Время, в течение которого соединение может находиться вне пула, прежде чем будет зарегистрировано сообщение, указывающее на возможную утечку соединения. Значение 0 означает, что обнаружение утечек отключено. Наименьшее приемлемое значение для включения обнаружения утечек составляет 10 с.
ATTILA_DB_CONNECTION_TEST_QUERY String Нет "SELECT 1" Выражение, которое будет выполнено непосредственно перед получением соединения из пула для проверки того, что соединение с базой данных все еще активно. Оно зависит от базы данных и должно представлять собой запрос, требующий минимальной обработки базой данных (например, «VALUES 1»). Если этот параметр не установлен, вместо него используется метод JDBC4 Connection.isValid().
ATTILA_DB_AUTO_COMMIT Boolean Нет true Это свойство определяет то, как будут вести себя по умолчанию возвращаемые соединения относительно autocommit-а.
ATTILA_DB_SCHEMA String Нет "public" Устанавливает schema по умолчанию
ATTILA_DB_ISOLATE_INTERNAL_QUERIES Boolean Нет false Определяет то, изолируются ли с помощью транзакций внутренние запросы пула (например запрос connection alive test). Свойство применяется только если autoCommit выключен.
ATTILA_DB_INITIALIZATION_FAIL_TIMEOUT Int Нет 1 Работает, начиная с версии Slick 3.3.0. Определяет, будет ли пул «быстро выходить из строя», если пул не может быть успешно заполнен начальными соединениями. Любое положительное число считается числом миллисекунд для попытки получить начальное соединение;поток приложения будет заблокирован в течение этого периода. Если соединение не может быть получено до истечения этого времени, будет брошено исключение. Данный таймаут применяется после периода connectionTimeout. Если значение равно нулю (0),HikariCP попытается получить и проверить подключение. Если соединение получено, но проверка не пройдена, будет брошено исключение, и пул не будет запущен. Однако, если соединение не может быть получено, пул запустится, но последующие попытки получить соединение могут потерпеть неудачу. Значение меньше нуля пройдет любую первоначальную попытку подключения, и пул немедленно запустится, пытаясь получить соединения в фоновом режиме. Следовательно, последующие попытки получить соединение могут потерпеть неудачу.
ATTILA_DB_REGISTER_MBEANS Boolean Нет false Зарегистрированы ли JMX Management Beans («MBeans»)
LOG_LEVEL_HLRULE_CONVERTER String Нет "INFO" Уровень логов для процесса конвертации высокоуровневых правил
ATTILA_READABLE_NAME String Нет "Сервис композитных правил" Читаемое название этого сервиса
ATTILA_DESCRIPTION String Нет "Сервис для работы с композитными правилами ограничения доступа" Читаемое описание этого сервиса
ATTILA_RULE_UPDATE_TIMEOUT Duration String Нет "10 minutes" Таймаут на обновление HighLevelRule в сервисе Оberto
ATTILA_DEFAULT_RESOURCES String Нет "User{id:Идентификатор пользователя;email:Email пользователя;groupId:Идентификаторы групп пользователя}" Описание ресурсов по умолчанию. Разделитель между ресурсами и полями в них ";". Символы для названий ресурсов и полей "a-zA-Z_\-0-9". Для описания разрешено все, кроме ";" и "}".
ATTILA_SENDERLIB_COMMANDS_HTTP_RETRY_ATTEMPTS Int Нет 5 Поле attempts из RetrySettings
ATTILA_SENDERLIB_COMMANDS_HTTP_RETRY_DELAY Duration String Нет "5 seconds" Поле delay из RetrySettings
ATTILA_SENDERLIB_COMMANDS_HTTP_RETRY_KIND String Нет "OnSomeExceptions(ConnectException)" CommandResultRetryConditionKind
ATTILA_SENDERLIB_CONSUL_CONNECTION_RETRY_MAX Int Нет 5 Количество попыток переподключения к Consul
ATTILA_SENDERLIB_CONSUL_CONNECTION_RETRY_DELAY Duration String Нет "1 second" Задержка при попытках переподключения к Consul
ATTILA_JOURNAL_MODE String Нет WriteToJournal Режим журналирования Nestor. Допустимые значения: WriteToJournal (Отправка в сервис журналирования), WriteToTopic (Отправка события в очередь)
ATTILA_JOURNAL_TOPIC String Да, если переменная ATTILA_JOURNAL_MODE = WriteToTopic "" Название очереди журналирования. Для режима WriteToJournal значение игнорируется.

Список команд сервиса Attila

В описании команд используется путь/route для отправки команды в сам сервис, а не в ApiGateway. В качестве Input-а для команд, сервис всегда ожидает CommandRequest (как и любой другой сервис, принимающий команды), так что в описании команды указано лишь описание поля payload для CommandRequest.

Информация по добавлению команд можно прочитать в описании шаблона

Список реализованных в сервисе команд, моделей EntityType и действий Actions, которые можно использовать при настройке авторизации.

Название команды EntityType Actions
attila_GetResourceTypeFields - -
attila_AddResourceTypeFields - -
attila_RemoveResourceTypeFields - -
attila_AddAuthorizationInfo - -
attila_DeleteAuthorizationInfo - -
attila_ListCommandAuthorizationInfo AuthorizationInfo AuthorizationInfo_ViewCommands
attila_ListResourceTypeAuthorizationInfo AuthorizationInfo AuthorizationInfo_ViewResources
attila_ListRuleActionAuthorizationInfo AuthorizationInfo AuthorizationInfo_ViewRuleActions
attila_ListUIActionAuthorizationInfo AuthorizationInfo AuthorizationInfo_ViewUIActions
attila_UpdateHighLevelRule HighLevelRule HighLevelRule_Update
attila_DeleteHighLevelRule HighLevelRule HighLevelRule_Delete
attila_GetHighLevelRule HighLevelRule HighLevelRule_View
attila_ListHighLevelRules HighLevelRule HighLevelRule_ViewList

ListCommands (attila)

Payload для команды

{
  "query": "resource",
  "context": {
    "resource": "like %A"
  },
  "sorting": {
    "fieldName": "ruleAction",
    "order": "desc"
  },
  "paging": {
    "page": 1,
    "count": 3
  }
}

Результат выполнения команды

{
  "items": [
    "commandName_EoverA",
    "commandName_DoverA",
    "commandName_CoverA"
  ],
  "total": 5
}

Возвращает список названий команд, которые удовлетворяют заданным фильтрам.

Имя команды для вызова: attila_ListCommandAuthorizationInfo.
Поддерживается только синхронный вызов.
Результат выполнения команды не журналируется.

По умолчанию сортировка производится по полю commandName.

Запрос принимает параметры сортировки, фильтров и пейджинга в параметре Search.
Применяется к полям модели AuthorizationInfo.

Доступные поля для фильтрации и виды фильтров по ним:

Поле Виды фильтров
id InSetQuery, LikeQuery
commandname InSetQuery, LikeQuery
resource InSetQuery, LikeQuery
ruleaction InSetQuery, LikeQuery
uiaction InSetQuery, LikeQuery

Доступные поля для сортировки:

Поле
resource
ruleaction
uiaction
commandName

ListResources (attila)

Payload для команды

{
  "query": "resource",
  "context": {
    "resource": "like %A"
  },
  "sorting": {
    "fieldName": "ruleAction",
    "order": "desc"
  },
  "paging": {
    "page": 1,
    "count": 3
  }
}

Результат выполнения команды

{
  "items": [
    "resource_BA",
    "resource_A"
  ],
  "total": 2
}

Возвращает список названий ресурсов, которые удовлетворяют заданным фильтрам.

Имя команды для вызова: attila_ListResourceTypeAuthorizationInfo.
Поддерживается только синхронный вызов.
Результат выполнения команды не журналируется.

По умолчанию сортировка производится по полю commandName.

Запрос принимает параметры сортировки, фильтров и пейджинга в параметре Search.
Применяется к полям модели AuthorizationInfo.

Доступные поля для фильтрации и виды фильтров по ним:

Поле Виды фильтров
id InSetQuery, LikeQuery
commandname InSetQuery, LikeQuery
resource InSetQuery, LikeQuery
ruleaction InSetQuery, LikeQuery
uiaction InSetQuery, LikeQuery

Доступные поля для сортировки:

Поле
resource
ruleaction
uiaction
commandName

ListRuleActions (attila)

Payload для команды

{
  "query": "resource",
  "context": {
    "resource": "like %A"
  },
  "sorting": {
    "fieldName": "ruleAction",
    "order": "desc"
  },
  "paging": {
    "page": 1,
    "count": 3
  }
}

Результат выполнения команды

{
  "items": [
    "ruleAction_EoverA",
    "ruleAction_DoverA",
    "ruleAction_CoverA"
  ],
  "total": 5
}

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

Имя команды для вызова: attila_ListRuleActionAuthorizationInfo.
Поддерживается только синхронный вызов.
Результат выполнения команды не журналируется.

По умолчанию сортировка производится по полю commandName.

Запрос принимает параметры сортировки, фильтров и пейджинга в параметре Search.
Применяется к полям модели AuthorizationInfo.

Доступные поля для фильтрации и виды фильтров по ним:

Поле Виды фильтров
id InSetQuery, LikeQuery
commandname InSetQuery, LikeQuery
resource InSetQuery, LikeQuery
ruleaction InSetQuery, LikeQuery
uiaction InSetQuery, LikeQuery

Доступные поля для сортировки:

Поле
resource
ruleaction
uiaction
commandName

ListUIActions (attila)

Payload для команды

{
  "query": "resource",
  "context": {
    "resource": "like %A"
  },
  "sorting": {
    "fieldName": "ruleAction",
    "order": "desc"
  },
  "paging": {
    "page": 1,
    "count": 3
  }
}

Результат выполнения команды

{
  "items": [
    "uiAction_A"
  ],
  "total": 1
}

Возвращает список UI действий, которые удовлетворяют заданным фильтрам.

Имя команды для вызова: attila_ListUIActionAuthorizationInfo.
Поддерживается только синхронный вызов.
Результат выполнения команды не журналируется.

По умолчанию сортировка производится по полю commandName.

Запрос принимает параметры сортировки, фильтров и пейджинга в параметре Search.
Применяется к полям модели AuthorizationInfo.

Доступные поля для фильтрации и виды фильтров по ним:

Поле Виды фильтров
id InSetQuery, LikeQuery
commandname InSetQuery, LikeQuery
resource InSetQuery, LikeQuery
ruleaction InSetQuery, LikeQuery
uiaction InSetQuery, LikeQuery

Доступные поля для сортировки:

Поле
resource
ruleaction
uiaction
commandName

AddAuthorizationInfo (attila)

Payload для команды

[
  {
    "commandName": "Command_Executed_When_Viewing_Register",
    "dependencies": [
      [
        "resource_A",
        "view_register_of_a",
        [
          "SectionForA_View_Register"
        ]
      ],
      [
        "resource_A",
        "other_action_on_a",
        []
      ]
    ]
  },
  {
    "commandName": "Other_Command",
    "dependencies": [
      [
        "AttractiveResourceName",
        "Some_Action_On_AttractiveResource",
        []
      ]
    ]
  },
  {
    "commandName": "Command_With_Resource_A",
    "dependencies": [
      [
        "resource_A",
        "ruleAction_BoverA",
        [
          "uiAction_A"
        ]
      ]
    ]
  }
]

Результат выполнения команды

{
  "Other_Command": true,
  "Command_Executed_When_Viewing_Register": true,
  "Command_With_Resource_A": true
}

Возвращает список команд с результатом добавления соответствующей информации для авторизации.

Поддерживается асинхронный и синхронный вызов.
Результат выполнения команды не журналируется.

Команда только внутренняя (нельзя вызвать через Api Gateway), не требует аутентификации.

Команда Путь
attila_AddAuthorizationInfo kafka topic "attila_commands"

DeleteAuthorizationInfo (attila)

Payload для команды

[
  "Other_Command"
]

Результат выполнения команды

1

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

Поддерживается асинхронный и синхронный вызов.
Результат выполнения команды не журналируется.

Команда только внутренняя (нельзя вызвать через Api Gateway), не требует аутентификации.

Команда Путь
attila_DeleteAuthorizationInfo kafka topic "attila_commands"

GetHighLevelRule (attila)

Payload для команды

"Rule_AccessTo_ResourceA"

Результат выполнения команды

{
  "id": "Rule_AccessTo_ResourceA",
  "name": "Rule_AccessTo_ResourceA",
  "description": "Some very high rule",
  "action": "SectionForA_View_Register",
  "condition": "User.groupId == 'users' && A.authorId == User.id",
  "priority": 100,
  "effect": true
}

Возвращает по указаному идентификатору высокоуровневое правило, если оно существует. Иначе возвращает статус 404 Not Found.

Поддерживается только синхронный вызов.
Результат выполнения команды не журналируется.

Команда Путь
attila_GetHighLevelRule HTTP POST "/v1/rules/get"

ListHighLevelRules (attila)

Payload для команды

{
  "query": "resource",
  "context": {
    "resource": "like %A"
  },
  "sorting": {
    "fieldName": "priority",
    "order": "asc"
  },
  "paging": {
    "page": 12,
    "count": 1
  }
}

Результат выполнения команды

[
  {
    "id": "Rule_AccessTo_ResourceA",
    "name": "Rule_AccessTo_ResourceA",
    "description": "Some very high rule",
    "action": "SectionForA_View_Register",
    "condition": "User.groupId == 'users' && A.authorId == User.id",
    "priority": 100,
    "effect": true
  },
  {
    "id": "Rule_View_List_Of_Data",
    "name": "Rule_View_List_Of_Data",
    "description": "Another rule",
    "action": "A_ViewList",
    "condition": "User.groupId == 'users'",
    "priority": 20,
    "effect": true
  },
  {
    "id": "Rule_Action_Over_A",
    "name": "Rule_Action_Over_A",
    "description": "Just a high rule",
    "action": "VerySmartAction",
    "condition": "User.groupId == 'users' && A.authorId == User.id",
    "priority": 30,
    "effect": true
  }
]

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

Имя команды для вызова: attila_ListHighLevelRules.
Поддерживается только синхронный вызов.
Результат выполнения команды не журналируется.

По умолчанию сортировка производится по полю priority.

Запрос принимает параметры сортировки, фильтров в параметре Search.
Применяется к полям модели HighLevelRules.

Доступные поля для фильтрации и виды фильтров по ним:

Поле Виды фильтров
id InSetQuery, LikeQuery
description InSetQuery, LikeQuery
priority InSetQuery, RangeQuery
modified InSetQuery, RangeQuery
effect InSetQuery
action InSetQuery, LikeQuery

Доступные поля для сортировки:

Поле
id
name
description
effect
action
modified
priority

UpdateHighLevelRule (attila)

Payload для команды

{
  "id": "Rule_AccessTo_ResourceA",
  "name": "Rule_AccessTo_ResourceA",
  "previousId": "Rule_AccessTo_ResourceA",
  "description": "Some very high rule",
  "action": "SectionForA_View_Register",
  "condition": "User.groupId == 'users' && A.authorId == User.id",
  "priority": 100,
  "effect": true
}

Результат выполнения команды

true

Возвращает индикатор успеха добавления новой версии правила.

Поддерживается асинхронный и синхронный вызов.
Результат выполнения команды журналируется.

Команда Путь
attila_UpdateHighLevelRule kafka topic "attila_commands"

DeleteHighLevelRule (attila)

Payload для команды

"Rule_AccessTo_ResourceA"

Результат выполнения команды

true

Возвращает индикатор успеха удаления указанной версии правила.

Поддерживается асинхронный и синхронный вызов.
Результат выполнения команды журналируется.

Команда Путь
attila_DeleteHighLevelRule kafka topic "attila_commands"

GetResourceTypeFields (attila)

Payload для команды

{
  "query": "resourceType",
  "context": {
    "resource": "like %A"
  },
  "sorting": {
    "fieldName": "fieldName",
    "order": "asc"
  },
  "paging": {
    "page": 1,
    "count": 3
  }
}

Результат выполнения команды

{
  "Resource_A": {
    "field_1": "title_1",
    "field_2": "title_2"
  },
  "Resource_ABA": {
    "field_1": "title_123",
    "field_2": "title_2"
  }
}

Возвращает список полей, которые удовлетворяют заданным фильтрам.

Имя команды для вызова: attila_GetResourceTypeFields.
Поддерживается только синхронный вызов.
Результат выполнения команды не журналируется.

По умолчанию сортировка производится по полю resourceType.

Запрос принимает параметры сортировки, фильтров в параметре Search.
Применяется к полям модели ResourceTypeFields.

Доступные поля для фильтрации и виды фильтров по ним:

Поле Виды фильтров
resourcetype InSetQuery, LikeQuery
fieldname InSetQuery, LikeQuery
title InSetQuery, LikeQuery

Доступные поля для сортировки:

Поле
fieldname
title
resourceType

При сортировке не по полю "resourceType", resourceType будут сортироваться по мере появления (т.к. на беке список плоский, без вложенностей).
Например, при сортировке по "fieldName":
ABC(f1,t1), CBA(f23,t2), ABC(f30,t12), ZS(f2,t3), CBA(f0, t43), ABC(f3,t1) =>
CBA(f0, t43), ABC(f1,t1), ZS(f2,t3), ABC(f3,t1), CBA(f23,t2), ABC(f30,t12) =>
CBA((f0, t43), (f23,t2)), ABC((f1,t1), (f3,t1), (f30,t12)), ZS(f2,t3)

AddResourceTypeFields (attila)

Payload для команды

"Rule_AccessTo_ResourceA"

Результат выполнения команды

true

Добавление набора полей для определенного типа ресурсов.

Поддерживается асинхронный и синхронный вызов.
Результат выполнения команды не журналируется.

Команда только внутренняя (нельзя вызвать через Api Gateway), не требует аутентификации.

Команда Путь
attila_AddResourceTypeFields kafka topic "attila_commands"

RemoveResourceTypeFields (attila)

Payload для команды

"Rule_AccessTo_ResourceA"

Результат выполнения команды

true

Удаляет указанные поля из определенного типа ресурсов.

Поддерживается асинхронный и синхронный вызов.
Результат выполнения команды не журналируется.

Команда только внутренняя (нельзя вызвать через Api Gateway), не требует аутентификации.

Команда Путь
attila_RemoveResourceTypeFields kafka topic "attila_commands"

Модели сервиса Attila

CommandName

Наименование команды. Имеет тип String.

ResourceType

Наименование типа ресурса. Имеет тип String.

RuleAction

Наименование действия, которое используется в низкоуровневых правилах. Имеет тип String.

UIAction

Наименование UI действия, которое используется в высокоуровневых правилах. Имеет тип String.

FieldName

Наименование поля. Имеет тип String.

Title

Наименование чего-либо для отображения в интерфейсе. Имеет тип String.

CommandAuthorizationInfo

Информация для авторизации определенной команде.

Поле Описание
commandName Наименование команды. Имеет тип CommandName
dependencies Список констант, которые используются для авторизации команды. Константы образуют кортеж, обозначающее одно действие, которое необходимо авторизовать, где:
ResourceType - ресурс, к которому осуществляется доступ,
RuleAction - название действия для авторизации,
UIAction - названия UI действий, которыми выражается RuleAction в терминах пользовательского интерфейса.
Имеет тип List[(ResourceType, RuleAction, List[UIAction])]

HighLevelRuleId

Идентификатор высокоуровневого правила. Имеет тип String.

HighLevelRule

Описание версии высокоуровневого правила

Поле Описание Тип данных
id Идентификатор правила. HighLevelRuleId
name Название правила для отображения в интерфейсе. HighLevelRuleVersion
description Описание правила. String
action UI действие, для которого необходимо применять данное правило. UIAction
condition Условие применения правила. Поле опционально. Option[Condition]
priority Приоритет правила : чем больше значение, тем "дальше" в очереди на применение будет распологаться правило Int
effect Является ли правило "разрешающим". Boolean

HighLevelRuleUpdateDTO

Описание версии высокоуровневого правила

Поле Описание Тип данных
id Идентификатор правила. HighLevelRuleId
previousId Используемый раньше идентификатор правила. Для новых правил, может быть пустым или равным текущему ID. HighLevelRuleId
name Название правила для отображения в интерфейсе. HighLevelRuleVersion
description Описание правила. String
action UI действие, для которого необходимо применять данное правило. UIAction
condition Условие применения правила. Поле опционально. Option[Condition]
priority Приоритет правила : чем больше значение, тем "дальше" в очереди на применение будет распологаться правило Int
effect Является ли правило "разрешающим". Boolean

AuthorizationInfo

Информация для авторизации.

Поле Описание Тип данных
id Идентификатор. UUID
commandName Наименование команды. CommandName
resource Наименование типа ресурса. ResourceType
ruleAction Наименование действия. RuleAction
uiAction Наименование UI действия. UIAction

ResourceTypeFields

Набор полей для определенного типа ресурсов.

Поле Описание Тип данных
resourceType Наименование типа ресурса. ResourceType
fieldName Наименование поля. FieldName
title Наименование. Title

Attribute-provider: провайдер атрибутов для сервиса Oberto

Является расширением для Authzforce server (Community edition). В терминах XACML является PIP. Репозиторий Authzforce server: https://github.com/authzforce/server Wiki Authzforce server: https://github.com/authzforce/core/wiki/Attribute-Providers Спецификация XACML 3.0: http://docs.oasis-open.org/xacml/3.0/errata01/os/xacml-3.0-core-spec-errata01-os-complete.html

Расширение представляет собой jar файл с фабрикой для класса реализующего интерфейс CloseableNamedAttributeProvider ( предоставляется authzforce-ce-core-pdp-api):

Предоставляемые атрибуты

Атрибуты предоставляются для объектов сервиса DataModel, где AttributeId = <Название типа ресурса>.<Путь к полю Json-объекта в поле "data">.
Например, запрашиваеммый атрибут MyModel.firstField будет получен по пути MyModel.data.firstField. Значения всех атрибутов имеют тип String или List[String], в зависимости от структуры.

Атрибуты связанных объектов

Атрибуты связанных объектов указываются с использованием relation-поля:
<Название типа ресурса>.<Название relation-поля>.<Путь к полю Json-объекта в поле "data" связанного объекта>. Например,elibJournalArticle.links.journalId.

Тип отношения между объектами Тип значения атрибута Если в поле связанного объекта хранится список
one-to-one String List[String]
one-to-many List[String] List[List[String]].flatten преобразуется в List[String]
many-to-many List[String] List[List[String]].flatten преобразуется в List[String]

Список переменных окружения

Список переменных окружения для настройки AttributeProvider. Переменные для логов находятся в файле resources/logback.xml.

Переменная Описание Значение по-умолчанию
MAVEN_HOME Домашняя директория для MAVEN, где находится bin/mvn. Используется только во время сборки. "/usr/share/maven"
AUTHZFORCE_CONSUL_ADDR Адрес Consul. "http://localhost:8500"
AUTHZFORCE_CONSUL_AUTH_USER Адрес Consul. "http://localhost:8500"
AUTHZFORCE_CONSUL_AUTH_PASSWORD Адрес Consul. "http://localhost:8500"
AUTHZFORCE_KAFKA_ADDR Название топика для входящих/исходящих событий. "localhost:9092"
AUTHZFORCE_KAFKA_EVENTS_TOPIC Название топика для входящих/исходящих событий. "commandevents"
AUTHZFORCE_KAFKA_AUTH_USER Название учетной записи Kafka. Если название не указано, то настройки авторизации не будут применены. ""
AUTHZFORCE_KAFKA_AUTH_PASSWORD Пароль учетной записи Kafka. ""
AUTHZFORCE_KAFKA_AUTH_PRINCIPAL Principal учетной записи Kafka в Kerberos(в случае аутентификации в kafka через Kerberos). ""
AUTHZFORCE_KAFKA_AUTH_KEYTAB_PATH Путь до keytab-файла (в случае аутентификации в kafka через Kerberos). ""
AUTHZFORCE_KAFKA_AUTH_TRUSTSTORE_LOCATION Путь до хранилища сертификатов (Java key store). Если путь не указан, то сертификат применяться не будет. ""
AUTHZFORCE_KAFKA_AUTH_TRUSTSTORE_PASSWORD Пароль к хранилищу сертификатов. ""
AUTHZFORCE_KAFKA_AUTH_MODE Режим аутентификации: static - одна учетная запись на все запросы, mapping - учетная запись зависит от запроса. "static"
AUTHZFORCE_KAFKA_AUTH_CONFIG Настройки для аутентификации: если AuthMode = mapping, то необходим JSON с List[KafkaAuthConfig]. Переменная соответствует полю authConfig из KafkaAuthSettings.
AUTHZFORCE_KAFKA_AUTH_CACHE_SIZE Максимальный размер кеша для Kafka producer (количество активных соединений).
AUTHZFORCE_KAFKA_CONNECTION_CHECK_TEST_MESSAGES_INTERVAL Применяется только для producer-ов со способом аутентификации kerberos. Интервал отправки тестовых сообщений кафки в топик connectionCheck.testMessagesTopicName. Тестовые сообщения (null, service producer test) отправляются регулярно с этим интервалом. 4 minutes
AUTHZFORCE_KAFKA_CONNECTION_CHECK_INTERVAL Применяется только для producer-ов со способом аутентификации kerberos. Интервал проверки того, сколько тестовых сообщений было отправлено за данный период. Если количество сообщений за этот период равно количеству сообщений за прошлый период, то начинается отсчет периода без сообщений. 60 seconds
AUTHZFORCE_KAFKA_CONNECTION_CHECK_FAILED_AFTER_INTERVAL Применяется только для producer-ов со способом аутентификации kerberos. Максимальная продолжительность периода без успешно отправленных тестовых сообщений. По ее достижении сервис будет объявлен больным. 5 minutes
AUTHZFORCE_KAFKA_AUTH_CACHE_TTL Время жизни Kafka producer в кеше.
AUTHZFORCE_COMMANDS_PREFIX Префикс в Consul для ключей команд. "commands"
AUTHZFORCE_CACHE_LIFETIME Время жизни в кеше (актуальность) 1 результата выполнения команды. "20 minutes"
AUTHZFORCE_CACHE_SIZE Максимальное количество закешированных результатов команд. "10000"
AUTHZFORCE_CACHE_REQ_TIMEOUT Хост для HttpListener. "10 seconds"
LOG_LEVEL Общий уровень логов. "INFO"
LOG_OUTPUT Параметры вывода логов: STDOUT - обычный лог в консоль, STDOUT_CEF - лог в формате CEF в консоль, FILE - обычный лог в файл, FILE_CEF - лог в формате CEF в файл, SYSLOG - лог в SYSLOG, SYSLOG_CEF - лог в формате CEF в SYSLOG. "FILE"
LOGGING_SRC_IP Параметр SRC (источник/source, на который ссылается событие) для логов в формате CEF. Если не установлена, src=notFound. Требуемый формат: IPv4, например 192.168.10.1.
LOGGING_SRC_HOST Параметр SHOST (источник/source, на который ссылается событие) для логов в формате CEF. Если не установлена, shost=notFound. Требуемый формат: fully qualified domain name (FQDN), например host или host.domain.com.
LOGGING_DST_IP Параметр DST (получатель/destination, на который ссылается событие) для логов в формате CEF. Если не установлена, dst=notFound. Требуемый формат: IPv4, например 192.168.10.1.
LOGGING_CEF_VER Версия формата CEF: либо 0, либо 1. Рекомендуется использовать 0. 0
AUTHZFORCE_SENDERLIB_COMMANDS_HTTP_RETRY_ATTEMPTS Поле attempts из RetrySettings. 5
AUTHZFORCE_SENDERLIB_COMMANDS_HTTP_RETRY_DELAY Поле delay из RetrySettings. "5 seconds"
AUTHZFORCE_SENDERLIB_COMMANDS_HTTP_RETRY_KIND CommandResultRetryConditionKind "OnSomeExceptions(ConnectException)"

Формат CEF для authzfoce-provider

У логов есть возможность включить формат CEF для логирования по следующему шаблону:
2022-12-14T16:56:31+0500 CEF:Version|Device Vendor|Device Product|Device Version|EventClassId|Message|Severity|src=? dst=? shost=? suid=? suser=? msg=? end=currentTimeMillis|.

Чтобы включить логирование в формате CEF, нужно задать переменную LOG_OUTPUT = STDOUT_CEF. Если логи пишутся в формате CEF, то необходимо задать следующие переменные, которые по умолчанию не заданы:

В файле boot/src/main/resources/logback.xml можно поменять class path для основного класса приложения ( переменная projectMainClassPath), если это необходимо.

Maven

В проекте используется Maven, путь к которому должен быть указан в MAVEN_HOME. Для генерации AttributeValueProviderDescriptor по XML описанию использутся maven плагин org.jvnet.jaxb2.maven2 % maven-jaxb2-plugin, т.к. он умеет работать с jar в качестве источника XML схем.
Github репозиторий плагина: https://github.com/highsource/maven-jaxb2-plugin.
Конфигурация для плагин находится в файле pom.xml, которй также описывает maven проект. Плагин вызывается во время компиляции sbt проекта. За вызов плагина отвечает sbt task cachedFilesGeneration и класс MavenInvoker. Сгененрированные классы кешируются до следующего изменения файлов с конфигурацией для генерации.

Важно На данный момент attribute-provider собирается только под Java 11 и ниже.

Используемые классы

EntityObject (attribute-provider)

Описывает возвращаемый объект из сервиса dataModel

Поле Тип Обязательное Описание
id uuid да ID объекта
entityType string да Тип сущности объекта
source string да Источник данных для объекта
created TimeStamp да Дата и время создания объекта
data json object да Json с полями объекта
additionalData json object да Json с дополнительными полями объекта
version int да Версия объекта для оптимистичных блокировок

EntityObjectsRepository

Репозиторий с доступом к экземплярам EntityObject по идентификатору EntityObjectIdentity.
Содержит кеш для хранения объектов. При отсутсвии объекта в кеше, отправляет команду с запросом объекта в сервис dataModel.

FieldValuesExtractor

Вспомогательный объект для получения полей из json-а EntityObject

Алгоритм обновления jar в Authzforce server

Добавление конфига для AttributeValueProvider в необходимый домен:

Пример тела запроса на изменение конфигурации AttributeValueProvider

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
    <ns2:attributeProviders xmlns="urn:oasis:names:tc:xacml:3.0:core:schema:wd-17" xmlns:ns2="http://authzforce.github.io/rest-api-model/xmlns/authz/5" xmlns:ns3="http://www.w3.org/2005/Atom" xmlns:ns4="http://authzforce.github.io/core/xmlns/pdp/7" xmlns:ns5="http://authzforce.github.io/pap-dao-flat-file/xmlns/properties/3.6">
        <ns2:attributeProvider xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:ns7="http://embedika.com/verdi/generated" xsi:type="ns7:AttributeValueProviderDescriptor" id="valuesProvider">
        <Attributes Category="urn:oasis:names:tc:xacml:3.0:attribute-category:resource">
            <Attribute AttributeId="MyModel.firstField" IncludeInResult="false">
                <AttributeValue DataType="http://www.w3.org/2001/XMLSchema#string">StubValue</AttributeValue>
            </Attribute>
            <Attribute AttributeId="MyModel.testField" IncludeInResult="false">
                <AttributeValue DataType="http://www.w3.org/2001/XMLSchema#string">StubValue</AttributeValue>
            </Attribute>
            <Attribute AttributeId="MyModel.additionalField" IncludeInResult="false">
                <AttributeValue DataType="http://www.w3.org/2001/XMLSchema#string">StubValue</AttributeValue>
            </Attribute>
        </Attributes>
    </ns2:attributeProvider>
</ns2:attributeProviders>

Authzforce-client: клиент для Authzforce

Клиент для Authzforce-server предоставляет 3 интерфейса:

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

Authorizer (Authzforce)

Предоставляет API для авторизации. Авторизация происходит на основе "контекста авторизации", т.е. набора полей с заранее известными значениями и набором полей, значения которых вычисляются динамически. Результатом авторизации является решение (Boolean) и набор фильтров, которые необходимо применить к набору обрабатываемых данных.

PolicyUpdater (Authzforce)

Предоставляет API для изменения политик. Так как все политики должны быть включены в корневую политику (PolicySetId = root), почти все методы вносят изменения в корневую политику. Данное API не обеспечивает безопасный конкуретный доступ.

AttributeProviderApi (Authzforce)

Предоставляет API для изменения конфигурации AttributeProvider-ов. Конфигурация изменяется атомарно, но возможно "состояние гонки" при доступе к файлу настроек. Данное API не обеспечивает безопасный конкуретный доступ.

Buzzer-client: клиент для работы с сервисами buzzer.

Библиотека предоставляет интерфейсы и реализацию клиента для работы с сервисами buzzer.

Пример создания клиента.

Для того чтобы использовать библиотеку необходимо добавить зависимость "com.embedika.verdi" %% "buzzer-client" % verdiVersion.

Все классы находятся в пакете package com.embedika.buzzer.client.

Предоставлен следующий набор интерфейсов:

Все данные интерфейсы реализованы в одном классе LiveBuzzerClient.

Buzzer-core: библиотека для сервисов Buzzer

В библиотеку вынесен общий для сервисов уведомлений код.

Модели

Notification

Базовое представление уведомления

Название поля Тип Обязательное Описание
code string да Код уведомления, по сути идентификатор
userId uuid string да Идентификатор пользователя для которого уведомление предназначено
data object да Данные уведомления

MustacheTemplate

Шаблон уведомления

Название поля Тип Обязательное Описание
key string да Идентификатор шаблона
content string да Данные шаблона

Код для работы с шаблонизатором mustache

MustacheService

Сервис для контролирования эффектов загрузки mustache шаблонов. Библиотека mustache поддерживает импорты шаблонов, но по умолчанию импортируемый шаблон ищется в локальной файловой структуре. Сервис переопределяет это поведение и оборачивает всю логику в алгебру.

Buzzer-email: сервис уведомлений на электронную почту

Сервис получает через Kafka уведомления и отправляет их на электронную почту. Уведомления отправляются через рассылки по определенному расписанию. Каждая рассылка описывает шаблон отображения уведомления в письме. Уведомления могут группироваться в одном письме. Уведомления, рассылки и группы связываются через настройки.

Сервис предоставляет следующие команды:

Конфигурирование сервиса отправки уведомлений на электронную почту

Требования к запуску сервиса отправки уведомлений на электронную почту

Запуск сервиса осуществляется локально через sbt, на стенде в docker на jvm.

Для корректной минимальной работы сервиса требуется обязательное подключение к PostgreSQL, Kafka, Consul. Для настройки подключения к ним нужно заполнить обязательные переменные окружения из раздела ниже.

Для нормальной работы сервису дополнительно требуется окружение Verdi: CommandStatus и ApiGateway. В этом случае нужно уделить внимание настройкам, связанным с ServiceDiscovery и CommandDiscovery.

Список переменных окружения сервиса

Все доступные переменные окружения для настройки сервиса отправки уведомлений на электронную почту.

Переменная Тип Обяза-тельная Значение по умолчанию Описание
SERVER_PORT int да 8080 Порт, на котором слушает HTTP-сервер
CONSUMER_TOPIC string да "email" Название кафка-топика, куда отправляются запросы на выполнение команд.
CONSUMER_GROUP string да "email" Имя consumer-группы для чтения из CONSUMER_TOPIC. Не должна меняться и не должна быть пустой, иначе сервис будет перечитывать все входящие команды при перезапуске.
VERDI_HOST string да "localhost" Адрес, который будет зарегистрирован за данным экземпляром сервиса
VERDI_TTL duration string да 30 seconds Время, в течение которого экземпляр сервиса считается "активным". Таймер обновляется каждый раз, когда сервис присылает "health check"
VERDI_HEALTH_CHECK duration string да 10 seconds Периодичность отправки "health check"
VERDI_COMMAND_STORAGE_UPDATE_PERIOD duration string да 1 minute Время жизни статуса команд в кеше сервиса статусов (после получения последнего статуса из кафка).
VERDI_SERVICE_DISCOVERY_UPDATE_PERIOD duration string да 30 seconds Период проверки кеша со статусами команд для удаления статусов, время жизни которых превысило COMMAND_STATUS_SERVICE_STATUS_CACHE_TTL.
VERDI_ALLOW_INTERNAL_COMMANDS bool да true Период проверки Command discovery для очистки команд, привязанных к сервисам, которые не считаются "живыми".
VERDI_CONSIDER_ALL_COMMANDS_AS_INTERNAL boolean Нет false Флаг, определяющий будут ли все обращения в другие сервисы являться внутренними (т.е. не требовать авторизацию). Детальное описание механизма: Внутренние команды.
VERDI_KAFKA string да "localhost:9092" Адрес Kafka
VERDI_KAFKA_TOPIC string да "commandevents" Название кафка-топика, куда отправляются сообщения со статусами выполняемых команд.
VERDI_KAFKA_AUTH_USER string да "" Название учетной записи Kafka. Если название не указано, то настройки авторизации не будут применены.
VERDI_KAFKA_AUTH_PASSWORD string да "" Пароль учетной записи Kafka.
VERDI_KAFKA_AUTH_PRINCIPAL string нет "" Principal учетной записи Kafka в Kerberos(в случае соединения с kafka через Kerberos).
VERDI_KAFKA_AUTH_KEYTAB_PATH string нет "" Путь до keytab-файла (в случае соединения с kafka через Kerberos).
VERDI_KAFKA_AUTH_TRUSTSTORE_LOCATION string да "" Путь до хранилища сертификатов (Java key store). Если путь не указан, то сертификат применяться не будет.
VERDI_KAFKA_AUTH_TRUSTSTORE_PASSWORD string да "" Пароль к хранилищу сертификатов.
VERDI_KAFKA_AUTH_MODE string нет "static" Режим аутентификации: static - одна учетная запись на все запросы, mapping - учетная запись зависит от запроса
VERDI_KAFKA_AUTH_CONFIG string нет "" Настройки для аутентификации: если AuthMode = mapping, то необходим JSON с List[KafkaAuthConfig]. Переменная соответствует полю authConfig из KafkaAuthSettings.
VERDI_KAFKA_AUTH_CACHE_SIZE int нет Максимальный размер кеша для Kafka producer (количество активных соединений).
VERDI_KAFKA_CONNECTION_CHECK_TEST_MESSAGES_INTERVAL duration string нет 4 minutes Применяется только для producer-ов со способом аутентификации kerberos. Интервал отправки тестовых сообщений кафки в топик connectionCheck.testMessagesTopicName. Тестовые сообщения (null, service producer test) отправляются регулярно с этим интервалом.
VERDI_KAFKA_CONNECTION_CHECK_INTERVAL duration string нет 60 seconds Применяется только для producer-ов со способом аутентификации kerberos. Интервал проверки того, сколько тестовых сообщений было отправлено за данный период. Если количество сообщений за этот период равно количеству сообщений за прошлый период, то начинается отсчет периода без сообщений.
VERDI_KAFKA_CONNECTION_CHECK_FAILED_AFTER_INTERVAL duration string нет 5 minutes Применяется только для producer-ов со способом аутентификации kerberos. Максимальная продолжительность периода без успешно отправленных тестовых сообщений. По ее достижении сервис будет объявлен больным.
VERDI_KAFKA_AUTH_CACHE_TTL duration string нет Время жизни Kafka producer в кеше.
VERDI_CONSUL url string да "http://localhost:8500" Адрес Сonsul.
VERDI_CONSUL_AUTH_USER string да "" Название учетной записи Сonsul. Если название не указано, то настройки авторизации не будут применены.
VERDI_CONSUL_AUTH_PASSWORD string да "" Пароль учетной записи Сonsul.
VERDI_CONSUL_CONNECTION_MAX_RETRY int да 5 Максимальное количество попыток подключения к Consul после обрыва соединения
VERDI_CONSUL_CONNECTION_RETRY_DELAY duration string да 1 seconds Задержка перед попыткой подключения к Consul
DB_HOST string да Хост БД
DB_PORT int да Порт БД
DB_NAME string да Имя базы в БД
DB_JDBC_URL jdbc url string да JDBC-url для соединения с БД. По умолчанию собирается из других обязательных переменных. Можно указать только его, если не хочется отдельно указывать хост/порт/имя базы.
DB_USER string да Пользователь БД
DB_PASSWORD string да Пароль пользователя БД
DB_THREADS int нет 10 Количество потоков в пуле потоков для соединения с БД
DB_QUEUE_SIZE int нет 300 Размер очереди для действий базы данных, которые не могут быть выполнены немедленно, когда все потоки заняты. За пределами этого значения новые действия немедленно завершаются неудачей
DB_CONN_MAX int нет 10 Максимальное количество одновременных подключений к БД
DB_CONN_TIMEOUT duration string нет 20 second Максимальное время ожидания ответа для соединения к БД. Если это время превышено, а соединение не становится доступным, будет брошено исключение SQLException. 1000 мс — минимальное значение.
DB_ISOLATION string нет "READ_COMMITTED" Уровень изоляции транзакций для новых подключений. Допустимые значения: NONE, READ_COMMITTED, READ_UNCOMMITTED, REPEATABLE_READ, SERIALIZABLE.
DB_READONLY boolean нет false Read-only SQL транзакция может изменять только временные таблицы. Этот параметр управляет статусом «только для чтения» по умолчанию для каждой новой транзакции.
DB_CONN_MIN int нет = DB_THREADS Минимальное количество одновременных подключений к БД
DB_VALIDATION_TIMEOUT duration string нет 1 seconds Максимальное время, в течение которого соединение будет проверяться на работоспособность. 1000 мс — минимальное значение.
DB_IDLE_TIMEOUT duration string нет 10 minutes Максимальное время, в течение которого соединению разрешено простаивать в пуле. Значение 0 означает, что простаивающие соединения никогда не удаляются из пула.
DB_MAX_LIFETIME duration string нет 30 minutes Максимальное время жизни соединения в пуле. Когда простаивающее соединение достигает этого времени ожидания, даже если оно недавно использовалось, оно будет удалено из пула. Значение 0 указывает на отсутствие максимального срока службы.
DB_INITIALIZATION_FAIL_FAST string нет false Deprecated, начиная с версии Slick 3.3.0. Определяет, будет ли пул «быстро выходить из строя», если пул не может быть успешно заполнен начальными соединениями. Если соединения не могут быть созданы во время запуска пула, будет выдано исключение RuntimeException. Это свойство не имеет никакого эффекта, если minConnections равно 0.
DB_LEAK_DETECTION_THRESHOLD int нет 0 Время, в течение которого соединение может находиться вне пула, прежде чем будет зарегистрировано сообщение, указывающее на возможную утечку соединения. Значение 0 означает, что обнаружение утечек отключено. Наименьшее приемлемое значение для включения обнаружения утечек составляет 10 с.
DB_CONNECTION_TEST_QUERY string нет "SELECT 1" Выражение, которое будет выполнено непосредственно перед получением соединения из пула для проверки того, что соединение с базой данных все еще активно. Оно зависит от базы данных и должно представлять собой запрос, требующий минимальной обработки базой данных (например, «VALUES 1»). Если этот параметр не установлен, вместо него используется метод JDBC4 Connection.isValid().
DB_REGISTER_MBEANS boolean нет false Зарегистрированы ли JMX Management Beans («MBeans»)
DB_AUTO_COMMIT boolean нет true Это свойство определяет то, как будут вести себя по умолчанию возвращаемые соединения относительно autocommit-а.
DB_SCHEMA string нет "public" Устанавливает schema по умолчанию
DB_ISOLATE_INTERNAL_QUERIES boolean нет false Определяет то, изолируются ли с помощью транзакций внутренние запросы пула (например запрос connection alive test). Свойство применяется только если autoCommit выключен.
DB_INITIALIZATION_FAIL_TIMEOUT int нет 1 Работает, начиная с версии Slick 3.3.0. Определяет, будет ли пул «быстро выходить из строя», если пул не может быть успешно заполнен начальными соединениями. Любое положительное число считается числом миллисекунд для попытки получить начальное соединение;поток приложения будет заблокирован в течение этого периода. Если соединение не может быть получено до истечения этого времени, будет брошено исключение. Данный таймаут применяется после периода connectionTimeout. Если значение равно нулю (0),HikariCP попытается получить и проверить подключение. Если соединение получено, но проверка не пройдена, будет брошено исключение, и пул не будет запущен. Однако, если соединение не может быть получено, пул запустится, но последующие попытки получить соединение могут потерпеть неудачу. Значение меньше нуля пройдет любую первоначальную попытку подключения, и пул немедленно запустится, пытаясь получить соединения в фоновом режиме. Следовательно, последующие попытки получить соединение могут потерпеть неудачу.
VERDI_COMMANDS_HTTP_RETRY_ATTEMPTS int нет 5 Поле attempts из RetrySettings
VERDI_COMMANDS_HTTP_RETRY_DELAY duration string нет "5 seconds" Поле delay из RetrySettings
VERDI_COMMANDS_HTTP_RETRY_KIND string нет "OnSomeExceptions(ConnectException)" CommandResultRetryConditionKind
SENDING_FROM_EMAIL string нет "test@test.test" Отправитель, который будет указан во всех письмах
SMTP_PORT int нет 25 Порт SMTP-сервера, к которому будет обращаться SMTP-клиент
SMTP_HOST string нет "localhost" Хост SMTP-сервера, к которому будет обращаться SMTP-клиент
SENDING_MAX_ATTEMPTS string нет 5 Максимальное количество попыток отправки уведомления
DEBUG_MAIL string нет Почта для дебага. В случае не пустого значения все письма будут отправляться на нее
SMTP_USER string нет Логин для авторизации SMTP-клиента к SMTP-серверу
SMTP_PASSWORD string нет Пароль для авторизации SMTP-клиента к SMTP-серверу
SMTP_READ_TIMEOUT string нет 300 Время в секундах сколько SMTP-клиент готов ожидать от SMTP-сервера ответ
SMTP_WRITE_TIMEOUT string нет 300 Время в секундах сколько SMTP-клиент готов пытаться передать байты своего ответа SMTP-серверу
SMTP_INSECURE boolean нет false При значении true отключает проверку сертификатов SMTP-сервера
EMAIL_CACHE_TTL int нет 300 TTL кэша с соответствующими определенным userId email-ами в секундах

Список команд сервиса уведомлений на электронную почту

Заготовка для списка реализованных в сервисе команд, моделей EntityType и действий Actions, которые можно использовать при настройке авторизации.
На данный момент, ни в одной команде сервиса нет авторизации.

Название команды EntityType Actions
CreateSettingEmail Setting -
GetSettingEmail Setting -
DeleteSettingEmail Setting -
UpdateSettingEmail Setting -
ListSettingEmail Setting -
CreateGroupEmail Group -
GetGroupEmail Group -
DeleteGroupEmail Group -
UpdateGroupEmail Group -
ListGroupEmail Group -
CreateTemplateEmail Template -
GetTemplateEmail Template -
DeleteTemplateEmail Template -
UpdateTemplateEmail Template -
ListTemplateEmail Template -
CreateDeliveryEmail Delivery -
GetDeliveryEmail Delivery -
DeleteDeliveryEmail Delivery -
UpdateDeliveryEmail Delivery -
ListDeliveryEmail Delivery -
CreateDeliveryTemplate Delivery -
DeliveryTemplatesEmail Delivery -
ListNotificationErrors NotificationError -

CreateSettingEmail (Buzzer-Email)

Payload для команды

{
  "id": "testCode",
  "deliveryId": "testDelivery",
  "groupId": "testGroup",
  "version": 1
}

Результат выполнения команды

"testCode"

Создание настройки.

Поддерживается только синхронный вызов.
Результат выполнения команды не журналируется.

Команда Путь
CreateSettingEmail HTTP POST "/createSetting"

GetSettingEmail (Buzzer-Email)

Payload для команды

"testCode"

Результат выполнения команды

{
  "id": "testCode",
  "deliveryId": "testDelivery",
  "groupId": "testGroup",
  "version": 1
}

Получение настройки.

Поддерживается только синхронный вызов.
Результат выполнения команды не журналируется.

Команда Путь
GetSettingEmail HTTP POST "/getSetting"

DeleteSettingEmail (Buzzer-Email)

Payload для команды

"testCode"

Результат выполнения команды

1

Удаление настройки.

Поддерживается только синхронный вызов.
Результат выполнения команды не журналируется.

Команда Путь
DeleteSettingEmail HTTP POST "/deleteSetting"

UpdateSettingEmail (Buzzer-Email)

Payload для команды

{
  "id": "testCode",
  "deliveryId": "another-delivery",
  "groupId": "testGroup",
  "version": 2
}

Результат выполнения команды

1

Обновление настройки.

Поддерживается только синхронный вызов.
Результат выполнения команды не журналируется.

Команда Путь
UpdateSetting HTTP POST "/updateSetting"

ListSettingEmail (Buzzer-Email)

Payload для команды

null

Результат выполнения команды

[
  {
    "id": "testCode",
    "deliveryId": "another-delivery",
    "groupId": "testGroup",
    "version": 2
  }
]

Получение списка настроек.

Поддерживается только синхронный вызов.
Результат выполнения команды не журналируется.

Команда Путь
ListSettingEmail HTTP POST "/listSetting"

CreateGroupEmail (Buzzer-Email)

Payload для команды

{
  "id": "testGroup",
  "name": "test group",
  "version": 1
}

Результат выполнения команды

"testCode"

Создание группы.

Поддерживается только синхронный вызов.
Результат выполнения команды не журналируется.

Команда Путь
CreateGroupEmail HTTP POST "/createGroup"

GetGroupEmail (Buzzer-Email)

Payload для команды

"testCode"

Результат выполнения команды

{
  "id": "testGroup",
  "name": "test group",
  "version": 1
}

Получение группы.

Поддерживается только синхронный вызов.
Результат выполнения команды не журналируется.

Команда Путь
GetGroupEmail HTTP POST "/getGroup"

DeleteGroupEmail (Buzzer-Email)

Payload для команды

"testCode"

Результат выполнения команды

1

Удаление группы.

Поддерживается только синхронный вызов.
Результат выполнения команды не журналируется.

Команда Путь
DeleteGroupEmail HTTP POST "/deleteGroup"

UpdateGroupEmail (Buzzer-Email)

Payload для команды

{
  "id": "testGroup",
  "name": "test group for notification delivery",
  "version": 2
}

Результат выполнения команды

1

Обновление группы.

Поддерживается только синхронный вызов.
Результат выполнения команды не журналируется.

Команда Путь
UpdateGroupEmail HTTP POST "/updateGroup"

ListGroupEmail (Buzzer-Email)

Payload для команды

null

Результат выполнения команды

[
  {
    "id": "testGroup",
    "name": "test group for notification delivery",
    "version": 2
  }
]

Получение списка групп.

Поддерживается только синхронный вызов.
Результат выполнения команды не журналируется.

Команда Путь
ListGroupEmail HTTP POST "/listGroup"

CreateTemplateEmail (Buzzer-Email)

Payload для команды

{
  "id": "testTemplate",
  "title": "some title",
  "content": "<b>some content</b>: {{data}}",
  "version": 1
}

Результат выполнения команды

"testCode"

Создание шаблона.

Поддерживается только синхронный вызов.
Результат выполнения команды не журналируется.

Данные для вставки в шаблон находятся по пути groups.notifications.data.*

Команда Путь
CreateTemplateEmail HTTP POST "/createTemplate"

GetTemplateEmail (Buzzer-Email)

Payload для команды

"testCode"

Результат выполнения команды

{
  "id": "testTemplate",
  "title": "some title",
  "content": "<b>some content</b>: {{data}}",
  "version": 1
}

Получение шаблона.

Поддерживается только синхронный вызов.
Результат выполнения команды не журналируется.

Команда Путь
GetTemplateEmail HTTP POST "/getTemplate"

DeleteTemplateEmail (Buzzer-Email)

Payload для команды

"testCode"

Результат выполнения команды

1

Удаление шаблона.

Поддерживается только синхронный вызов.
Результат выполнения команды не журналируется.

Команда Путь
DeleteTemplateEmail HTTP POST "/deleteTemplate"

UpdateTemplateEmail (Buzzer-Email)

Payload для команды

{
  "id": "testTemplate",
  "title": "Object deletion",
  "content": "Объект {{data.title}} удален",
  "version": 2
}

Результат выполнения команды

1

Обновление шаблона.

Поддерживается только синхронный вызов.
Результат выполнения команды не журналируется.

Команда Путь
UpdateTemplateEmail HTTP POST "/updateTemplate"

ListTemplateEmail (Buzzer-Email)

Payload для команды

null

Результат выполнения команды

[
  {
    "id": "testTemplate",
    "title": "Object deletion",
    "content": "Объект {{data.title}} удален",
    "version": 2
  }
]

Получение списка шаблонов.

Поддерживается только синхронный вызов.
Результат выполнения команды не журналируется.

Команда Путь
ListTemplateEmail HTTP POST "/listTemplate"

CreateDeliveryEmail (Buzzer-Email)

Payload для команды

{
  "id": "testDelivery",
  "schedule": "0 12"
}

Результат выполнения команды

"testCode"

Создание рассылки.

Поддерживается только синхронный вызов.
Результат выполнения команды не журналируется.

Формат: {{minutes}} {{hours}}

Команда Путь
CreateDeliveryEmail HTTP POST "/createDelivery"

GetDeliveryEmail (Buzzer-Email)

Payload для команды

"testDelivery"

Результат выполнения команды

{
  "id": "testDelivery",
  "schedule": "15 *",
  "version": 1
}

Получение рассылки.

Поддерживается только синхронный вызов.
Результат выполнения команды не журналируется.

Команда Путь
GetDeliveryEmail HTTP POST "/getDelivery"

DeleteDeliveryEmail (Buzzer-Email)

Payload для команды

"testDelivery"

Результат выполнения команды

1

Удаление рассылки.

Поддерживается только синхронный вызов.
Результат выполнения команды не журналируется.

Команда Путь
DeleteDeliveryEmail HTTP POST "/deleteDelivery"

UpdateDeliveryEmail (Buzzer-Email)

Payload для команды

{
  "id": "testDelivery",
  "schedule": "0 *"
}

Результат выполнения команды

1

Обновление рассылки.

Поддерживается только синхронный вызов.
Результат выполнения команды не журналируется.

Команда Путь
UpdateDeliveryEmail HTTP POST "/updateDelivery"

ListDeliveryEmail (Buzzer-Email)

Payload для команды

null

Результат выполнения команды

[
  {
    "id": "testDelivery",
    "schedule": "0 14",
    "version": 2
  }
]

Получение списка рассылок.

Поддерживается только синхронный вызов.
Результат выполнения команды не журналируется.

Команда Путь
ListDeliveryEmail HTTP POST "/listDelivery"

ListNotificationErrors (Buzzer-email)

Payload для команды

{
  "sorting": {
    "fieldName": "created",
    "order": "asc"
  },
  "paging": {
    "page": 1,
    "count": 20
  },
  "query": "isRead",
  "context": {
    "isRead": "false"
  }
}

Результат выполнения команды

{
  "total": 1,
  "items": [
    {
      "id": "a133f0c8-a516-4537-8f3f-915acb335e2c",
      "errorMessage": "Test error message",
      "notificationId": "d95c6a34-9c06-4bd3-9c65-3e6323dc33a2",
      "created": "1671179029000",
      "stackTrace": null
    }
  ]
}

Список ошибок отправки уведомлений.

Поддерживается только синхронный вызов.
Результат выполнения команды не журналируется.

Команда Путь
ListNotificationErrors HTTP POST "/listNotificationErrors"

Доступные поля для фильтрации и виды фильтров по ним:

Поле Виды фильтров
created InSetQuery, LikeQuery, RangeQuery
errorMessage InSetQuery, LikeQuery
notificationId InSetQuery, LikeQuery
id InSetQuery

Доступные поля для сортировки:

Поле
created
errorMessage
notificationId
id

CreateDeliveryTemplate (buzzer-email)

Payload для команды

{
  "templateId": "testTemplate",
  "deliveryId": "testDelivery"
}

Результат выполнения команды

1

Связывание рассылки и шаблона.

Поддерживается только синхронный вызов.
Результат выполнения команды не журналируется.

Команда Путь
CreateDeliveryTemplate HTTP POST "/createDeliveryTemplate"

DeliveryTemplatesEmail (buzzer-email)

Payload для команды

"testDelivery"

Результат выполнения команды

[
  {
    "id": "testTemplate",
    "title": "Object deletion",
    "content": "Объект {{data.title}} удален",
    "version": 2
  }
]

Получения списка шаблонов привязанных к рассылке.

Поддерживается только синхронный вызов.
Результат выполнения команды не журналируется.

Команда Путь
DeliveryTemplatesEmail HTTP POST "/deliveryTemplates"

Модели сервиса отправки уведомлений на электронную почту

Delivery (Buzzer-email)

Рассылка

Поле Тип Обязательное Описание
id String Да Идентификатор рассылки
schedule String Да Расписание в виде строки для cron в формате {{minutes}} {{hours}}
version Long Да Версия рассылки, unix timestamp даты создания

CreateDelivery (Buzzer-email)

Запрос создания рассылки

Поле Тип Обязательное Описание
id String Да Идентификатор рассылки
schedule String Да Расписание в виде строки для cron в формате {{minutes}} {{hours}}
templateId String Да Идентификатор шаблона

DeliveryTemplate (Buzzer-email)

Связь рассылки и шаблона

Поле Тип Обязательное Описание
id UUID Да Идентификатор связи
deliveryId String Да Идентификатор рассылки
templateId String Да Идентификатор шаблона

DeliveryTemplateDTO (Buzzer-email)

Запрос создания связи рассылки и шаблона

Поле Тип Обязательное Описание
templateId String Да Идентификатор шаблона
deliveryId String Да Идентификатор рассылки

Template (Buzzer-email)

Шаблон отображения уведомления или группы уведомлений в письме

Поле Тип Обязательное Описание
id String Да Идентификатор
title String Да Заголовок
content String Да Шаблон рендеринга уведомлений в виде html разметки
version Int Нет Версия. Значение по умолчанию: 1

Group (Buzzer-email)

Группа уведомлений для отображения в письме

Поле Тип Обязательное Описание
id String Да Идентификатор
name String Да Название группы
version Int Нет Версия. Значение по умолчанию: 1

Setting (Buzzer-email)

Настройка рассылок и групп уведомлений

Поле Тип Обязательное Описание
id String Да Идентификатор, должен соответствовать коду уведомления
deliveryId String Да Идентификатор рассылки
groupId String Да Идентификатор группы
version Int Нет Версия. Значение по умолчанию: 1

StoredNotification (Buzzer-email)

Сохраняемые уведомления

Поле Тип Обязательное Описание
id UUID Да Идентификатор уведомления
code String Да Код уведомления
userId UUID Да Идентификатор пользователя
data Json Да Данные уведомления
email String Да Email пользователя
created LocalDateTime Да Дата сохранения. A date-time without a time-zone in the ISO-8601 calendar system, such as "2007-12-03T10:15:30"
isSend Boolean Да Отметка об успешной отправке
numberOfAttempts Int Да Количество попыток отправки

NotificationError (Buzzer-email)

Ошибки отправки уведомлений

Поле Тип Обязательное Описание
id UUID Да Идентификатор ошибки
notificationId UUID Да Идентификатор уведомления
errorMessage String Нет Сообщение об ошибке
stackTrace String Нет Дополнительная подробная информация об ошибке
created TimeStamp Да Дата сохранения (unix timestamp)

Envelop (Buzzer-email)

Промежуточная структура для представления письма

Поле Тип Обязательное Описание
to String Да Адресат письма
subject String Да Заголовок письма
content String Да Содержимое письма

Buzzer-personal-page: сервис уведомлений в личном кабинете

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

Сервис предоставляет следующие команды:

Список переменных окружения для сервиса Buzzer-personal-page

Все доступные переменные окружения для настройки сервиса уведомлений в личном кабинете.

Переменная Тип Обяза-тельная Значение по умолчанию Описание
SERVER_PORT int да 8080 Порт, на котором слушает HTTP-сервер
CONSUMER_TOPIC string да "personal-page" Название кафка-топика, куда отправляются запросы на выполнение команд.
CONSUMER_GROUP string да "personal-page" Имя consumer-группы для чтения из CONSUMER_TOPIC. Не должна меняться и не должна быть пустой, иначе сервис будет перечитывать все входящие команды при перезапуске.
CONSUMER_CHUNK_SIZE int да 8080 Максимальный размер "пачки сообщений", которые будут вычитываться из CONSUMER_TOPIC
CONSUMER_CHUNK_WITHIN duration string да 8080 Время в течении которого будет ожидаться "пачка сообщений" (максимальная длительность набора "пачки")
VERDI_HOST string да "localhost" Адрес который будет зарегистрирован за данным экземпляром сервиса
VERDI_TTL duration string да 30 seconds Время в течении которого экземпляр сервиса считается "активным". Таймер обновляется каждый раз, когда сервис присылает "health check"
VERDI_HEALTH_CHECK duration string да 10 seconds Периодичность отправки "health check"
VERDI_COMMAND_STORAGE_UPDATE_PERIOD duration string да 1 minute Время жизни статуса команд в кеше сервиса статусов (после получения последнего статуса из кафка).
VERDI_SERVICE_DISCOVERY_UPDATE_PERIOD duration string да 30 seconds Период проверки кеша со статусами команд для удаления статусов, время жизни которых превысило COMMAND_STATUS_SERVICE_STATUS_CACHE_TTL.
VERDI_ALLOW_INTERNAL_COMMANDS bool да true Период проверки Command discovery для очистки команд, привязанных к сервисам которые не считаются "живыми".
VERDI_CONSIDER_ALL_COMMANDS_AS_INTERNAL boolean Нет false Флаг, определяющий будут ли все обращения в другие сервисы являться внутренними (т.е. не требовать авторизацию). Детальное описание механизма: Внутренние команды.
VERDI_KAFKA string да "localhost:9092" Адрес Kafka
VERDI_KAFKA_TOPIC string да "commandevents" Название кафка-топика, куда отправляются сообщения со статусами выполняемых команд.
VERDI_KAFKA_AUTH_USER string да "" Название учетной записи Kafka. Если название не указано, то настройки авторизации не будут применены.
VERDI_KAFKA_AUTH_PASSWORD string да "" Пароль учетной записи Kafka.
VERDI_KAFKA_AUTH_PRINCIPAL string нет "" Principal учетной записи Kafka в Kerberos(в случае соединения с kafka через Kerberos).
VERDI_KAFKA_AUTH_KEYTAB_PATH string нет "" Путь до keytab-файла (в случае соединения с kafka через Kerberos).
VERDI_KAFKA_AUTH_TRUSTSTORE_LOCATION string да "" Путь до хранилища сертификатов (Java key store). Если путь не указан, то сертификат применяться не будет.
VERDI_KAFKA_AUTH_TRUSTSTORE_PASSWORD string да "" Пароль к хранилищу сертификатов.
VERDI_KAFKA_AUTH_MODE string нет "static" Режим аутентификации: static - одна учетная запись на все запросы, mapping - учетная запись зависит от запроса
VERDI_KAFKA_AUTH_CONFIG string нет "" Настройки для аутентификации: если AuthMode = mapping, то необходим JSON с List[KafkaAuthConfig]. Переменная соответствует полю authConfig из KafkaAuthSettings.
VERDI_KAFKA_AUTH_CACHE_SIZE int нет Максимальный размер кеша для Kafka producer (количество активных соединений).
VERDI_KAFKA_CONNECTION_CHECK_TEST_MESSAGES_INTERVAL duration string нет 4 minutes Применяется только для producer-ов со способом аутентификации kerberos. Интервал отправки тестовых сообщений кафки в топик connectionCheck.testMessagesTopicName. Тестовые сообщения (null, service producer test) отправляются регулярно с этим интервалом.
VERDI_KAFKA_CONNECTION_CHECK_INTERVAL duration string нет 60 seconds Применяется только для producer-ов со способом аутентификации kerberos. Интервал проверки того, сколько тестовых сообщений было отправлено за данный период. Если количество сообщений за этот период равно количеству сообщений за прошлый период, то начинается отсчет периода без сообщений.
VERDI_KAFKA_CONNECTION_CHECK_FAILED_AFTER_INTERVAL duration string нет 5 minutes Применяется только для producer-ов со способом аутентификации kerberos. Максимальная продолжительность периода без успешно отправленных тестовых сообщений. По ее достижении сервис будет объявлен больным.
VERDI_KAFKA_AUTH_CACHE_TTL duration string нет Время жизни Kafka producer в кеше.
VERDI_CONSUL url string да "http://localhost:8500" Адрес Сonsul.
VERDI_CONSUL_AUTH_USER string да "" Название учетной записи Сonsul. Если название не указано, то настройки авторизации не будут применены.
VERDI_CONSUL_AUTH_PASSWORD string да "" Пароль учетной записи Сonsul.
VERDI_CONSUL_CONNECTION_MAX_RETRY int да 5 Максимальное количество попыток подключения к Consul после обрыва соединения
VERDI_CONSUL_CONNECTION_RETRY_DELAY duration string да 1 seconds Задержка перед попыткой подключения к Consul
DB_HOST string да Хост БД
DB_PORT int да Порт БД
DB_NAME string да Имя базы в БД
DB_JDBC_URL jdbc url string да JDBC-url для соединения с БД. По умолчанию собирается из других обязательных переменных. Можно указать только его, если не хочется отдельно указывать хост/порт/имя базы.
DB_USER string да Пользователь БД
DB_PASSWORD string да Пароль пользователя БД
DB_THREADS int нет 10 Количество потоков в пуле потоков для соединения с БД
DB_QUEUE_SIZE int нет 300 Размер очереди для действий базы данных, которые не могут быть выполнены немедленно, когда все потоки заняты. За пределами этого значения новые действия немедленно завершаются неудачей
DB_CONN_MAX int нет 10 Максимальное количество одновременных подключений к БД
DB_CONN_TIMEOUT duration string нет 20 second Максимальное время ожидания ответа для соединения к БД. Если это время превышено, а соединение не становится доступным, будет брошено исключение SQLException. 1000 мс — минимальное значение.
DB_ISOLATION string нет "READ_COMMITTED" Уровень изоляции транзакций для новых подключений. Допустимые значения: NONE, READ_COMMITTED, READ_UNCOMMITTED, REPEATABLE_READ, SERIALIZABLE.
DB_READONLY boolean нет false Read-only SQL транзакция может изменять только временные таблицы. Этот параметр управляет статусом «только для чтения» по умолчанию для каждой новой транзакции.
DB_CONN_MIN int нет = DB_THREADS Минимальное количество одновременных подключений к БД
DB_VALIDATION_TIMEOUT duration string нет 1 seconds Максимальное время, в течение которого соединение будет проверяться на работоспособность. 1000 мс — минимальное значение.
DB_IDLE_TIMEOUT duration string нет 10 minutes Максимальное время, в течение которого соединению разрешено простаивать в пуле. Значение 0 означает, что простаивающие соединения никогда не удаляются из пула.
DB_MAX_LIFETIME duration string нет 30 minutes Максимальное время жизни соединения в пуле. Когда простаивающее соединение достигает этого времени ожидания, даже если оно недавно использовалось, оно будет удалено из пула. Значение 0 указывает на отсутствие максимального срока службы.
DB_INITIALIZATION_FAIL_FAST string нет false Deprecated, начиная с версии Slick 3.3.0. Определяет, будет ли пул «быстро выходить из строя», если пул не может быть успешно заполнен начальными соединениями. Если соединения не могут быть созданы во время запуска пула, будет выдано исключение RuntimeException. Это свойство не имеет никакого эффекта, если minConnections равно 0.
DB_LEAK_DETECTION_THRESHOLD int нет 0 Время, в течение которого соединение может находиться вне пула, прежде чем будет зарегистрировано сообщение, указывающее на возможную утечку соединения. Значение 0 означает, что обнаружение утечек отключено. Наименьшее приемлемое значение для включения обнаружения утечек составляет 10 с.
DB_CONNECTION_TEST_QUERY string нет "SELECT 1" Выражение, которое будет выполнено непосредственно перед получением соединения из пула для проверки того, что соединение с базой данных все еще активно. Оно зависит от базы данных и должно представлять собой запрос, требующий минимальной обработки базой данных (например, «VALUES 1»). Если этот параметр не установлен, вместо него используется метод JDBC4 Connection.isValid().
DB_AUTO_COMMIT boolean нет true Это свойство определяет то, как будут вести себя по умолчанию возвращаемые соединения относительно autocommit-а.
DB_SCHEMA string нет "public" Устанавливает schema по умолчанию
DB_ISOLATE_INTERNAL_QUERIES boolean нет false Определяет то, изолируются ли с помощью транзакций внутренние запросы пула (например запрос connection alive test). Свойство применяется только если autoCommit выключен.
DB_INITIALIZATION_FAIL_TIMEOUT int нет 1 Работает, начиная с версии Slick 3.3.0. Определяет, будет ли пул «быстро выходить из строя», если пул не может быть успешно заполнен начальными соединениями. Любое положительное число считается числом миллисекунд для попытки получить начальное соединение;поток приложения будет заблокирован в течение этого периода. Если соединение не может быть получено до истечения этого времени, будет брошено исключение. Данный таймаут применяется после периода connectionTimeout. Если значение равно нулю (0),HikariCP попытается получить и проверить подключение. Если соединение получено, но проверка не пройдена, будет брошено исключение, и пул не будет запущен. Однако, если соединение не может быть получено, пул запустится, но последующие попытки получить соединение могут потерпеть неудачу. Значение меньше нуля пройдет любую первоначальную попытку подключения, и пул немедленно запустится, пытаясь получить соединения в фоновом режиме. Следовательно, последующие попытки получить соединение могут потерпеть неудачу.
DB_REGISTER_MBEANS boolean нет false Зарегистрированы ли JMX Management Beans («MBeans»)
VERDI_COMMANDS_HTTP_RETRY_ATTEMPTS int нет 5 Поле attempts из RetrySettings
VERDI_COMMANDS_HTTP_RETRY_DELAY duration string нет "5 seconds" Поле delay из RetrySettings
VERDI_COMMANDS_HTTP_RETRY_KIND string нет "OnSomeExceptions(ConnectException)" CommandResultRetryConditionKind

Команды сервиса Buzzer-personal-page

searchPPNotifications (Buzzer-personal-page)

Payload для команды

{
  "search": {
    "sorting": {
      "fieldName": "created",
      "order": "asc"
    },
    "paging": {
      "page": 1,
      "count": 20
    },
    "query": "isRead",
    "context": {
      "isRead": "false"
    }
  }
}

Результат выполнения команды

{
  "total": 1,
  "items": [
    {
      "id": "a133f0c8-a516-4537-8f3f-915acb335e2c",
      "code": "testCode",
      "userId": "a133f0c8-a516-4537-8f3f-915acb335e2c",
      "data": {},
      "created": 1673942815499,
      "isRead": false,
      "render": null
    }
  ]
}

Поиск уведомлений в личном кабинете (ЛК). В качестве фильтра по пользователю, всегда используется текущий пользователь, который отправил запрос.
Если в Search-объекте был передан фильтр "userId", то он будет переписан на текущего пользователя.

Поддерживается только синхронный вызов.
Результат выполнения команды не журналируется.

Команда Путь
searchPPNotifications HTTP POST "/search"

Доступные поля для фильтрации и виды фильтров по ним:

Поле Виды фильтров
userId Всегда используется текущий пользователь
sectionId InSetQuery
isRead InSetQuery
id InSetQuery

Доступные поля для сортировки:

Поле
created
isRead

auditSearchPPNotifications (Buzzer-personal-page)

Payload для команды

{
  "search": {
    "sorting": {
      "fieldName": "created",
      "order": "asc"
    },
    "paging": {
      "page": 1,
      "count": 20
    },
    "query": "userId",
    "context": {
      "userId": {
        "kind": "any",
        "values": [
          "a133f0c8-a516-4537-8f3f-915acb335e2c",
          "aa1ceac9-a21c-4eba-9268-c62ce7fde9b3",
          "d1533243-10f1-40d8-bd88-ffe6cef735aa"
        ]
      }
    }
  }
}

Результат выполнения команды

{
  "total": 1,
  "items": [
    {
      "id": "a133f0c8-a516-4537-8f3f-915acb335e2c",
      "code": "testCode",
      "userId": "a133f0c8-a516-4537-8f3f-915acb335e2c",
      "data": {},
      "created": 1673942815499,
      "isRead": false,
      "render": null
    }
  ]
}

Поиск уведомлений в личном кабинете (ЛК), в котором можно указать любых пользователей в фильтре "userId".

Поддерживается только синхронный вызов.
Результат выполнения команды не журналируется.

Команда Путь
auditSearchPPNotifications HTTP POST "/auditSearch"

Доступные поля для фильтрации и виды фильтров по ним:

Поле Виды фильтров
userId InSetQuery
sectionId InSetQuery
isRead InSetQuery
id InSetQuery

Доступные поля для сортировки:

Поле
created
isRead

changeNotificationStatus (Buzzer-personal-page)

Payload для команды

{
  "ids": [
    "00000000-0000-0000-0000-000000000001",
    "00000000-0000-0000-0000-000000000002"
  ],
  "isRead": true,
  "allNotifications": false
}

Результат выполнения команды

true

Поиск уведомлений в личном кабинете (ЛК).

Поддерживается только синхронный вызов.
Результат выполнения команды не журналируется.

Команда Путь
changeNotificationStatus HTTP POST "/changeNotificationStatus"

createSectionPp (Buzzer-personal-page)

Payload для команды

{
  "id": "section1",
  "name": "section name",
  "version": 1
}

Результат выполнения команды

"section1"

Создание раздела.

Поддерживается только синхронный вызов.
Результат выполнения команды не журналируется.

Команда Путь
createSectionPp HTTP POST "/createSection"

getSectionPp (Buzzer-personal-page)

Payload для команды

"section1"

Результат выполнения команды

{
  "id": "section1",
  "name": "section name",
  "version": 1
}

Получение раздела.

Поддерживается только синхронный вызов.
Результат выполнения команды не журналируется.

Команда Путь
getSectionPp HTTP POST "/getSection"

deleteSectionPp (Buzzer-personal-page)

Payload для команды

"section1"

Результат выполнения команды

1

Удаление раздела.

Поддерживается только синхронный вызов.
Результат выполнения команды не журналируется.

Команда Путь
deleteSectionPp HTTP POST "/deleteSection"

updateSectionPp (Buzzer-personal-page)

Payload для команды

{
  "id": "section1",
  "name": "other section name",
  "version": 2
}

Результат выполнения команды

1

Обновление раздела.

Поддерживается только синхронный вызов.
Результат выполнения команды не журналируется.

Команда Путь
updateSectionPp HTTP POST "/updateSection"

listSectionPp (Buzzer-personal-page)

Payload для команды

null

Результат выполнения команды

[
  {
    "id": "section1",
    "name": "other section name",
    "version": 2
  }
]

Получение списка разделов.

Поддерживается только синхронный вызов.
Результат выполнения команды не журналируется.

Команда Путь
listSectionPp HTTP POST "/listSection"

createSettingPp (Buzzer-personal-page)

Payload для команды

{
  "id": "testCode",
  "sectionId": "section1",
  "version": 1
}

Результат выполнения команды

"testCode"

Создание настройки.

Поддерживается только синхронный вызов.
Результат выполнения команды не журналируется.

Команда Путь
createSettingPp HTTP POST "/createSetting"

getSettingPp (Buzzer-personal-page)

Payload для команды

"testCode"

Результат выполнения команды

{
  "id": "testCode",
  "sectionId": "section1",
  "version": 1
}

Получение настройки.

Поддерживается только синхронный вызов.
Результат выполнения команды не журналируется.

Команда Путь
getSettingPp HTTP POST "/getSetting"

deleteSettingPp (Buzzer-personal-page)

Payload для команды

"testCode"

Результат выполнения команды

1

Удаление настройки.

Поддерживается только синхронный вызов.
Результат выполнения команды не журналируется.

Команда Путь
deleteSetting HTTP POST "/deleteSetting"

updateSetting (Buzzer-personal-page)

Payload для команды

{
  "id": "testCode",
  "sectionId": "section2",
  "version": 2
}

Результат выполнения команды

1

Обновление настройки.

Поддерживается только синхронный вызов.
Результат выполнения команды не журналируется.

Команда Путь
updateSettingPp HTTP POST "/updateSetting"

listSettingPp (Buzzer-personal-page)

Payload для команды

null

Результат выполнения команды

[
  {
    "id": "testCode",
    "sectionId": "section2",
    "version": 2
  }
]

Получение списка настроек.

Поддерживается только синхронный вызов.
Результат выполнения команды не журналируется.

Команда Путь
listSettingPp HTTP POST "/listSetting"

createTemplatePp (Buzzer-personal-page)

Payload для команды

{
  "id": "template1",
  "settingId": "testCode",
  "title": "",
  "content": "",
  "version": 1
}

Результат выполнения команды

"template1"

Создание шаблона.

Поддерживается только синхронный вызов.
Результат выполнения команды не журналируется.

Команда Путь
createTemplatePp HTTP POST "/createTemplate"

getTemplatePp (Buzzer-personal-page)

Payload для команды

"template1"

Результат выполнения команды

{
  "id": "template1",
  "settingId": "testCode",
  "title": "",
  "content": "",
  "version": 1
}

Получение шаблона.

Поддерживается только синхронный вызов.
Результат выполнения команды не журналируется.

Команда Путь
getTemplatePp HTTP POST "/getTemplate"

deleteTemplatePp (Buzzer-personal-page)

Payload для команды

"template1"

Результат выполнения команды

1

Удаление шаблона.

Поддерживается только синхронный вызов.
Результат выполнения команды не журналируется.

Команда Путь
deleteTemplatePp HTTP POST "/deleteTemplate"

updateTemplatePp (Buzzer-personal-page)

Payload для команды

{
  "id": "template1",
  "settingId": "testCode",
  "title": "Template name",
  "content": "",
  "version": 1
}

Результат выполнения команды

1

Обновление шаблона.

Поддерживается только синхронный вызов.
Результат выполнения команды не журналируется.

Команда Путь
updateTemplatePp HTTP POST "/updateTemplate"

listTemplatePp (Buzzer-personal-page)

Payload для команды

null

Результат выполнения команды

[
  {
    "id": "template1",
    "settingId": "testCode",
    "title": "Template code",
    "content": "",
    "version": 1
  }
]

Получение списка шаблонов.

Поддерживается только синхронный вызов.
Результат выполнения команды не журналируется.

Команда Путь
listTemplatePp HTTP POST "/listTemplate"

Модели сервиса Buzzer-personal-page

NotificationPP (Buzzer-personal-page)

Уведомление личного кабинета

Поле Тип Обязательное Описание
id UUID Да Идентификатор уведомления
code String Да Код уведомления
userId UUID Да Идентификатор пользователя
data Json Да Данные уведомления
created TimeStamp Да Дата сохранения
isRead Boolean Да Отметка о прочтении
render String Нет Рендер уведомления

SearchRequest (Buzzer-personal-page)

Поисковый запрос

Поле Тип Обязательное Описание
search Search Да Параметры поиска
markRead Boolean Нет Нужно ли помечать уведомления как прочитанные
render Boolean Нет Нужно ли рендерить уведомления

ChangeNotificationsDTO (Buzzer-personal-page)

Данные для изменения статуса уведомлений

Поле Тип Обязательное Описание
ids List[UUID] Да Список идентификаторов уведомлений для изменения
isRead Boolean Да Новый статус уведомлений. True - "прочитано", False - "не прочитано"
allNotifications Boolean Да Применение изменений ко всем уведомлениям. True - "игнорирование списка ID", False - "изменить только переданные ID"

Section (Buzzer-personal-page)

Раздел личного кабинета

Поле Тип Обязательное Описание
id String Да Идентификатор
name String Да Название раздела
version Int Нет Версия. Значение по умолчанию: 1

Setting (Buzzer-personal-page)

Настройка раздела личного кабинета

Поле Тип Обязательное Описание
id String Да Идентификатор, должен соответствовать коду уведомления
sectionId String Да Идентификатор раздела
version Int Нет Версия. Значение по умолчанию: 1

StoredNotification (Buzzer-personal-page)

Сохраняемые уведомления

Поле Тип Обязательное Описание
id UUID Да Идентификатор
code String Да Код уведомления
userId UUID Да Идентификатор пользователя
data Json Да Данные уведомления
При рендере данных из data в случае когда поле
отсутствует или равно null оно отображается как пустая строка.
created TimeStamp Да Дата сохранения
isRead Boolean Да Отметка о прочтении

Template (Buzzer-personal-page)

Шаблон

Поле Тип Обязательное Описание
id String Да Идентификатор
settingId String Да Идентификатор настройки
title String Да Заголовок
content String Да Шаблон рендеринга уведомлений
version Int Нет Версия. Значение по умолчанию: 1

Buzzer-subscription: сервис подписок

Сервис подписок обеспечивает генерацию уведомлений при поступлении от бизнес-логики событий, приходящих через Kafka в топик businessevent. Также сервис принимает HTTP команды и хранит в PostgreSQL информацию о настройках подписки для событий и подписках пользователя.

Локальный запуск сервиса подписок

При запуске сервиса ожидается, что уже развернута необходимая инфраструктура:

Запуск сервиса подписок из консоли с помощью SBT

DB_HOST=localhost DB_PORT=5432 DB_NAME=buzzer-subscription DB_USER=$DB_USER DB_PASSWORD=$DB_PASSWORD sbt run

Список переменных окружения для сервиса Buzzer-subscription

Переменная Значение по умолчанию Описание
SERVER_PORT 8080 Порт для HttpListener
CONSUMER_TOPIC "entityObjectEvent" Название топика для чтения событий
CONSUMER_GROUP "notification" Название группы для чтения событий
SENDER_TOPIC "notification" Название топика для отправки уведомлений
VERDI_CONSUL "http://localhost:8500" Адрес Сonsul
VERDI_CONSUL_AUTH_USER "" Название учетной записи Сonsul. Если название не указано, то настройки авторизации не будут применены.
VERDI_CONSUL_AUTH_PASSWORD "" Пароль учетной записи Сonsul.
VERDI_KAFKA "localhost:9092" Адрес Kafka
VERDI_KAFKA_TOPIC "commandevents" Название топика для событий
VERDI_KAFKA_AUTH_USER "" Название учетной записи Kafka. Если название не указано, то настройки авторизации не будут применены.
VERDI_KAFKA_AUTH_PASSWORD "" Пароль учетной записи Kafka.
VERDI_KAFKA_AUTH_PRINCIPAL "" Principal учетной записи Kafka в Kerberos(в случае соединения с kafka через Kerberos).
VERDI_KAFKA_AUTH_KEYTAB_PATH "" Путь до keytab-файла (в случае соединения с kafka через Kerberos).
VERDI_KAFKA_AUTH_TRUSTSTORE_LOCATION "" Путь до хранилища сертификатов (Java key store). Если путь не указан, то сертификат применяться не будет.
VERDI_KAFKA_AUTH_TRUSTSTORE_PASSWORD "" Пароль к хранилищу сертификатов.
VERDI_KAFKA_AUTH_MODE "static" Режим аутентификации: static - одна учетная запись на все запросы, mapping - учетная запись зависит от запроса
VERDI_KAFKA_AUTH_CONFIG "" Настройки для аутентификации: если AuthMode = mapping, то необходим JSON с List[KafkaAuthConfig]. Переменная соответствует полю authConfig из KafkaAuthSettings.
VERDI_KAFKA_AUTH_CACHE_SIZE Максимальный размер кеша для Kafka producer (количество активных соединений).
VERDI_KAFKA_CONNECTION_CHECK_TEST_MESSAGES_INTERVAL 4 minutes Применяется только для producer-ов со способом аутентификации kerberos. Интервал отправки тестовых сообщений кафки в топик connectionCheck.testMessagesTopicName. Тестовые сообщения (null, service producer test) отправляются регулярно с этим интервалом.
VERDI_KAFKA_CONNECTION_CHECK_INTERVAL 60 seconds Применяется только для producer-ов со способом аутентификации kerberos. Интервал проверки того, сколько тестовых сообщений было отправлено за данный период. Если количество сообщений за этот период равно количеству сообщений за прошлый период, то начинается отсчет периода без сообщений.
VERDI_KAFKA_CONNECTION_CHECK_FAILED_AFTER_INTERVAL 5 minutes Применяется только для producer-ов со способом аутентификации kerberos. Максимальная продолжительность периода без успешно отправленных тестовых сообщений. По ее достижении сервис будет объявлен больным.
VERDI_KAFKA_AUTH_CACHE_TTL Время жизни Kafka producer в кеше.
VERDI_COMMAND_STORAGE_UPDATE_PERIOD 1 minutes Время кэширования данных по командам из CommandDiscovery
VERDI_SERVICE_DISCOVERY_UPDATE_PERIOD 30 seconds Время кэширования данных по сервисам из ServiceDiscovery
VERDI_ALLOW_INTERNAL_COMMANDS true Можно ли сервису отправлять внутрисистемные команды
VERDI_CONSIDER_ALL_COMMANDS_AS_INTERNAL false Флаг, определяющий будут ли все обращения в другие сервисы являться внутренними (т.е. не требовать авторизацию). Детальное описание механизма: Внутренние команды.
VERDI_CONSUL_CONNECTION_MAX_RETRY 5 Максимальное количество попыток подключений к Consul
VERDI_CONSUL_CONNECTION_RETRY_DELAY 1 seconds Таймаут между неудачными попытками подключения к Consul
VERDI_HOST "localhost" Адрес текущего инстанса сервиса, который будет виден через ServiceDiscovery
DB_JDBC_URL "jdbc:postgresql://localhost:5432/buzzer-subscription" Адрес базы данных. Можно использовать вместо DB_HOST, DB_PORT и DB_NAME
DB_HOST Хост сервера базы данных
DB_PORT Порт сервера базы данных
DB_NAME Название базы данных
DB_USER Пользователь базы данных
DB_PASSWORD Пароль для пользователя базы данных
DB_THREADS 10 Количество потоков в пуле потоков для соединения с БД
DB_QUEUE_SIZE 300 Размер очереди для действий базы данных, которые не могут быть выполнены немедленно, когда все потоки заняты. За пределами этого значения новые действия немедленно завершаются неудачей
DB_CONN_MAX 10 Максимальное количество одновременных подключений к БД
DB_CONN_TIMEOUT 20 second Максимальное время ожидания ответа для соединения к БД. Если это время превышено, а соединение не становится доступным, будет брошено исключение SQLException. 1000 мс — минимальное значение.
DB_ISOLATION "READ_COMMITTED" Уровень изоляции транзакций для новых подключений. Допустимые значения: NONE, READ_COMMITTED, READ_UNCOMMITTED, REPEATABLE_READ, SERIALIZABLE.
DB_READONLY false Read-only SQL транзакция может изменять только временные таблицы. Этот параметр управляет статусом «только для чтения» по умолчанию для каждой новой транзакции.
DB_CONN_MIN = DB_THREADS Минимальное количество одновременных подключений к БД
DB_VALIDATION_TIMEOUT 1 seconds Максимальное время, в течение которого соединение будет проверяться на работоспособность. 1000 мс — минимальное значение.
DB_IDLE_TIMEOUT 10 minutes Максимальное время, в течение которого соединению разрешено простаивать в пуле. Значение 0 означает, что простаивающие соединения никогда не удаляются из пула.
DB_MAX_LIFETIME 30 minutes Максимальное время жизни соединения в пуле. Когда простаивающее соединение достигает этого времени ожидания, даже если оно недавно использовалось, оно будет удалено из пула. Значение 0 указывает на отсутствие максимального срока службы.
DB_INITIALIZATION_FAIL_FAST false Deprecated, начиная с версии Slick 3.3.0. Определяет, будет ли пул «быстро выходить из строя», если пул не может быть успешно заполнен начальными соединениями. Если соединения не могут быть созданы во время запуска пула, будет выдано исключение RuntimeException. Это свойство не имеет никакого эффекта, если minConnections равно 0.
DB_LEAK_DETECTION_THRESHOLD 0 Время, в течение которого соединение может находиться вне пула, прежде чем будет зарегистрировано сообщение, указывающее на возможную утечку соединения. Значение 0 означает, что обнаружение утечек отключено. Наименьшее приемлемое значение для включения обнаружения утечек составляет 10 с.
DB_CONNECTION_TEST_QUERY "SELECT 1" Выражение, которое будет выполнено непосредственно перед получением соединения из пула для проверки того, что соединение с базой данных все еще активно. Оно зависит от базы данных и должно представлять собой запрос, требующий минимальной обработки базой данных (например, «VALUES 1»). Если этот параметр не установлен, вместо него используется метод JDBC4 Connection.isValid().
DB_AUTO_COMMIT boolean Это свойство определяет то, как будут вести себя по умолчанию возвращаемые соединения относительно autocommit-а.
DB_SCHEMA string Устанавливает schema по умолчанию
DB_ISOLATE_INTERNAL_QUERIES boolean Определяет то, изолируются ли с помощью транзакций внутренние запросы пула (например запрос connection alive test). Свойство применяется только если autoCommit выключен.
DB_INITIALIZATION_FAIL_TIMEOUT int Работает, начиная с версии Slick 3.3.0. Определяет, будет ли пул «быстро выходить из строя», если пул не может быть успешно заполнен начальными соединениями. Любое положительное число считается числом миллисекунд для попытки получить начальное соединение;поток приложения будет заблокирован в течение этого периода. Если соединение не может быть получено до истечения этого времени, будет брошено исключение. Данный таймаут применяется после периода connectionTimeout. Если значение равно нулю (0),HikariCP попытается получить и проверить подключение. Если соединение получено, но проверка не пройдена, будет брошено исключение, и пул не будет запущен. Однако, если соединение не может быть получено, пул запустится, но последующие попытки получить соединение могут потерпеть неудачу. Значение меньше нуля пройдет любую первоначальную попытку подключения, и пул немедленно запустится, пытаясь получить соединения в фоновом режиме. Следовательно, последующие попытки получить соединение могут потерпеть неудачу.
DB_REGISTER_MBEANS false Зарегистрированы ли JMX Management Beans («MBeans»)
VERDI_COMMANDS_HTTP_RETRY_ATTEMPTS 5 Поле attempts из RetrySettings
VERDI_COMMANDS_HTTP_RETRY_DELAY "5 seconds" Поле delay из RetrySettings
VERDI_COMMANDS_HTTP_RETRY_KIND "OnSomeExceptions(ConnectException)" CommandResultRetryConditionKind
CHUNK_SIZE 512 Размер батчей, которыми происходит обработка стримов userId подписанных на событие пользователей
GROUP_CACHE_TTL 300 Количество секунд, которое маппинг группы (groupId) к ее участниками (userId) хранится в кэше
SERVER_AUTHORIZER_KIND "authzforce" Вид авторизатора, который используется в сервисе. Допустимые значения: "authzforce", "oberto". При указании неизвестного значения будет использовано значение по-умолчанию.
AUTHZFORCE_ADDR "http://localhost:8080/authzforce-ce" Адрес AuthZforce server
AUTHZFORCE_DOMAIN "" Доступный DomainID в AuthZforce server
AUTHZFORCE_CONNECT_TIMEOUT "5 seconds" Таймаут подключения к authzforce
JOURNAL_MODE string нет
JOURNAL_TOPIC string да, если переменная JOURNAL_MODE = WriteToTopic

Команды сервиса Buzzer-subscription

В качестве тела команд сервис всегда ожидает CommandRequest. В описании команд указано описание поля payload для CommandRequest и путь для отправки команды в сам сервис (не в ApiGateway).

В сервисе реализованы следующие команды:

Список реализованных в сервисе команд, моделей EntityType и действий Actions, которые можно использовать при настройке авторизации.
Не все поля EntityType доступны для использования в настройке авторизации.
Если указан прочерк "-", то данное значение не влияет на авторизацию:

Название команды EntityType Actions
createEventSettingsBuzzer-subscription - -
getEventSettingsBuzzer-subscription - -
updateEventSettingsBuzzer-subscription - -
deleteEventSettingsBuzzer-subscription - -
listEventSettingsBuzzer-subscription - -
searchEventSettingsBuzzer-subscription - -
createGroupSubscriptionBuzzer-subscription GroupSubscription createGroupSubscription
listGroupSubscriptionBuzzer-subscription GroupSubscription listGroupSubscription
deleteGroupSubscriptionBuzzer-subscription GroupSubscription deleteGroupSubscription
updateGroupSubscriptionBuzzer-subscription GroupSubscription updateGroupSubscription
getGroupSubscriptionBuzzer-subscription GroupSubscription getGroupSubscription
createSubscriptionBuzzer-subscription - -
getSubscriptionBuzzer-subscription - -
updateSubscriptionBuzzer-subscription - -
deleteSubscriptionBuzzer-subscription - -

CreateEventSettings (Buzzer-subscription)

Передаем JSON с данными для создания настроек события

{
  "entityType": "Document",
  "eventType": "Create",
  "enabled": true,
  "notificationCode": "DocumentCreated"
}

Получаем Id настроек события

"4345011c-c579-4e1b-b84b-94e4eed2f2da"

Создать настройки события из данных EventSettingsDTO. Гарантируется уникальность для набора полей: entityType, eventType.

В ответ приходит Id настроек события.

Поддерживается только синхронный вызов.
Результат выполнения команды не журналируется.

Команда Путь
createEventSettingsBuzzer-subscription HTTP POST "/createEventSettings"

GetEventSettings (Buzzer-subscription)

Передаем Id настроек события

"ed2de80e-0289-43c2-a944-70e9a4277d36"

Получаем JSON с настройками события

{
  "id": "ed2de80e-0289-43c2-a944-70e9a4277d36",
  "entityType": "Employee",
  "eventType": "Create",
  "enabled": true,
  "notificationCode": "EmployeeCreated",
  "version": 1
}

Возвращает настройки события EventSettings по Id.

Поддерживается только синхронный вызов.
Результат выполнения команды не журналируется.

Команда Путь
getEventSettingsBuzzer-subscription HTTP POST "/getEventSettings"

UpdateEventSettings (Buzzer-subscription)

Передаем JSON с настройками события

{
  "id": "0b27209a-1931-4cd7-a19a-7739bd1dfb4f",
  "entityType": "DocumentFile",
  "eventType": "Delete",
  "enabled": true,
  "notificationCode": "DocumentFileDeleted",
  "version": 1
}

Получаем результат

1

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

Поддерживается только синхронный вызов.
Результат выполнения команды не журналируется.

Команда Путь
updateEventSettingsBuzzer-subscription HTTP POST "/updateEventSettings"

DeleteEventSettings (Buzzer-subscription)

Передаем Id настроек события

"0ccd05ac-50c0-4e7e-906b-6893eaa8d9de"

Получаем результат

1

Удалить существующие настройки события по Id.

Поддерживается только синхронный вызов.
Результат выполнения команды не журналируется.

Команда Путь
deleteEventSettingsBuzzer-subscription HTTP POST "/deleteEventSettings"

ListEventSettings (Buzzer-subscription)

Получаем JSON со списком всех существующих настроек событий

[
  {
    "id": "f3287c8e-efa5-45d9-ba38-76ef78f09fe0",
    "entityType": "Document",
    "eventType": "Delete",
    "enabled": true,
    "notificationCode": "DocumentDeleted",
    "version": 1
  },
  {
    "id": "34c919ae-a73c-4705-8833-0a1b0434e04c",
    "entityType": "Employee",
    "eventType": "Update",
    "enabled": false,
    "notificationCode": "EmployeeUpdated",
    "version": 2
  }
]

Возвращает список всех существующих настроек событий.

Поддерживается только синхронный вызов.
Результат выполнения команды не журналируется.

Команда Путь
listEventSettingsBuzzer-subscription HTTP POST "/listEventSettings"

SearchEventSettings (Buzzer-subscription)

Передаем поисковой запрос

{
  "query": "eventType",
  "context": {
    "eventType": "Delete"
  },
  "sorting": {
    "fieldName": "eventType",
    "order": "Asc"
  },
  "paging": {
    "page": 2,
    "count": 10
  }
}

Получаем JSON со списком отфильтрованных настроек событий

{
  "items": [
    {
      "id": "f3287c8e-efa5-45d9-ba38-76ef78f09fe0",
      "entityType": "Document",
      "eventType": "Delete",
      "enabled": true,
      "notificationCode": "DocumentDeleted",
      "version": 1
    },
    {
      "id": "34c919ae-a73c-4705-8833-0a1b0434e04c",
      "entityType": "Employee",
      "eventType": "Update",
      "enabled": false,
      "notificationCode": "EmployeeUpdated",
      "version": 2
    }
  ],
  "total": 12
}

Возвращает отфильтрованный список настроек событий.

Доступные для сортировки поля:

Доступные для фильтрации поля и виды фильтров по ним:

Поле Виды фильтров
id InSetQuery
eventType InSetQuery, LikeQuery
notificationCode InSetQuery, LikeQuery
entityType InSetQuery, LikeQuery

Поддерживается только синхронный вызов.
Результат выполнения команды не журналируется.

Команда Путь
searchEventSettingsBuzzer-subscription HTTP POST "/searchEventSettings"

CreateGroupSubscription (Buzzer-subscription)

Передаем JSON с данными для создания подписки

{
  "entityType": "Document",
  "entityId": "fd460be0-99f6-4cfc-95eb-2e3f6a847ef5",
  "eventType": "Create",
  "enabled": true,
  "groupId": "someGroupId"
}

Получаем Id подписки

"d053e6c2-877e-4dc4-83c6-d7f80911e1f1"

Создать подписку для всех userId из группы с указанным groupId из данных GroupSubscriptionDTO. Гарантируется уникальность для набора полей: entityType, entityId, eventType, groupId. Поле eventType опциональное, в случае его отсутствия подписка будет генерировать уведомления на все типы событий.

В ответ приходит Id подписки.

Поддерживается только синхронный вызов.
Результат выполнения команды журналируется.

Команда Путь
createGroupSubscriptionBuzzer-subscription HTTP POST "/createGroupSubscription"

GetGroupSubscription (Buzzer-subscription)

Передаем UUID с id подписки

Получаем JSON с данными для о подписке

{
  "id": "ed3fa199-5576-4e83-b54c-15cfd116aaaf",
  "entityType": "Document",
  "entityId": "fd460be0-99f6-4cfc-95eb-2e3f6a847ef5",
  "eventType": "Create",
  "enabled": true,
  "groupId": "someGroupId",
  "version": 2
}

Получить подписку с указанным id в формате GroupSubscription.

Поддерживается только синхронный вызов.
Результат выполнения команды не журналируется.

Команда Путь
getGroupSubscriptionBuzzer-subscription HTTP POST "/getGroupSubscription"

UpdateGroupSubscription (Buzzer-subscription)

Передаем JSON с данными для создания подписки

{
  "id": "ed3fa199-5576-4e83-b54c-15cfd116aaaf",
  "entityType": "Document",
  "entityId": "fd460be0-99f6-4cfc-95eb-2e3f6a847ef5",
  "eventType": "Create",
  "enabled": true,
  "groupId": "someGroupId",
  "version": 2
}

Обновить подписку для всех userId из группы с указанным groupId из данных GroupSubscription. Гарантируется уникальность для набора полей: entityType, entityId, eventType, groupId. Поле eventType опциональное, в случае его отсутствия подписка будет генерировать уведомления на все типы событий.

Поддерживается только синхронный вызов.
Результат выполнения команды журналируется.

Команда Путь
updateGroupSubscriptionBuzzer-subscription HTTP POST "/updateGroupSubscription"

DeleteGroupSubscription (Buzzer-subscription)

Передаем id групповой подписки

"d053e6c2-877e-4dc4-83c6-d7f80911e1f1"

Удалить групповую подписку с указанным id.

Поддерживается только синхронный вызов.
Результат выполнения команды журналируется.

Команда Путь
deleteGroupSubscriptionBuzzer-subscription HTTP POST "/deleteGroupSubscription"

ListGroupSubscription (Buzzer-subscription)

Получаем JSON со списком всех существующих групповых подписок

[
  {
    "id": "8eca9dc3-f64c-4169-ac00-94e35f7a77c5",
    "entityType": "File",
    "entityId": "4de27416-e20d-4883-889c-207527eb724e",
    "eventType": "Delete",
    "enabled": true,
    "groupId": "groupId",
    "version": 1
  }
]

Возвращает список всех существующих настроек групповых событий.

Поддерживается только синхронный вызов.
Результат выполнения команды не журналируется.

Команда Путь
listGroupSubscriptionBuzzer-subscription HTTP POST "/listGroupSubscription"

CreateSubscription (Buzzer-subscription)

Передаем JSON с данными для создания подписки

{
  "entityType": "Document",
  "entityId": "fd460be0-99f6-4cfc-95eb-2e3f6a847ef5",
  "eventType": "Create",
  "enabled": true,
  "userId": "fd460be0-99f6-4cfc-95eb-2e3f6a847efb"
}

Получаем Id подписки

"d053e6c2-877e-4dc4-83c6-d7f80911e1f1"

Создать подписки из данных SubscriptionDTO. Гарантируется уникальность для набора полей: entityType, entityId, eventType, userId. Поле eventType опциональное, в случае его отсутствия подписка будет генерировать уведомления на все типы событий.

В ответ приходит Id подписки.

Поддерживается только синхронный вызов.
Результат выполнения команды не журналируется.

Команда Путь
createSubscriptionBuzzer-subscription HTTP POST "/createSubscription"

GetSubscription (Buzzer-subscription)

Передаем Id подписки

"d053e6c2-877e-4dc4-83c6-d7f80911e1f1"

Получаем JSON с подпиской

{
  "id": "d053e6c2-877e-4dc4-83c6-d7f80911e1f1",
  "entityType": "Document",
  "entityId": "fd460be0-99f6-4cfc-95eb-2e3f6a847ef5",
  "eventType": "Create",
  "enabled": true,
  "userId": "fd460be0-99f6-4cfc-95eb-2e3f6a847efa",
  "version": 1
}

Возвращает подписку Subscription по Id.

Поддерживается только синхронный вызов.
Результат выполнения команды не журналируется.

Команда Путь
getSubscriptionBuzzer-subscription HTTP POST "/getSubscription"

UpdateSubscription (Buzzer-subscription)

Передаем JSON с подпиской

{
  "id": "69c33893-b769-4292-8259-3295fe0d7450",
  "entityType": "DocumentFile",
  "entityId": "a7833b48-aeb6-4048-99fd-e90bf1780b7e",
  "eventType": "Create",
  "enabled": true,
  "userId": "fd460be0-99f6-4cfc-95eb-2e3f6a847efe",
  "version": 1
}

Получаем результат

1

Обновить существующую подписку из Subscription. Если значение, передаваемое в version, отличается от текущего, обновление не происходит. При успешном обновлении version формы увеличивается на единицу.

Поддерживается только синхронный вызов.
Результат выполнения команды не журналируется.

Команда Путь
updateSubscriptionBuzzer-subscription HTTP POST "/updateSubscription"

DeleteSubscription (Buzzer-subscription)

Передаем Id подписки

"954855b6-5390-45ca-9280-2746563e6905"

Получаем результат

1

Удалить существующую подписку по Id.

Поддерживается только синхронный вызов.
Результат выполнения команды не журналируется.

Команда Путь
deleteSubscriptionBuzzer-subscription HTTP POST "/deleteSubscription"

ListSubscription (Buzzer-subscription)

Получаем JSON со списком всех существующих подписок

[
  {
    "id": "69c33893-b769-4292-8259-3295fe0d7450",
    "entityType": "Document",
    "entityId": "53cc3dec-29c3-4814-a2e7-69f435f74a1f",
    "eventType": "Update",
    "enabled": true,
    "userId": "fd460be0-99f6-4cfc-95eb-2e3f6a847efe",
    "version": 2
  },
  {
    "id": "018815b5-6fa3-4b8c-8bec-374bb3c20574",
    "entityType": "Organization",
    "entityId": "1bce425e-f1ae-4729-a36f-8a16dd6afa58",
    "enabled": false,
    "userId": "018815b5-6fa3-4b8c-8bec-374bb3c20574",
    "version": 1
  }
]

Возвращает список всех существующих настроек событий.

Поддерживается только синхронный вызов.
Результат выполнения команды не журналируется.

Команда Путь
listSubscriptionBuzzer-subscription HTTP POST "/listSubscription"

Модели сервиса подписок

EventSettingsDTO (Buzzer-subscription)

Поле Тип Обязательное Описание
entityType String да Тип сущности
eventType String да Тип события
enabled Boolean да Активность подписки
notificationCode String да Код уведомления

EventSettings (Buzzer-subscription)

Поле Тип Обязательное Описание
id UUID да Id настроек события
entityType String да Тип сущности
eventType String да Тип события
enabled Boolean да Активность подписки
notificationCode String да Код уведомления
version Int да Версия настроек события

SubscriptionDTO (Buzzer-subscription)

Поле Тип Обязательное Описание
entityType String да Тип сущности
entityId String да Id сущности
eventType String нет Тип события
enabled Boolean да Активность подписки
userId UUID да Id пользователя

GroupSubscriptionDTO (Buzzer-subscription)

Поле Тип Обязательное Описание
entityType String да Тип сущности
entityId String да Id сущности
eventType String нет Тип события
enabled Boolean да Активность подписки
groupId String да Id группы пользователей

Subscription (Buzzer-subscription)

Поле Тип Обязательное Описание
id UUID да Id подписки
entityType String да Тип сущности
entityId String да Id сущности
eventType String нет Тип события
enabled Boolean да Активность подписки
userId UUID да Id пользователя
version Int да Версия настроек события

GroupSubscription (Buzzer-subscription)

Поле Тип Обязательное Описание
id UUID да Id подписки
entityType String да Тип сущности
entityId String да Id сущности
eventType String нет Тип события
enabled Boolean да Активность подписки
groupId String да Id группы пользователей
version Int да Версия настроек события

Buzzer: сервис уведомлений

Сервис получает через Kafka уведомления и перенаправляет их в сервисы отправки. На данный момент реализованы 2 таких сервиса - Buzzer email и Buzzer personal page.

Конфигурирование сервиса уведомлений

Требования к запуску

Для корректной минимальной работы сервиса требуется обязательное подключение к PostgreSQL, Kafka, Consul. Для настройки подключения к ним нужно заполнить обязательные переменные окружения из раздела ниже.

Для нормальной работы сервису дополнительно требуется окружение Verdi: CommandStatus и ApiGateway. В этом случае нужно уделить внимание настройкам, связанным с ServiceDiscovery и CommandDiscovery.

Список переменных окружения сервиса уведомлений

Переменная Значение по умолчанию Описание
SERVER_PORT 8080 Порт для HttpListener
CONSUMER_TOPIC "notification" Название топика для уведомлений к отправке, поступающих из других сервисов
CONSUMER_SEND_NOTIFICATION_COMMAND_TOPIC "send_notification_command" Название топика для Verdi-команды отправки уведомления
CONSUMER_GROUP "notification" Название группы для чтения из топиков Kafka
PASSWORD_RECOVERY_TOPIC "email" Kafka topic используемый для отправки писем с восстановлением пароля.
При старте приложения этим значением обновляется поле topic сущности sending с id='password-recovery' если оно отличается.
EMAIL_CONFIRM_TOPIC "email" Аналогично PASSWORD_RECOVERY_TOPIC, но для верификации электронной почты
VERDI_HOST "localhost" Адрес текущего инстанса сервиса, который будет виден через ServiceDiscovery
VERDI_TTL 30 seconds Период после последней отправки health check, в течение которого ServiceDiscovery считает данный сервис живым.
VERDI_HEALTH_CHECK 10 seconds Периодичность отправки health check в ServiceDiscovery
VERDI_CONSUL http://localhost:8500 Адрес Consul
VERDI_CONSUL_AUTH_USER "" Название учетной записи Сonsul. Если название не указано, то настройки авторизации не будут применены.
VERDI_CONSUL_AUTH_PASSWORD "" Пароль учетной записи Сonsul.
VERDI_KAFKA "localhost:9092" Адрес брокера Kafka.
VERDI_KAFKA_TOPIC "commandevents" Название топика для событий
VERDI_KAFKA_AUTH_USER "" Название учетной записи Kafka. Если название не указано, то настройки авторизации не будут применены.
VERDI_KAFKA_AUTH_PASSWORD "" Пароль учетной записи Kafka.
VERDI_KAFKA_AUTH_PRINCIPAL "" Principal учетной записи Kafka в Kerberos(в случае соединения с kafka через Kerberos).
VERDI_KAFKA_AUTH_KEYTAB_PATH "" Путь до keytab-файла (в случае соединения с kafka через Kerberos).
VERDI_KAFKA_AUTH_TRUSTSTORE_LOCATION "" Путь до хранилища сертификатов (Java key store). Если путь не указан, то сертификат применяться не будет.
VERDI_KAFKA_AUTH_TRUSTSTORE_PASSWORD "" Пароль к хранилищу сертификатов.
VERDI_KAFKA_AUTH_MODE "static" Режим аутентификации: static - одна учетная запись на все запросы, mapping - учетная запись зависит от запроса
VERDI_KAFKA_AUTH_CONFIG "" Настройки для аутентификации: если AuthMode = mapping, то необходим JSON с List[KafkaAuthConfig]. Переменная соответствует полю authConfig из KafkaAuthSettings.
VERDI_KAFKA_AUTH_CACHE_SIZE Максимальный размер кеша для Kafka producer (количество активных соединений).
VERDI_KAFKA_CONNECTION_CHECK_TEST_MESSAGES_INTERVAL 4 minutes Применяется только для producer-ов со способом аутентификации kerberos. Интервал отправки тестовых сообщений кафки в топик connectionCheck.testMessagesTopicName. Тестовые сообщения (null, service producer test) отправляются регулярно с этим интервалом.
VERDI_KAFKA_CONNECTION_CHECK_INTERVAL 60 seconds Применяется только для producer-ов со способом аутентификации kerberos. Интервал проверки того, сколько тестовых сообщений было отправлено за данный период. Если количество сообщений за этот период равно количеству сообщений за прошлый период, то начинается отсчет периода без сообщений.
VERDI_KAFKA_CONNECTION_CHECK_FAILED_AFTER_INTERVAL 5 minutes Применяется только для producer-ов со способом аутентификации kerberos. Максимальная продолжительность периода без успешно отправленных тестовых сообщений. По ее достижении сервис будет объявлен больным.
VERDI_KAFKA_AUTH_CACHE_TTL Время жизни Kafka producer в кеше.
VERDI_COMMAND_STORAGE_UPDATE_PERIOD 1 minutes Время кэширования данных по командам из CommandDiscovery
VERDI_SERVICE_DISCOVERY_UPDATE_PERIOD 30 seconds Время кэширования данных по сервисам из ServiceDiscovery
VERDI_ALLOW_INTERNAL_COMMANDS true Можно ли сервису отправлять внутрисистемные команды
VERDI_CONSIDER_ALL_COMMANDS_AS_INTERNAL false Флаг, определяющий будут ли все обращения в другие сервисы являться внутренними (т.е. не требовать авторизацию). Детальное описание механизма: Внутренние команды.
VERDI_CONSUL_CONNECTION_MAX_RETRY 5 Максимальное количество попыток подключений к Consul
VERDI_CONSUL_CONNECTION_RETRY_DELAY 1 seconds Таймаут между неудачными попытками подключения к Consul
DB_JDBC_URL Адрес базы данных. Можно использовать вместо DB_HOST, DB_PORT и DB_NAME
DB_HOST Хост сервера базы данных
DB_PORT Порт сервера базы данных
DB_NAME Название базы данных
DB_USER Пользователь базы данных
DB_PASSWORD Пароль для пользователя базы данных
DB_THREADS 10 Количество потоков в пуле потоков для соединения с БД
DB_QUEUE_SIZE 300 Размер очереди для действий базы данных, которые не могут быть выполнены немедленно, когда все потоки заняты. За пределами этого значения новые действия немедленно завершаются неудачей
DB_CONN_MAX 10 Максимальное количество одновременных подключений к БД
DB_CONN_TIMEOUT 20 second Максимальное время ожидания ответа для соединения к БД. Если это время превышено, а соединение не становится доступным, будет брошено исключение SQLException. 1000 мс — минимальное значение.
DB_ISOLATION "READ_COMMITTED" Уровень изоляции транзакций для новых подключений. Допустимые значения: NONE, READ_COMMITTED, READ_UNCOMMITTED, REPEATABLE_READ, SERIALIZABLE.
DB_READONLY false Read-only SQL транзакция может изменять только временные таблицы. Этот параметр управляет статусом «только для чтения» по умолчанию для каждой новой транзакции.
DB_CONN_MIN = DB_THREADS Минимальное количество одновременных подключений к БД
DB_VALIDATION_TIMEOUT 1 seconds Максимальное время, в течение которого соединение будет проверяться на работоспособность. 1000 мс — минимальное значение.
DB_IDLE_TIMEOUT 10 minutes Максимальное время, в течение которого соединению разрешено простаивать в пуле. Значение 0 означает, что простаивающие соединения никогда не удаляются из пула.
DB_MAX_LIFETIME 30 minutes Максимальное время жизни соединения в пуле. Когда простаивающее соединение достигает этого времени ожидания, даже если оно недавно использовалось, оно будет удалено из пула. Значение 0 указывает на отсутствие максимального срока службы.
DB_INITIALIZATION_FAIL_FAST false Deprecated, начиная с версии Slick 3.3.0. Определяет, будет ли пул «быстро выходить из строя», если пул не может быть успешно заполнен начальными соединениями. Если соединения не могут быть созданы во время запуска пула, будет выдано исключение RuntimeException. Это свойство не имеет никакого эффекта, если minConnections равно 0.
DB_LEAK_DETECTION_THRESHOLD 0 Время, в течение которого соединение может находиться вне пула, прежде чем будет зарегистрировано сообщение, указывающее на возможную утечку соединения. Значение 0 означает, что обнаружение утечек отключено. Наименьшее приемлемое значение для включения обнаружения утечек составляет 10 с.
DB_CONNECTION_TEST_QUERY "SELECT 1" Выражение, которое будет выполнено непосредственно перед получением соединения из пула для проверки того, что соединение с базой данных все еще активно. Оно зависит от базы данных и должно представлять собой запрос, требующий минимальной обработки базой данных (например, «VALUES 1»). Если этот параметр не установлен, вместо него используется метод JDBC4 Connection.isValid().
DB_AUTO_COMMIT boolean Это свойство определяет то, как будут вести себя по умолчанию возвращаемые соединения относительно autocommit-а.
DB_SCHEMA string Устанавливает schema по умолчанию
DB_ISOLATE_INTERNAL_QUERIES boolean Определяет то, изолируются ли с помощью транзакций внутренние запросы пула (например запрос connection alive test). Свойство применяется только если autoCommit выключен.
DB_INITIALIZATION_FAIL_TIMEOUT int Работает, начиная с версии Slick 3.3.0. Определяет, будет ли пул «быстро выходить из строя», если пул не может быть успешно заполнен начальными соединениями. Любое положительное число считается числом миллисекунд для попытки получить начальное соединение;поток приложения будет заблокирован в течение этого периода. Если соединение не может быть получено до истечения этого времени, будет брошено исключение. Данный таймаут применяется после периода connectionTimeout. Если значение равно нулю (0),HikariCP попытается получить и проверить подключение. Если соединение получено, но проверка не пройдена, будет брошено исключение, и пул не будет запущен. Однако, если соединение не может быть получено, пул запустится, но последующие попытки получить соединение могут потерпеть неудачу. Значение меньше нуля пройдет любую первоначальную попытку подключения, и пул немедленно запустится, пытаясь получить соединения в фоновом режиме. Следовательно, последующие попытки получить соединение могут потерпеть неудачу.
DB_REGISTER_MBEANS false Зарегистрированы ли JMX Management Beans («MBeans»)
VERDI_COMMANDS_HTTP_RETRY_ATTEMPTS 5 Поле attempts из RetrySettings
VERDI_COMMANDS_HTTP_RETRY_DELAY "5 seconds" Поле delay из RetrySettings
VERDI_COMMANDS_HTTP_RETRY_KIND "OnSomeExceptions(ConnectException)" CommandResultRetryConditionKind

Список команд сервиса уведомлений

В сервисе реализованы следующие команды:

CreateSendingBuzzer

Передаем JSON с описанием сервиса отправки

{
  "id": "profile",
  "topic": "personal-page",
  "version": 1
}

Получаем код сервиса

"profile"

Зарегистрировать сервис отправки.

Имя вызова команды: createSendingBuzzer.
Поддерживается только синхронный вызов.
Результат выполнения команды не журналируется.

GetSendingBuzzer

Передаем код сервиса отправки

"profile"

Получаем JSON с описанием сервиса отправки

{
  "id": "profile",
  "topic": "personal-page",
  "version": 1
}

Получить описание сервиса отправки.

Имя вызова команды: getSendingBuzzer.
Поддерживается только синхронный вызов.
Результат выполнения команды не журналируется.

ListSendingBuzzer

Получаем JSON со списком всех существующих сервисов отправки

[
  {
    "id": "profile",
    "topic": "personal-page",
    "version": 1
  },
  {
    "id": "email",
    "topic": "email",
    "version": 1
  }
]

Возвращает список всех зарегистрированных сервисов отправки

Имя вызова команды: listSendingBuzzer.
Поддерживается только синхронный вызов.
Результат выполнения команды не журналируется.

UpdateSendingBuzzer

Передаем JSON с описанием сервиса отправки

{
  "id": "profile",
  "topic": "personal-page",
  "version": 1
}

Получаем результат

1

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

Имя вызова команды: updateSendingBuzzer.
Поддерживается только синхронный вызов.
Результат выполнения команды не журналируется.

DeleteSendingBuzzer

Передаем код сервиса отправки

"email"

Получаем результат

1

Отменить регистрацию сервиса отправки.

Имя вызова команды: deleteSendingBuzzer.
Поддерживается только синхронный вызов.
Результат выполнения команды не журналируется.

CreateSettingBuzzer

Передаем JSON с данными для создания пользовательских настроек уведомления

{
  "code": "buzzerNotification",
  "sendingIds": [
    "profile"
  ]
}

Получаем ID новой настройки

"4345011c-c579-4e1b-b84b-94e4eed2f2da"

Создать пользовательские настройки уведомления.

Имя вызова команды: createSettingBuzzer.
Поддерживается только синхронный вызов.
Результат выполнения команды не журналируется.

GetSettingBuzzer

Передаем ID настроек

"ed2de80e-0289-43c2-a944-70e9a4277d36"

Получаем JSON с настройками уведомления

{
  "id": "e3901923-21dc-4f95-98d0-cb2ea29abe1e",
  "code": "buzzerNotification",
  "sendingIds": [
    "profile",
    "email"
  ],
  "userId": "016d04f4-fc1a-4629-808b-e5e1c35bb348",
  "version": 1
}

Получить настройки уведомления.

Имя вызова команды: getSettingBuzzer.
Поддерживается только синхронный вызов.
Результат выполнения команды не журналируется.

ListSettingBuzzer

Получаем JSON со списком всех пользовательских настроек уведомлений

[
  {
    "id": "e3901923-21dc-4f95-98d0-cb2ea29abe1e",
    "code": "buzzerNotification",
    "sendingIds": [
      "profile",
      "email"
    ],
    "userId": "016d04f4-fc1a-4629-808b-e5e1c35bb348",
    "version": 1
  }
]

Возвращает список всех существующих пользовательских настроек уведомлений.

Имя вызова команды: listSettingBuzzer.
Поддерживается только синхронный вызов.
Результат выполнения команды не журналируется.

SearchSettingBuzzer

Передаем поисковой запрос

{
  "query": "sendingid",
  "context": {
    "sendingid": "profile"
  },
  "sorting": {
    "fieldName": "code",
    "order": "Asc"
  },
  "paging": {
    "page": 1,
    "count": 10
  }
}

Получаем JSON со списком отфильтрованных пользовательских настроек уведомлений

{
  "items": [
    {
      "id": "e3901923-21dc-4f95-98d0-cb2ea29abe1e",
      "code": "buzzerNotification",
      "sendingIds": [
        "profile",
        "email"
      ],
      "userId": "016d04f4-fc1a-4629-808b-e5e1c35bb348",
      "version": 2
    },
    {
      "id": "ec44f7d8-4e8b-4259-8c86-2cd9b2472451",
      "code": "buzzerNotification2",
      "sendingIds": [
        "profile"
      ],
      "userId": "016d04f4-fc1a-4629-808b-e5e1c35bb348",
      "version": 1
    }
  ],
  "total": 2
}

Возвращает отфильтрованный список пользовательских настроек уведомлений. Доступные для фильтрации поля и виды фильтров по ним:

Поле Виды фильтров
id InSetQuery
code InSetQuery, LikeQuery
sendingid InSetQuery

Доступные для сортировки поля:

Имя вызова команды: searchSettingBuzzer.
Поддерживается только синхронный вызов.
Результат выполнения команды не журналируется.

UpdateSettingBuzzer

Передаем JSON с пользовательскими настройками уведомления

{
  "id": "e3901923-21dc-4f95-98d0-cb2ea29abe1e",
  "code": "buzzerNotification",
  "sendingIds": [
    "profile",
    "email"
  ],
  "version": 1
}

Получаем результат

1

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

Имя вызова команды: updateSettingBuzzer.
Поддерживается только синхронный вызов.
Результат выполнения команды не журналируется.

DeleteSettingBuzzer

Передаем ID пользовательских настроек уведомления

"0ccd05ac-50c0-4e7e-906b-6893eaa8d9de"

Получаем результат

1

Удалить существующие пользовательские настройки события по их ID.

Имя вызова команды: deleteSettingBuzzer.
Поддерживается только синхронный вызов.
Результат выполнения команды не журналируется.

CreateSystemSettingBuzzer

Передаем JSON с данными для создания системных настроек

{
  "code": "buzzerNotification",
  "sendingIds": [
    "profile",
    "email"
  ]
}

Получаем ID новой системной настройки

"4345011c-c579-4e1b-b84b-94e4eed2f2da"

Создать системные настройки уведомления.

Имя вызова команды: createSystemSettingBuzzer.
Поддерживается только синхронный вызов.
Результат выполнения команды не журналируется.

GetSystemSettingBuzzer

Передаем ID системных настроек

"ed2de80e-0289-43c2-a944-70e9a4277d36"

Получаем JSON с системными настройками уведомления

{
  "id": "e3901923-21dc-4f95-98d0-cb2ea29abe1e",
  "code": "buzzerNotification",
  "sendingIds": [
    "profile",
    "email"
  ],
  "userId": null,
  "version": 1
}

Получить системные настройки уведомления.

Имя вызова команды: getSystemSettingBuzzer.
Поддерживается только синхронный вызов.
Результат выполнения команды не журналируется.

ListSystemSettingBuzzer

Получаем JSON со списком всех системных настроек уведомлений

[
  {
    "id": "e3901923-21dc-4f95-98d0-cb2ea29abe1e",
    "code": "buzzerNotification",
    "sendingIds": [
      "profile",
      "email"
    ],
    "userId": null,
    "version": 1
  }
]

Возвращает список всех существующих системных настроек уведомлений.

Имя вызова команды: listSystemSettingBuzzer.
Поддерживается только синхронный вызов.
Результат выполнения команды не журналируется.

SearchSystemSettingBuzzer

Передаем поисковой запрос

{
  "query": "sendingid",
  "context": {
    "sendingid": "profile"
  },
  "sorting": {
    "fieldName": "code",
    "order": "Asc"
  },
  "paging": {
    "page": 1,
    "count": 10
  }
}

Получаем JSON со списком отфильтрованных системных настроек уведомлений

{
  "items": [
    {
      "id": "e3901923-21dc-4f95-98d0-cb2ea29abe1e",
      "code": "buzzerNotification",
      "sendingIds": [
        "profile",
        "email"
      ],
      "userId": null,
      "version": 2
    },
    {
      "id": "ec44f7d8-4e8b-4259-8c86-2cd9b2472451",
      "code": "buzzerNotification2",
      "sendingIds": [
        "profile"
      ],
      "userId": null,
      "version": 1
    }
  ],
  "total": 2
}

Возвращает отфильтрованный список системных настроек уведомлений. Доступные для фильтрации поля и виды фильтров по ним:

Поле Виды фильтров
id InSetQuery
code InSetQuery, LikeQuery
sendingid InSetQuery

Доступные для сортировки поля:

Имя вызова команды: searchSystemSettingBuzzer.
Поддерживается только синхронный вызов.
Результат выполнения команды не журналируется.

UpdateSystemSettingBuzzer

Передаем JSON с системными настройками уведомления

{
  "id": "e3901923-21dc-4f95-98d0-cb2ea29abe1e",
  "code": "buzzerNotification",
  "sendingIds": [
    "profile",
    "email"
  ],
  "version": 1
}

Получаем результат

1

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

Имя вызова команды: updateSystemSettingBuzzer.
Поддерживается только синхронный вызов.
Результат выполнения команды не журналируется.

DeleteSystemSettingBuzzer

Передаем ID системных настроек уведомления

"0ccd05ac-50c0-4e7e-906b-6893eaa8d9de"

Получаем результат

1

Удалить существующие системные настройки события по ID.

Имя вызова команды: deleteSystemSettingBuzzer.
Поддерживается только синхронный вызов.
Результат выполнения команды не журналируется.

SendNotification

Передаем данные отправляемого уведомления

{
  "code": "buzzerNotification",
  "userId": "016d04f4-fc1a-4629-808b-e5e1c35bb348",
  "data": {
    "field": "value"
  }
}

Получаем результат

true

Отправка уведомления пользователю.

Имя вызова команды: sendNotification.
Поддерживается асинхронный и синхронный вызов.
Результат выполнения команды не журналируется.

Модели сервиса уведомлений

Sending (Buzzer)

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

Название поля Тип Обязательное Описание
id uuid да Идентификатор сервиса
topic string да Очередь сервиса отправки в Kafka, в которую нужно перенаправить уведомление
version number нет Версия описания (опциональная, по умолчанию - 1)

Setting (Buzzer)

Настройка связи уведомления с сервисами отправки

Название поля Тип Обязательное Описание
id uuid да Идентификатор настройки
code string да Код уведомления
sendingIds string[] да Список сервисов отправки
userId uuid string нет Идентификатор пользователя, для которого определяется настройка. Отсутствует у системных настроек.
version number да Версия настройки

SettingCreateDTO (Buzzer)

Объект для создания настройки связи уведомления с сервисами отправки

Название поля Тип Обязательное Описание
code string да Код уведомления
sendingIds string[] да Список сервисов отправки

SettingUpdateDTO (Buzzer)

Объект для обновления настройки связи уведомления с сервисами отправки

Название поля Тип Обязательное Описание
id uuid да Идентификатор настройки
code string да Код уведомления
sendingIds string[] да Список сервисов отправки
version number да Версия настройки

Command-status: сервис статуса команд

Сервис обеспечивает трассировку выполнения команд и хранение их промежуточных “текущих” состояний и результатов. Также он позволяет простым и быстрым способом запрашивать данные по этим текущим состояниям команд.

Иногда сервис может не успевать обрабатывать все события. Чтобы повысить скорость обработки входящих событий по командам, нужно запускать несколько инстансов. Производительность одной ноды и их общее количество подсчитывается индивидуально, в зависимости от ресурсов на одну ноду и количества партиций в топике (точнее, сколько будет приходиться партиций на одну ноду).
Например, для 8 CPU и 16gb RAM одна нода может вычитывать около 1500 сообщений в секунду из топика с 10 партициями ( читает все 10 партиций).
Обычно, чем меньше партиций читается одной нодой, тем меньше ядер CPU на нее нужно выделять (например, читает 2 партиции - выделяем 2 CPU).

Конфигурирование Command-status

Требования к запуску Command-status

Запуск локально из консоли с помощью SBT

COMMAND_STATUS_SERVICE_DB_HOST=localhost
COMMAND_STATUS_SERVICE_DB_PORT=5432
COMMAND_STATUS_SERVICE_DB_NAME=command-status_db
COMMAND_STATUS_SERVICE_DB_USER=postgres
COMMAND_STATUS_SERVICE_DB_PASSWORD=postgres
sbt boot/run

При запуске сервиса локально ожидается, что уже развернута необходимая инфраструктура:

Список переменных окружения для сервиса Command-status

Переменная Тип Обязательная Значение по умолчанию Описание
COMMAND_STATUS_SERVICE_PUBLISH_HOST string Нет "0.0.0.0" Хост, на котором слушает HTTP-сервер.
COMMAND_STATUS_SERVICE_PUBLISH_PORT int Нет 8080 Порт, на котором слушает HTTP-сервер.
COMMAND_STATUS_SERVICE_KAFKA_SERVERS string Да "localhost:9092" Адрес Kafka.
COMMAND_STATUS_SERVICE_STATUS_TOPIC string Да "commandevents" Название кафка-топика, куда отправляются сообщения со статусами выполняемых команд.
COMMAND_STATUS_SERVICE_CONSUMER_GROUP string Нет "statusGroup" Имя consumer-группы для чтения из кафка-топика команд. Не должна меняться и не должна быть пустой, иначе сервис перечитает свои команды при перезапуске.
COMMAND_STATUS_SERVICE_TOPIC_PARTITIONS int Нет 10 Число читаемых партиций из кафка-топика со статусами.
COMMAND_STATUS_SERVICE_KAFKA_CONSUMER_RESTART_MIN_BACKOFF duration string Нет 3 seconds Изначальная задержка до рестарта консьюмера после падения. С каждым рестартом, задержка увелчивается по формуле "delay = restartsNumber * initDelay"
COMMAND_STATUS_SERVICE_KAFKA_CONSUMER_RESTART_MAX_BACKOFF duration string Нет 1 minute Максимальное задержка до рестарта консьюмера после падения.
COMMAND_STATUS_SERVICE_KAFKA_CONSUMER_RESTART_MAX_RESTARTS int Нет 20 Максимальное число попыток переподключения консьюмера. После достижения максимального, роут /health будет возвращать 503, что приведет к рестарту сервиса в k8s.
COMMAND_STATUS_SERVICE_KAFKA_AUTH_USER string Нет "" Название учетной записи Kafka. Если название не указано, то настройки авторизации не будут применены.
COMMAND_STATUS_SERVICE_KAFKA_AUTH_PASSWORD string Нет "" Пароль учетной записи Kafka.
COMMAND_STATUS_SERVICE_KAFKA_AUTH_PRINCIPAL string Нет "" Principal учетной записи Kafka в Kerberos(в случае соединения с kafka через Kerberos).
COMMAND_STATUS_SERVICE_KAFKA_AUTH_KEYTAB_PATH string Нет "" Путь до keytab-файла(в случае соединения с kafka через Kerberos).
COMMAND_STATUS_SERVICE_KAFKA_AUTH_TRUSTSTORE_LOCATION string Нет "" Путь до хранилища сертификатов (Java key store). Если путь не указан, то сертификат применяться не будет.
COMMAND_STATUS_SERVICE_KAFKA_AUTH_TRUSTSTORE_PASSWORD string Нет "" Пароль к хранилищу сертификатов.
COMMAND_STATUS_SERVICE_KAFKA_AUTH_MODE string Нет "" Режим аутентификации: static - одна учетная запись на все запросы, mapping - учетная запись зависит от запроса.
COMMAND_STATUS_SERVICE_KAFKA_AUTH_CONFIG string Нет "" Настройки для аутентификации: если AuthMode = mapping, то необходим JSON с List[KafkaAuthConfig]. Переменная соответствует полю authConfig из KafkaAuthSettings.
COMMAND_STATUS_SERVICE_KAFKA_AUTH_CACHE_SIZE int Нет Максимальный размер кеша для Kafka producer (количество активных соединений).
COMMAND_STATUS_SERVICE_KAFKA_CONNECTION_CHECK_TEST_MESSAGES_INTERVAL duration string Нет 4 minutes Применяется только для producer-ов со способом аутентификации kerberos. Интервал отправки тестовых сообщений кафки в топик connectionCheck.testMessagesTopicName. Тестовые сообщения (null, service producer test) отправляются регулярно с этим интервалом.
COMMAND_STATUS_SERVICE_KAFKA_CONNECTION_CHECK_INTERVAL duration string Нет 60 seconds Применяется только для producer-ов со способом аутентификации kerberos. Интервал проверки того, сколько тестовых сообщений было отправлено за данный период. Если количество сообщений за этот период равно количеству сообщений за прошлый период, то начинается отсчет периода без сообщений.
COMMAND_STATUS_SERVICE_KAFKA_CONNECTION_CHECK_FAILED_AFTER_INTERVAL duration string Нет 5 minutes Применяется только для producer-ов со способом аутентификации kerberos. Максимальная продолжительность периода без успешно отправленных тестовых сообщений. По ее достижении сервис будет объявлен больным.
COMMAND_STATUS_SERVICE_KAFKA_AUTH_CACHE_TTL duration string Нет Время жизни Kafka producer в кеше.
COMMAND_STATUS_SERVICE_CONSUL_ADDRESS url string Нет "http://localhost:8500" Адрес Сonsul.
COMMAND_STATUS_SERVICE_CONSUL_AUTH_USER string Нет "" Название учетной записи Сonsul. Если название не указано, то настройки авторизации не будут применены.
COMMAND_STATUS_SERVICE_CONSUL_AUTH_PASSWORD string Нет "" Пароль учетной записи Сonsul.
COMMAND_STATUS_SERVICE_DISCOVERABLE_ID string Нет "CommandStatusService" ID сервиса в ServiceDiscovery.
COMMAND_STATUS_SERVICE_DISCOVERABLE_NAME string Нет "CommandStatusService" Имя сервиса в ServiceDiscovery.
COMMAND_STATUS_SERVICE_DISCOVERABLE_HOST string Да "localhost" Хост, публикуемый в ServiceDiscovery. По нему на данный сервис будут обращаться другие через HTTP. Указанный адрес должен быть виден другим сервисам. Пример: имя kubernetes/docker_swarm service.
COMMAND_STATUS_SERVICE_DISCOVERABLE_PORT int Нет Порт, публикуемый в ServiceDiscovery. По нему на данный сервис будут обращаться другие через HTTP. По умолчанию указывается порт, который слушает HTTP-сервер.
COMMAND_STATUS_SERVICE_DISCOVERABLE_LIVETIME duration string Нет 5 minutes Период после последней отправки health check, в течение которого ServiceDiscovery считает данный сервис живым.
COMMAND_STATUS_SERVICE_DISCOVERABLE_HEALTHPASS duration string Нет 1 minute Периодичность отправки health check в ServiceDiscovery.
COMMAND_STATUS_SERVICE_DISCOVERABLE_VERSION string Нет "v1" Версия сервиса, публикуемого в ServiceDiscovery.
COMMAND_STATUS_SERVICE_AKKA_HTTP_MAXCON int Нет 1024 Максимальное число одновременных исходящих HTTP-соединений.
COMMAND_STATUS_SERVICE_AKKA_HTTP_IDLE_TIMEOUT duration string Нет 60 seconds Максимальное время жизни бездействующего соединения.
COMMAND_STATUS_SERVICE_AKKA_HTTP_REQUEST_TIMEOUT duration string Нет 30 seconds Максимальное время ожидания исполнения запроса; должно быть меньше COMMAND_STATUS_SERVICE_AKKA_HTTP_IDLE_TIMEOUT.
COMMAND_STATUS_SERVICE_AKKA_DEFAULT_DISPATCHER_EXECUTOR string Нет "default-executor" AKKA DOC: Which kind of ExecutorService to use for this dispatcher. Valid options: "default-executor" requires a "default-executor" section; "fork-join-executor" requires a "fork-join-executor" section; "thread-pool-executor" requires a "thread-pool-executor" section; "affinity-pool-executor" requires an "affinity-pool-executor" section.
COMMAND_STATUS_SERVICE_AKKA_DEFAULT_DISPATCHER_THROUGHPUT int Нет 5 AKKA DOC: Throughput defines the number of messages that are processed in a batch before the thread is returned to the pool. Set to 1 for as fair as possible.
COMMAND_STATUS_SERVICE_AKKA_FJP_PARALLELISM_MIN int Нет 8 AKKA DOC: Min number of threads to cap factor-based parallelism number to.
COMMAND_STATUS_SERVICE_AKKA_FJP_PARALLELISM_MAX int Нет 64 AKKA DOC: Max number of threads to cap factor-based parallelism number to.
COMMAND_STATUS_SERVICE_AKKA_FJP_PARALLELISM_FACTOR float Нет 1.0 AKKA DOC: The parallelism factor is used to determine thread pool size using the following formula: ceil(available processors * factor). Resulting size is then bounded by the parallelism-min and parallelism-max values.
COMMAND_STATUS_SERVICE_AKKA_FJP_PARALLELISM_QUEUE_MODE string Нет "FIFO" AKKA DOC: Setting to "FIFO" to use queue like peeking mode which "poll" or "LIFO" to use stack like peeking mode which "pop".
COMMAND_STATUS_SERVICE_AKKA_DEFAULT_DISPATCHER_EXECUTOR string Нет "thread-pool-executor" AKKA DOC: Which kind of ExecutorService to use for this dispatcher. Valid options: "default-executor" requires a "default-executor" section; "fork-join-executor" requires a "fork-join-executor" section; "thread-pool-executor" requires a "thread-pool-executor" section; "affinity-pool-executor" requires an "affinity-pool-executor" section.
COMMAND_STATUS_SERVICE_AKKA_DEFAULT_DISPATCHER_THROUGHPUT int Нет 1 AKKA DOC: Throughput defines the number of messages that are processed in a batch before the thread is returned to the pool. Set to 1 for as fair as possible.
COMMAND_STATUS_SERVICE_AKKA_DEFAULT_BLOCKING_FIXED_POOL_SIZE int Нет 16 AKKA DOC: Define a fixed thread pool size with this property. The corePoolSize and the maximumPoolSize of the ThreadPoolExecutor will be set to this value, if it is defined. Then the other pool-size properties will not be used.
Valid values are: off or a positive integer.
COMMAND_STATUS_SERVICE_SENDERLIB_COMMANDS_CACHE_UPDATEPERIOD duration string Нет 10 minutes Время кэширования данных по командам из CommandDiscovery.
COMMAND_STATUS_SERVICE_SENDERLIB_SERVICES_CACHE_UPDATEPERIOD duration string Нет 0 minutes Время кэширования данных по сервисам из ServiceDiscovery.
COMMAND_STATUS_SERVICE_DB_HOST string Да Хост БД.
COMMAND_STATUS_SERVICE_DB_PORT int Да Порт БД.
COMMAND_STATUS_SERVICE_DB_NAME string Да Имя базы в БД.
COMMAND_STATUS_SERVICE_DB_URL jdbc url string Нет JDBC-url для соединения с БД. По умолчанию собирается из других обязательных переменных. Можно указать только его, если не хочется отдельно указывать хост/порт/имя базы.
COMMAND_STATUS_SERVICE_DB_USER string Да Пользователь БД.
COMMAND_STATUS_SERVICE_DB_PASSWORD string Да Пароль пользователя БД.
COMMAND_STATUS_SERVICE_DB_THREADS int Нет 10 Количество потоков в пуле потоков для соединения с БД.
COMMAND_STATUS_SERVICE_DB_QUEUE_SIZE int Нет 300 Размер очереди для действий базы данных, которые не могут быть выполнены немедленно, когда все потоки заняты. За пределами этого значения новые действия немедленно завершаются неудачей.
COMMAND_STATUS_SERVICE_DB_CONN_MAX int Нет 10 Максимальное количество одновременных подключений к БД.
COMMAND_STATUS_SERVICE_DB_CONN_MIN int Нет ${COMMAND_STATUS_SERVICE_DB_THREADS} Минимальное количество одновременных подключений к БД.
COMMAND_STATUS_SERVICE_DB_CONN_TIMEOUT duration string Нет 20 seconds Максимальное время ожидания ответа для соединения к БД. Если это время превышено, а соединение не становится доступным, будет брошено исключение SQLException. 1000 мс — минимальное значение.
COMMAND_STATUS_SERVICE_DB_ISOLATION string Нет "READ_COMMITTED" Уровень изоляции транзакций для новых подключений. Допустимые значения: NONE, READ_COMMITTED, READ_UNCOMMITTED, REPEATABLE_READ, SERIALIZABLE.
COMMAND_STATUS_SERVICE_DB_READONLY boolean Нет false Read-only SQL транзакция может изменять только временные таблицы. Этот параметр управляет статусом «только для чтения» по умолчанию для каждой новой транзакции.
COMMAND_STATUS_SERVICE_DB_VALIDATION_TIMEOUT duration string Нет 1 seconds Максимальное время, в течение которого соединение будет проверяться на работоспособность. 1000 мс — минимальное значение.
COMMAND_STATUS_SERVICE_DB_IDLE_TIMEOUT duration string Нет 10 minutes Максимальное время, в течение которого соединению разрешено простаивать в пуле. Значение 0 означает, что простаивающие соединения никогда не удаляются из пула.
COMMAND_STATUS_SERVICE_DB_MAX_LIFETIME duration string Нет 30 minutes Максимальное время жизни соединения в пуле. Когда простаивающее соединение достигает этого времени ожидания, даже если оно недавно использовалось, оно будет удалено из пула. Значение 0 указывает на отсутствие максимального срока службы.
COMMAND_STATUS_SERVICE_DB_INITIALIZATION_FAIL_FAST boolean Нет false Deprecated, начиная с версии Slick 3.3.0. Определяет, будет ли пул «быстро выходить из строя», если пул не может быть успешно заполнен начальными соединениями. Если соединения не могут быть созданы во время запуска пула, будет выдано исключение RuntimeException. Это свойство не имеет никакого эффекта, если minConnections равно 0.
COMMAND_STATUS_SERVICE_DB_LEAK_DETECTION_THRESHOLD int Нет 0 Время, в течение которого соединение может находиться вне пула, прежде чем будет зарегистрировано сообщение, указывающее на возможную утечку соединения. Значение 0 означает, что обнаружение утечек отключено. Наименьшее приемлемое значение для включения обнаружения утечек составляет 10 с.
COMMAND_STATUS_SERVICE_DB_CONNECTION_TEST_QUERY string Нет "SELECT 1" Выражение, которое будет выполнено непосредственно перед получением соединения из пула для проверки того, что соединение с базой данных все еще активно. Оно зависит от базы данных и должно представлять собой запрос, требующий минимальной обработки базой данных (например, «VALUES 1»). Если этот параметр не установлен, вместо него используется метод JDBC4 Connection.isValid().
COMMAND_STATUS_SERVICE_DB_AUTO_COMMIT boolean Нет true Это свойство определяет то, как будут вести себя по умолчанию возвращаемые соединения относительно autocommit-а.
COMMAND_STATUS_SERVICE_DB_SCHEMA string Нет "public" Устанавливает schema по умолчанию.
COMMAND_STATUS_SERVICE_DB_ISOLATE_INTERNAL_QUERIES boolean Нет false Определяет то, изолируются ли с помощью транзакций внутренние запросы пула(например запрос connection alive test). Свойство применяется только если autoCommit выключен.
COMMAND_STATUS_SERVICE_DB_INITIALIZATION_FAIL_TIMEOUT int Нет 1 Работает, начиная с версии Slick 3.3.0. Определяет, будет ли пул «быстро выходить из строя», если пул не может быть успешно заполнен начальными соединениями. Любое положительное число считается числом миллисекунд для попытки получить начальное соединение;поток приложения будет заблокирован в течение этого периода. Если соединение не может быть получено до истечения этого времени,будет брошено исключение. Данный таймаут применяется после периода connectionTimeout. Если значение равно нулю (0),HikariCP попытается получить и проверить подключение. Если соединение получено,но проверка не пройдена, будет брошено исключение, и пул не будет запущен. Однако,если соединение не может быть получено, пул запустится,но последующие попытки получить соединение могут потерпеть неудачу.Значение меньше нуля пройдет любую первоначальную попытку подключения, и пул немедленно запустится,пытаясь получить соединения в фоновом режиме.Следовательно, последующие попытки получить соединение могут потерпеть неудачу.
COMMAND_STATUS_SERVICE_DB_REGISTER_MBEANS boolean Нет false Зарегистрированы ли JMX Management Beans («MBeans»).
COMMAND_STATUS_SERVICE_STATUS_CACHE_TTL duration string Нет 2 hours Время жизни статуса команд в базе данных сервиса статусов (после получения последнего статуса из кафка).
COMMAND_STATUS_SERVICE_STATUS_CACHE_CLEAN_CHECK duration string Нет 5 minutes Период проверки базы данных со статусами команд для удаления статусов, время жизни которых превысило COMMAND_STATUS_SERVICE_STATUS_CACHE_TTL.
COMMAND_STATUS_SERVICE_STATUS_CACHE_SUBSCRIPTION_CHECK duration string Нет 1 second Время задержки между проверками кеша со статусами команд для уведомления подписчиков на статусы. Период проверки статуса = время обхода всех команд, для которых существуют подписки + время задержки.
COMMAND_STATUS_SERVICE_COMMAND_CLEANER_CHECK duration string Нет 1 hour Период проверки Command discovery для очистки команд, привязаных к сервисам которые не считаются "живыми".
COMMAND_STATUS_SERVICE_COMMAND_CLEANER_DELETE_ERRORS boolean Нет true Удалять ли принудительно команды из Command discovery, с которыми возникли ошибки во время "очистки".
COMMAND_STATUS_SERVICE_SENDERLIB_COMMANDS_HTTP_RETRY_ATTEMPTS int Нет 5 Поле attempts из RetrySettings.
COMMAND_STATUS_SERVICE_SENDERLIB_COMMANDS_HTTP_RETRY_DELAY duration string Нет 5 seconds Поле delay из RetrySettings.
COMMAND_STATUS_SERVICE_SENDERLIB_COMMANDS_HTTP_RETRY_KIND string Нет "OnSomeExceptions(ConnectException)" CommandResultRetryConditionKind.
COMMAND_STATUS_SERVICE_SENDERLIB_CONSIDER_ALL_COMMANDS_AS_INTERNAL boolean Нет false Флаг, определяющий будут ли все обращения в другие сервисы являться внутренними (т.е. не требовать авторизацию). Детальное описание механизма: Внутренние команды.
COMMAND_STATUS_SERVICE_KAFKA_CONSUMER_PER_MESSAGE_RESTART_MAX_RESTARTS int Нет 2 Максимальное количество раз, которое консьюмер перезапустится с неизменной очередью сообщений(в пределах COMMAND_STATUS_SERVICE_KAFKA_CONSUMER_RESTART_MAX_RESTARTS_WITHIN), прежде чем проигнорировать сообщение, на котором происходит ошибка (Указано количество рестартов, а не прочтений. Если ALEXANDRINA_KAFKA_CONSUMER_RESTART_MAX_RESTARTS = 2, то ошибочное сообщение будет обработано 3 раза, после чего произойдет 3ий рестарт и оно будет проигнорировано). Если указать 0, то перезапуск произойдет, но сообщение будет обработано только в первый раз, когда произошла ошибка. Если указать значение меньше 0, то перезапуски все равно будут происходить, но игнорирование сообщений, вызывающих ошибку, будет отключено.
COMMAND_STATUS_SERVICE_KAFKA_CONSUMER_PER_MESSAGE_RESTART_CACHE_SIZE int Нет 100 Для каждого сообщения счетчик перепрочтений хранится в кэше. Максимальное количество значений в этом кэше.
COMMAND_STATUS_SERVICE_KAFKA_CONSUMER_PER_MESSAGE_RESTART_CACHE_TTL duration string Нет 5 minutes Для каждого сообщения счетчик перепрочтений хранится в кэше.Максимальное время жизни элемента в этом кэше. В случае отсутствия значения время жизни элемента не будет ограничено.
COMMAND_STATUS_SERVICE_KAFKA_CONSUMER_POLL_TIMEOUT duration string нет 10 milliseconds timeout запроса poll для kafka consumer
COMMAND_STATUS_SERVICE_KAFKA_CONSUMER_POLL_INTERVAL duration string нет 100 milliseconds интервал между запросами poll для kafka consumer
COMMAND_STATUS_SERVICE_KAFKA_CONSUMER_PROPS string нет "max.poll.records=500;max.partition.fetch.bytes=524288" дополнительные параметры для kafka consumer в формате "key1=value1;key2=value2"
COMMAND_STATUS_SERVICE_WRITE_STATUS_INMEMORY_CACHE_MAX_SIZE int Нет 1000 Максимальный размер кэша, который поддерживается при записи статусов. К этому кэшу происходит обращение для проверки приоритета статуса. (Статус записывается в БД только если его приоритет выше, чем у последнего статуса этой команды уже записанного в БД).
COMMAND_STATUS_SERVICE_WRITE_STATUS_INMEMORY_CACHE_TTL duration string Нет 60 seconds Время жизни элемента в кэше, который поддерживается при записи статусов.
COMMAND_STATUS_SERVICE_WRITE_STATUS_INMEMORY_CACHE_SCHEDULER_ENABLED boolean Нет true Будет ли запущен scheduler, который убирает элементы из кэша в момент истечения ttl, или элементы будет удаляться только в момент обращения к кэшу при записи статусов.
COMMAND_STATUS_SERVICE_READ_STATUS_INMEMORY_CACHE_MAX_SIZE int Нет 10 Максимальный размер кэша, который поддерживается при чтении статусов. При чтении статусов обращение к БД происходит только если в кэше нет статуса по этой команде.
COMMAND_STATUS_SERVICE_READ_STATUS_INMEMORY_CACHE_TTL duration string Нет 10 milliseconds Время жизни элемента в кэше, который поддерживается при чтении статусов.
COMMAND_STATUS_SERVICE_READ_STATUS_INMEMORY_CACHE_SCHEDULER_ENABLED boolean Нет true Будет ли запущен scheduler, который убирает элементы из кэша в момент истечения ttl, или элементы будет удаляться только в момент обращения к кэшу при чтении статусов.
NOT_LOG_VALUE_FOR_STATUSES string Нет "" Список CommandStatus, для которых не нужно логировать поле "value". Статусы перечисляются в одной строке через запятую ",".
APP_LOGIC_LOG_LEVEL string Нет "INFO" Уровень логгирования бизнес логики сервиса.
BACKGROUND_LOGIC_LOG_LEVEL string Нет "INFO" Уровень логгирования бэкграунд процессов сервиса.

Список команд сервиса Command-status (commands-list)

Список команд сервиса Command-status аналогичен списку команд в библиотеке command-status-core.

Модели сервиса Command-status

Набор моделей сервиса Command-status аналогичен набору моделей в библиотеке command-status-core.

Command-status-core: базовая библиотека сервисов сервисов статуса команд command-status

В библиотеку вынесен шаблон структуры и кода для сервисов статуса команд и реализации по умолчанию.

Сервис разбит на несколько модулей, в виде sbt проектов:

Публикуются эти проекты как одна библиотека command-status-core.

Сервис обеспечивает трассировку выполнения команд и хранение их промежуточных “текущих” состояний и результатов. Также он позволяет простым и быстрым способом запрашивать данные по этим текущим состояниям команд.

Иногда сервис может не успевать обрабатывать все события. Чтобы повысить скорость обработки входящих событий по командам, нужно запускать несколько инстансов. Производительность одной ноды и их общее количество подсчитывается индивидуально, в зависимости от ресурсов на одну ноду и количества партиций в топике (точнее, сколько будет приходиться партиций на одну ноду).
Например, для 8 CPU и 16gb RAM одна нода может вычитывать около 1500 сообщений в секунду из топика с 10 партициями ( читает все 10 партиций).
Обычно, чем меньше партиций читается одной нодой, тем меньше ядер CPU на нее нужно выделять (например, читает 2 партиции - выделяем 2 CPU).

Подключение (command-status-core)

Для того чтобы использовать библиотеку command-status-core, нужно добавить зависимость "com.embedika.commandstatus" %% "command-status-core" % verdiVersion

Liquibase (command-status-core)

Реализация command-status-core, поставляемая в данной библиотеке, предполагает наличие определенных таблиц в базе данных, которая указана в application.conf по пути database.db.url. Эти таблицы command-status-core создает с помощью com.embedika.verdi.persistence.migration.LiquibasePlugin. Для корректной работы плагина в сервисе, созданном на основе command-status-core, по пути boot/src/main/resources/liquibase должен лежать файл changelog.xml, иначе при запуске упадет исключение liquibase.exception.ChangeLogParseException: The file liquibase/changelog.xml was not found. Для корректной работы всех команд в сервисе, созданном на основе command-status-core, предоставленный файл changelog.xml должен включать в себя все stages, находящиеся в command-status-core по пути /boot/src/main/resources/liquibase/stages. При необходимости после указанных stages можно добавить в changelog.xml свои кастомные stages.

Пример содержимого файла changelog.xml.

<?xml version="1.0" encoding="UTF-8"?>
<databaseChangeLog
        xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog
         http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.6.xsd">

    <include file="stages/202504.xml" relativeToChangelogFile="true"/>

</databaseChangeLog>

Модули (command-status-core)

Для инициализации сервиса command-status-core используются модули izumi-distage.

В каждом модуле описывается создание сущностей, необходимых для работы сервиса.

Более подробное описание работы с модулями можно найти в Модули (mon-core)

Список команд библиотеки Command-status-core (commands list)

Список реализованных в сервисе команд.

Назначение команды Имя вызова команды
Получение статуса команды (без ожидания) GetStatus
Получение статуса команды (ожидание конечного статуса в течение переданного таймаута) PollStatus

GetStatus

Payload для команды

import com.embedika.senderlib.{Discpatcher, VerdiFactory}
import com.embedika.senderlib.models.command._

val factory: VerdiFactory = VerdiFactory.create(
  /** params here */
)
val dispatcher: Dispatcher = factory.dispatcher

dispatcher.status(CommandId("a9f813eb-22ff-4982-9828-c3471cec76fe"))
// or
dispatcher.sendCommandSync(CommandName("getStatus"), CommandId("a9f813eb-22ff-4982-9828-c3471cec76fe"))
"a9f813eb-22ff-4982-9828-c3471cec76fe"

Результат выполнения команды

val result: Future[Either[DispatchError, (CommandId, CommandStatusRepresentation)]] =
  dispatcher.sendCommandSync(CommandName("getStatus"), CommandId("a9f813eb-22ff-4982-9828-c3471cec76fe"))
result.transform {
  case Success(Some(Right(id, result))) =>
    val status = result.status
    val json = result.json
  // process result
  case _ => // process errors
}
{
  "status": "Completed",
  "timestamp": 1657797778943,
  "value": "test completed"
}

Получает текущий статус исполняемой команды. Dispatcher для команд имеет вспомогательный метод .status() для упрощенного вызова этой команды.

Свойства команды

Свойство Значение Описание
Версия v1
Название команды getStatus Название команды для прямого вызова
Тип вызова HTTP
HTTP-метод POST
Url /v1/status
Права доступа []
Внутренняя команда нет
Сервисная команда да для служебных команд не ведется жизненный цикл, не пишутся состояния

Поддерживается только синхронный вызов.
Результат выполнения команды не журналируется.

PollStatus

Передаем ID команды и таймаут поллинга

{
  "commandId": "efef5704-5827-49f8-8b3f-a00df3db7f5a",
  "timeoutSeconds": 5
}

Результат выполнения команды

{
  "status": "Completed",
  "timestamp": 1657797778943,
  "value": "test completed"
}

Ожидает завершение команды в течение указанного времени (long-polling) и возвращает результат.
Если команда не завершилась за указанное время, вернет ее текущий статус.

Свойства команды

Свойство Значение Описание
Версия v1
Название команды pollStatus Название команды для прямого вызова
Тип вызова HTTP
HTTP-метод POST
Url /v1/pollStatus
Права доступа []
Внутренняя команда нет
Сервисная команда да для служебных команд не ведется жизненный цикл, не пишутся состояния

Поддерживается только синхронный вызов.
Результат выполнения команды не журналируется.

Модели сервиса command-status-core (models)

PollStatus (command-status-core)

Поле Тип Обязательное Значение по умолчанию Описание Ограничения
commandId CommandId Да ID команды, статус которой необходимо получить
timeoutSeconds Int Да Таймаут, в течение которого будет производиться ожидание одного из финальных статусов команды

CommandAggregatedStatus (command-status-core)

CommandAggregatedStatus без поля httpHeaders.

Data-model: сервис модели данных

Сервис модели данных (Data Model Service) позволяет настроить какие сущности, с какими полями и отношениями будут храниться в системе на основе Verdi. На основе данных о сущностях сервис будет формировать описание модели данных и возвращать его в формате JsonSchema. Также сервис управляет созданием/изменением/удалением объектов сущностей в реестрах.
Сущности, полученные из внешних источников (клиентов), таких как сетевая папка или 1С, называются внешними. Отличие от внутренних сущностей состоит в том, что помимо внутреннего ID, они имеют ID из внешнего источника, по которому этот источник может совершать запросы.

Конфигурирование Data-model

Требования к запуску Data-model

Запуск сервиса осуществляется локально через sbt, на стенде в docker на jvm.

Для корректной минимальной работы сервиса требуется обязательное подключение к PostgreSQL, Kafka, Consul. Для настройки подключения к ним нужно заполнить обязательные переменные окружения из раздела ниже.

Для нормальной работы сервису дополнительно требуется окружение Verdi: CommandStatus и ApiGateway. В этом случае нужно уделить внимание настройкам, связанным с ServiceDiscovery и CommandDiscovery.

Список переменных окружения для сервиса Data-model

Все доступные переменные окружения для настройки сервиса модели данных.

Переменная Тип Обязательная Значение по умолчанию Описание
DATA_MODEL_HTTP_HOST String Нет 0.0.0.0 Хост, на котором слушает HTTP-сервер.
DATA_MODEL_HTTP_PORT Int Нет 8192 Порт, на котором слушает HTTP-сервер.
DATA_MODEL_KAFKA_SERVERS String Да localhost:9092 Адрес Kafka.
DATA_MODEL_KAFKA_TOPIC String Нет data_model_service_commands Название кафка-топика для получения команд. Сервис получает кафка-команды по нему, но и также сам публикует это название в CommandDiscovery.
DATA_MODEL_KAFKA_CONSUMER_GROUP String Нет data-model-service Имя consumer-группы для чтения из кафка-топика команд. Не должна меняться и не должна быть пустой, иначе сервис перечитает свои команды при перезапуске.
DATA_MODEL_KAFKA_PARTITIONS Int Нет 10 Число читаемых партиций из кафка-топика команд.
DATA_MODEL_KAFKA_CONSUMER_RESTART_MIN_BACKOFF Duration String Нет 1 second Изначальная задержка до рестарта консьюмера после падения (увеличивается в 2 раза после каждого рестарта).
DATA_MODEL_KAFKA_CONSUMER_RESTART_MAX_BACKOFF Duration String Нет 30 seconds Максимальная задержка до рестарта консьюмера после падения.
DATA_MODEL_KAFKA_CONSUMER_RESTART_RANDOM_FACTOR Double Нет 0.2 Коэффициент величины дополнительной случайной задержки(jitter) относительно основной задержки (При значении 0.2 задержка может быть до 20% больше, чем при 0). Если после умножения задержки на DATA_MODEL_KAFKA_CONSUMER_RESTART_RANDOM_FACTOR получится меньше 1 миллисекунды, то jitter будет приравнен к нулю.
DATA_MODEL_KAFKA_CONSUMER_RESTART_MAX_RESTARTS Int Нет 5 Максимальное число рестартов консьюмера после падения (в пределах DATA_MODEL_KAFKA_CONSUMER_RESTART_MAX_RESTARTS_WITHIN).После превышения этого числа сервис будет объявлен больным. Все рестарты для каждого отдельного сообщения увеличивают и общий счетчик рестартов консьюмера, поэтому при использовании DATA_MODEL_KAFKA_CONSUMER_PER_MESSAGE_RESTART_MAX_RESTARTS нужно указывать DATA_MODEL_KAFKA_CONSUMER_RESTART_MAX_RESTARTS > DATA_MODEL_KAFKA_CONSUMER_PER_MESSAGE_RESTART_MAX_RESTARTS или не указывать DATA_MODEL_KAFKA_CONSUMER_PER_MESSAGE_RESTART_MAX_RESTARTS совсем.
DATA_MODEL_KAFKA_CONSUMER_RESTART_MAX_RESTARTS_WITHIN Duration String Нет 5 minutes Временной отрезок, в который DATA_MODEL_KAFKA_CONSUMER_RESTART_MAX_RESTARTS ограничивает число рестартов.
DATA_MODEL_KAFKA_CONSUMER_PER_MESSAGE_RESTART_MAX_RESTARTS Int Нет 2 Максимальное количество раз, которое консьюмер перезапустится с неизменной очередью сообщений(в пределах DATA_MODEL_KAFKA_CONSUMER_RESTART_MAX_RESTARTS_WITHIN), прежде чем проигнорировать сообщение, на котором происходит ошибка (Указано количество рестартов, а не прочтений. Если DATA_MODEL_KAFKA_CONSUMER_RESTART_MAX_RESTARTS = 2, то ошибочное сообщение будет обработано 3 раза, после чего произойдет 3ий рестарт и оно будет проигнорировано). Если указать 0, то перезапуск произойдет, но сообщение будет обработано только в первый раз, когда произошла ошибка. Если указать значение меньше 0, то перезапуски все равно будут происходить, но игнорирование сообщений, вызывающих ошибку, будет отключено.
DATA_MODEL_KAFKA_CONSUMER_PER_MESSAGE_RESTART_CACHE_SIZE Int Нет 100 Для каждого сообщения счетчик перепрочтений хранится в кэше. Максимальное количество значений в этом кэше.
DATA_MODEL_KAFKA_CONSUMER_PER_MESSAGE_RESTART_CACHE_TTL Duration String Нет 5 minutes Для каждого сообщения счетчик перепрочтений хранится в кэше.Максимальное время жизни элемента в этом кэше. В случае отсутствия значения время жизни элемента не будет ограничено.
DATA_MODEL_KAFKA_CONSUMER_POLL_TIMEOUT Duration String Нет 10 milliseconds timeout запроса poll для kafka consumer.
DATA_MODEL_KAFKA_CONSUMER_POLL_INTERVAL Duration String Нет 100 milliseconds Интервал между запросами poll для kafka consumer.
DATA_MODEL_KAFKA_CONSUMER_PROPS String Нет max.poll.records=500;max.partition.fetch.bytes=524288 Дополнительные параметры для kafka consumer в формате key1=value1;key2=value2.
DATA_MODEL_KAFKA_PRODUCER_PROPS String Нет batch.size=524288;linger.ms=10;max.request.size=1048576 Дополнительные параметры для kafka producer в формате key1=value1;key2=value2.
DATA_MODEL_KAFKA_COMMANDEVENT_TOPIC String Да commandevents Название кафка-топика для отправки сообщений со статусами выполняемых команд. ОБЯЗАТЕЛЬНО должно соответствовать названию этого топика в сервисе статуса команд.
DATA_MODEL_KAFKA_FILE_EVENTS_TOPIC String Нет fileEvents Название кафка-топика для отправки сообщений об удалении файлов.
DATA_MODEL_KAFKA_AUTH_USER String Нет Название учетной записи Kafka. Если название не указано, то настройки авторизации не будут применены.
DATA_MODEL_KAFKA_AUTH_PASSWORD String Нет Пароль учетной записи Kafka.
DATA_MODEL_KAFKA_AUTH_PRINCIPAL String Нет Principal учетной записи Kafka в Kerberos(в случае соединения с kafka через Kerberos).
DATA_MODEL_KAFKA_AUTH_KEYTAB_PATH String Нет Путь до keytab-файла(в случае соединения с kafka через Kerberos).
DATA_MODEL_KAFKA_AUTH_TRUSTSTORE_LOCATION String Нет Путь до хранилища сертификатов (Java key store). Если путь не указан, то сертификат применяться не будет.
DATA_MODEL_KAFKA_AUTH_TRUSTSTORE_PASSWORD String Нет Пароль к хранилищу сертификатов.
DATA_MODEL_KAFKA_AUTH_MODE String Нет Режим аутентификации: static - одна учетная запись на все запросы, mapping - учетная запись зависит от запроса.
DATA_MODEL_KAFKA_AUTH_CONFIG String Нет Настройки для аутентификации: если AuthMode = mapping, то необходим JSON с List[KafkaAuthConfig]. Переменная соответствует полю authConfig из KafkaAuthSettings.
DATA_MODEL_KAFKA_AUTH_CACHE_SIZE Int Нет Максимальный размер кэша для Kafka producer (количество активных соединений).
DATA_MODEL_KAFKA_AUTH_CACHE_TTL Duration String Нет Время жизни Kafka producer в кэше.
DATA_MODEL_KAFKA_CONNECTION_CHECK_TEST_MESSAGES_INTERVAL Duration String Нет 4 minutes Применяется только для producer-ов со способом аутентификации kerberos. Интервал отправки тестовых сообщений кафки в топик connectionCheck.testMessagesTopicName. Тестовые сообщения (null, service producer test) отправляются регулярно с этим интервалом.
DATA_MODEL_KAFKA_CONNECTION_CHECK_INTERVAL Duration String Нет 60 seconds Применяется только для producer-ов со способом аутентификации kerberos. Интервал проверки того, сколько тестовых сообщений было отправлено за данный период. Если количество сообщений за этот период равно количеству сообщений за прошлый период, то начинается отсчет периода без сообщений.
DATA_MODEL_KAFKA_CONNECTION_CHECK_FAILED_AFTER_INTERVAL Duration String Нет 5 minutes Применяется только для producer-ов со способом аутентификации kerberos. Максимальная продолжительность периода без успешно отправленных тестовых сообщений. По ее достижении сервис будет объявлен больным.
DATA_MODEL_KAFKA_PRODUCER_PROPS String Нет max.request.size=1048576 Дополнительные параметры для Kafka producer. Заполняются по шаблону "key1=value1;key2=value2".
DATA_MODEL_KAFKA_PRODUCER_MESSAGE_MAX_BYTES Int Нет 1048576 Лимит в байтах для Kafka сообщений.
DATA_MODEL_CONSUL_ADDR URL Нет http://localhost:8500 Адрес Сonsul.
DATA_MODEL_CONSUL_AUTH_USER String Нет Название учетной записи Сonsul. Если название не указано, то настройки авторизации не будут применены.
DATA_MODEL_CONSUL_AUTH_PASSWORD String Нет Пароль учетной записи Сonsul.
DATA_MODEL_TRACE_DURATION Boolean Нет false Признак необходимости трассировки выполнения команд.
DATA_MODEL_BATCH_PARALLELISM Int Нет 4 Параллелизм для батч-обработок (например обновление нескольких объектов в одном запросе).
DATA_MODEL_DISCOVERABLE_ID String Нет another_data_model _service_instance ID сервиса в ServiceDiscovery.
DATA_MODEL_DISCOVERABLE_NAME String Нет dataModel Имя сервиса в ServiceDiscovery.
DATA_MODEL_DISCOVERABLE_HOST String Да localhost Хост, публикуемый в ServiceDiscovery. По нему на данный сервис будут обращаться другие через HTTP. Указанный адрес должен быть виден другим сервисам. Пример: имя kubernetes/docker_swarm service.
DATA_MODEL_DISCOVERABLE_PORT Int Нет Порт, публикуемый в ServiceDiscovery. По нему на данный сервис будут обращаться другие через HTTP. По умолчанию указывается порт, который слушает HTTP-сервер.
DATA_MODEL_DISCOVERABLE_LIVETIME Duration String Нет 2 minutes Период после последней отправки health check, в течение которого ServiceDiscovery считает данный сервис живым.
DATA_MODEL_DISCOVERABLE_HEALTHPASS String Нет 1 minute Периодичность отправки health check в ServiceDiscovery.
DATA_MODEL_AKKA_HTTP_CLIENT_MAXCON Int Нет 512 Максимальное число одновременных исходящих HTTP-соединений.
DATA_MODEL_AKKA_HTTP_CLIENT_MAXREQ Int Нет 1024 Максимальное число одновременных исходящих HTTP-запросов.
DATA_MODEL_AKKA_HTTP_SERVER_MAXCON Int Нет 1024 Максимальное число одновременных входящих HTTP-соединений.
DATA_MODEL_AKKA_HTTP_SERVER_IDLE_TIMEOUT Duration String Нет 5 minutes Максимальное время жизни входящего http-соединения.
DATA_MODEL_AKKA_HTTP_SERVER_REQUEST_TIMEOUT Duration String Нет 5 minutes Максимальное время обработки входящего http-запроса. Должно быть не больше предыдущего значения, иначе входящее соединение оборвется по таймауту времени жизни запроса.
DATA_MODEL_INTERNALCMD_ALLOW Boolean Нет false Можно ли сервису отправлять внутрисистемные команды.
DATA_MODEL_SENDERLIB_COMMANDS_CACHE_UPDATEPERIOD Duration String Нет 10 minutes Время кэширования данных по командам из CommandDiscovery.
DATA_MODEL_SENDERLIB_SERVICES_CACHE_UPDATEPERIOD Duration String Нет 30 seconds Время кэширования данных по сервисам из ServiceDiscovery.
DATA_MODEL_SENDERLIB_CONSIDER_ALL_COMMANDS_AS_INTERNAL Boolean Нет false Флаг, определяющий будут ли все обращения в другие сервисы являться внутренними (т.е. не требовать авторизацию). Детальное описание механизма: Внутренние команды.
DATA_MODEL_DB_HOST String Да Хост БД.
DATA_MODEL_DB_PORT Int Да Порт БД.
DATA_MODEL_DB_NAME String Да Имя базы в БД.
DATA_MODEL_DB_URL JBDC URL Нет JDBC-url для соединения с БД. По умолчанию собирается из других обязательных переменных. Можно указать только его, если не хочется отдельно указывать хост/порт/имя базы.
DATA_MODEL_DB_USER String Да Пользователь БД.
DATA_MODEL_DB_PASSWORD String Да Пароль пользователя БД.
DATA_MODEL_DB_THREADS Int Нет 10 Количество потоков в пуле потоков для соединения с БД.
DATA_MODEL_DB_QUEUE_SIZE Int Нет 300 Размер очереди для действий базы данных, которые не могут быть выполнены немедленно, когда все потоки заняты. За пределами этого значения новые действия немедленно завершаются неудачей.
DATA_MODEL_DB_CONN_MAX Int Нет 10 Максимальное количество одновременных подключений к БД.
DATA_MODEL_DB_CONN_TIMEOUT Duration String Нет 20 second Максимальное время ожидания ответа для соединения к БД. Если это время превышено, а соединение не становится доступным, будет брошено исключение SQLException. 1000 мс — минимальное значение.
DATA_MODEL_DB_ISOLATION String Нет READ_COMMITTED Уровень изоляции транзакций для новых подключений. Допустимые значения: NONE, READ_COMMITTED, READ_UNCOMMITTED, REPEATABLE_READ, SERIALIZABLE.
DATA_MODEL_DB_READONLY Boolean Нет false Read-only SQL транзакция может изменять только временные таблицы. Этот параметр управляет статусом «только для чтения» по умолчанию для каждой новой транзакции.
DATA_MODEL_DB_CONN_MIN Int Нет = DB_THREADS Минимальное количество одновременных подключений к БД.
DATA_MODEL_DB_VALIDATION_TIMEOUT Duration String Нет 1 seconds Максимальное время, в течение которого соединение будет проверяться на работоспособность. 1000 мс — минимальное значение.
DATA_MODEL_DB_IDLE_TIMEOUT Duration String Нет 10 minutes Максимальное время, в течение которого соединению разрешено простаивать в пуле. Значение 0 означает, что простаивающие соединения никогда не удаляются из пула.
DATA_MODEL_DB_MAX_LIFETIME Duration String Нет 30 minutes Максимальное время жизни соединения в пуле. Когда простаивающее соединение достигает этого времени ожидания, даже если оно недавно использовалось, оно будет удалено из пула. Значение 0 указывает на отсутствие максимального срока службы.
DATA_MODEL_DB_INITIALIZATION_FAIL_FAST String Нет false Deprecated, начиная с версии Slick 3.3.0. Определяет, будет ли пул «быстро выходить из строя», если пул не может быть успешно заполнен начальными соединениями. Если соединения не могут быть созданы во время запуска пула, будет выдано исключение RuntimeException. Это свойство не имеет никакого эффекта, если minConnections равно 0.
DATA_MODEL_DB_LEAK_DETECTION_THRESHOLD Int Нет 0 Время, в течение которого соединение может находиться вне пула, прежде чем будет зарегистрировано сообщение, указывающее на возможную утечку соединения. Значение 0 означает, что обнаружение утечек отключено. Наименьшее приемлемое значение для включения обнаружения утечек составляет 10 с.
DATA_MODEL_DB_CONNECTION_TEST_QUERY String Нет SELECT 1 Выражение, которое будет выполнено непосредственно перед получением соединения из пула для проверки того, что соединение с базой данных все еще активно. Оно зависит от базы данных и должно представлять собой запрос, требующий минимальной обработки базой данных (например, «VALUES 1»). Если этот параметр не установлен, вместо него используется метод JDBC4 Connection.isValid().
DATA_MODEL_DB_AUTO_COMMIT Boolean Нет true Это свойство определяет то, как будут вести себя по умолчанию возвращаемые соединения относительно autocommit-а.
DATA_MODEL_DB_SCHEMA String Нет public Устанавливает schema по умолчанию.
DATA_MODEL_DB_ISOLATE_INTERNAL_QUERIES Boolean Нет false Определяет то, изолируются ли с помощью транзакций внутренние запросы пула(например запрос connection alive test). Свойство применяется только если autoCommit выключен.
DATA_MODEL_DB_INITIALIZATION_FAIL_TIMEOUT Int Нет 1 Работает, начиная с версии Slick 3.3.0. Определяет, будет ли пул «быстро выходить из строя», если пул не может быть успешно заполнен начальными соединениями. Любое положительное число считается числом миллисекунд для попытки получить начальное соединение;поток приложения будет заблокирован в течение этого периода. Если соединение не может быть получено до истечения этого времени,будет брошено исключение. Данный таймаут применяется после периода connectionTimeout. Если значение равно нулю (0),HikariCP попытается получить и проверить подключение. Если соединение получено,но проверка не пройдена, будет брошено исключение, и пул не будет запущен. Однако,если соединение не может быть получено, пул запустится,но последующие попытки получить соединение могут потерпеть неудачу.Значение меньше нуля пройдет любую первоначальную попытку подключения, и пул немедленно запустится,пытаясь получить соединения в фоновом режиме.Следовательно, последующие попытки получить соединение могут потерпеть неудачу.
DATA_MODEL_DB_REGISTER_MBEANS Boolean Нет false Зарегистрированы ли JMX Management Beans («MBeans»).
DATA_MODEL_FS_REQUIRED Boolean Нет false Обязательно ли использовать реальное файлохранилище. Можно отключать для локального использования (НЕЛЬЗЯ! НЕ РАБОТАЕТ).
DATA_MODEL_FS_URI URL Нет http://localhost:9000 Адрес для подключения к Minio.
DATA_MODEL_FS_ACCESS_KEY_ID String Нет minioadmin Ключ доступа к хранилищу файлов Minio (aka пользователь).
DATA_MODEL_FS_SECRET_ACCESS_KEY String Нет minioadmin Секретный код доступа к хранилищу файлов Minio (aka пароль).
DATA_MODEL_FS_UPLOAD_PARALLELISM Int Нет 4 Максимально возможный параллелизм при загрузке файлов в хранилище.
DATA_MODEL_FS_AUTH_MODE String Нет static Режим аутентификации: static - одна учетная запись на все запросы, mapping - учетная запись зависит от запроса.
DATA_MODEL_FS_AUTH_CONFIG String Нет Настройки для аутентификации: если AuthMode = mapping, то необходим JSON с List[FSBucketConfig] соответствует полю authConfig FSConfigRep.
DATA_MODEL_FS_CACHE_SIZE Int Нет 1 Максимальный размер кэша клиентов для хранилища файлов (количество активных соединений).
DATA_MODEL_FS_CACHE_TTL Duration String Нет Время жизни клиента в кэше.
DATA_MODEL_FS_RETRY_ATTEMPTS Int Нет 5 Количество ретраев, которое будет произведено в случае Exception-а в операции FSClient-а и при вычитывании стрима в get операциях FSClient-а.
DATA_MODEL_FS_RETRY_DELAY Duration String Нет 10 millis Задержка между ретраями операций FSClient-а.
DATA_MODEL_FS_ZIO_SHORT_MESSAGE_MODE Boolean Нет false Флаг включения режима сохранения ошибок работы с файловым хранилищем в сервисе журналирования nestor. При включении режима ошибки в логах будут отображаться в сокращенном формате: Short zio message mode. ExceptionType: ТИП ОШИБКИ, Exception id: 'СГЕНЕРИРОВАННЫЙ UUID' added to journal. Указанный id будет фиксироваться в event записи nestor'а в поле data.id.
DATA_MODEL_TEMP_BUCKET String Нет temp Название бакета в Minio, в котором находятся временные файлы.
DATA_MODEL_ENTITY_OBJECTS_BUCKET String Нет datamodel Название бакета в Minio, в котором сохраняются на постоянной основе файлы объектов модели данных.
DATA_MODEL_RELATION_SYSTEM_FIELDS_PREFIX String Нет _ Префикс для системных полей relation-объектов, используемые в результате RichGet команд.
DATA_MODEL_AUTHORIZER_KIND String Нет authzforce Вид авторизатора, который используется в сервисе. Допустимые значения: authzforce, oberto. При указании неизвестного значения будет использовано значение по-умолчанию.
DATA_MODEL_SENDERLIB_COMMANDS_HTTP_RETRY_ATTEMPTS Int Нет 5 Поле attempts из RetrySettings.
DATA_MODEL_SENDERLIB_COMMANDS_HTTP_RETRY_DELAY Duration String Нет 5 seconds Поле delay из RetrySettings.
DATA_MODEL_SENDERLIB_COMMANDS_HTTP_RETRY_KIND String Нет OnSomeExceptions(ConnectException) CommandResultRetryConditionKind.
DATA_MODEL_SENDERLIB_CONSUL_CONNECTION_RETRY_MAX Int Нет 5 Количество попыток переподключения к Consul.
DATA_MODEL_SENDERLIB_CONSUL_CONNECTION_RETRY_DELAY Duration String Нет 1 second Задержка при попытках переподключения к Consul.
DATA_MODEL_JOURNAL_MODE String Нет WriteToJournal Режим журналирования Nestor. Допустимые значения: WriteToJournal (Отправка в сервис журналирования), WriteToTopic (Отправка события в очередь).
DATA_MODEL_JOURNAL_TOPIC String Да, если переменная DATA_MODEL_JOURNAL_MODE = WriteToTopic Название очереди журналирования. Для режима WriteToJournal значение игнорируется.

Команды сервиса Data-model

Список реализованных в сервисе команд, моделей EntityType и действий Actions, которые можно использовать при настройке авторизации.
Не все поля EntityType доступны для использования в настройке авторизации.
Если указан прочерк "-", то данное значение не влияет на авторизацию:

Назначение команды Имя вызова команды EntityType Actions
Получение типов полей для сущностей модели данных. getFieldTypes - DataModel_GetFieldTypes
Получение типов отношений между сущностями в модели данных. getRelationTypes - DataModel_GetRelationTypes
Создание или изменение модели данных с использованием миграции. createDataModel - DataModel_CreateModel
Получение описания модели данных для конкретной сущности в виде JSON-Schema. getDataModel - DataModel_GetModel
Получение созданных типов сущностей. listDataModels - DataModel_GetDataModel
Получение JSON-Schema для всех моделей данных. getAllDataModels - DataModel_GetAllModels
Получение примера объекта сущности. getExampleObject - DataModel_GetExampleObj
Сохранение объекта сущности. saveObject Произвольный EntityType из ObjectStorage. DataModel_SaveObject
Сохранение списка объектов сущности. saveObjectBatch - -
Сохранение списка объектов сущности. saveObjectBatchV2 - -
Сохранение объекта сущности, полученного из внешнего источника. saveExternalObject - DataModel_SaveExternalObj
Получение данных объекта сущности. getObject Произвольный EntityType из ObjectStorage. DataModel_GetObject
Получение данных объекта сущности. internalGetObject - -
Получение данных объектов по их ID и типу сущности. getObjectsBatch - DataModel_GetObjects
Получение данных объекта сущности. richGetObject Произвольный EntityType из ObjectStorage. DataModel_RichGetObject
Получение данных объекта сущности. internalRichGetObject - -
Получение данных объектов по их ID, типу сущности и списку требуемых полей. richGetObjectsBatch Произвольный EntityType из ObjectStorage. DataModel_RichGetObjectsBatch
Получение данных объекта сущности. getExternalObject - DataModel_GetExternalObj
Изменение объекта сущности. updateObject Произвольный EntityType из ObjectStorage. DataModel_UpdateObj
Изменение полей в объекте сущности. updateObjectFields Произвольный EntityType из ObjectStorage. DataModel_UpdateObjField
Изменение полей в объекте сущности. internalUpdateObjectFields - -
Массовое изменение полей в объектах сущности, попадающих под списочный запрос. updateObjectFieldsList Произвольный EntityType из ObjectStorage. DataModel_UpdateObjFieldList
Массовое изменение полей в объектах сущности по ID объектов. updateObjectFieldsBatch Произвольный EntityType из ObjectStorage. DataModel_UpdateObjFieldBatch
Изменение внешнего объекта. updateExternalObject Произвольный EntityType из ObjectStorage. DataModel_UpdateExternalObj
Отмечает в БД объект сущности как удаленный. softDeleteObject Произвольный EntityType из ObjectStorage. DataModel_DeleteObject
Удаление объекта сущности. deleteObject Произвольный EntityType из ObjectStorage. DataModel_DeleteObject
Отмечает в БД сущности из списка как удаленные. softDeleteObjectBatch - -
Удаление объектов сущностей по списку. deleteObjectBatch - -
Отмечает сущности полученные поиском по реестру как удаленные. softDeleteObjectSearch Произвольный EntityType из ObjectStorage. -
Удаление объектов сущности поиском по реестру. deleteObjectSearch Произвольный EntityType из ObjectStorage. -
Удаление внешнего объекта сущности. deleteExternalObject - DataModel_DeleteExternal
Сохранение дополнительных полей объекта сущности. saveAdditionalInfo - DataModel_SaveInfo
Сохранение метаданных объекта сущности. saveObjectMetadata - -
Сохранение метаданных объектов сущностей батчем. saveObjectMetadataBatch - -
Добавление информации о дополнительных файлах файловых полей. saveFilesAdditionalInfo - DataModel_SaveFilesInfo
Привязывание дополнительных файлов к исходным. saveFilesAdditionalInfoV2 - DataModel_SaveFilesInfo
Получение списка объектов запрашиваемой сущности. listObjects Произвольный EntityType (берется на проверку из input.entityType) из ObjectStorage. DataModel_ListObjects
Получение списка объектов запрашиваемой сущности. internalListObjects - -
Получение списка объектов запрашиваемой сущности. richListObjects - DataModel_RichListObjects
Получение списка объектов запрашиваемой сущности. internalRichListObjects - -
Получение списка метаданных объектов запрашиваемой сущности. listObjectsMeta Произвольный EntityType (берется на проверку из input.entityType) из ObjectStorage. DataModel_ListObjMeta
Получение списка наименований объектов. listObjectTitles - DataModel_ListObjTitles
Получение списка наименований объектов. listObjectTitlesV2 Произвольный EntityType (берется на проверку из input.entityType) из ObjectStorage. DataModel_ListObjTitles
Получение позиции объекта в списке объектов. getObjectPosition - DataModel_GetObjPosition
Получения списка ID файлов, которые отсутствуют в сервисе. listNonExistingFileId - -
Получение статистики полей модели данных. getEntityFieldAggregation - DataModel_GetFieldAggregation
Сохранение отношения между объектами двух сущностей. saveRelation - DataModel_SaveRelation
Сохранение отношения между объектами двух сущностей. internalSaveRelation - -
Сохранение нескольких отношений между объектами двух сущностей. saveRelationBatch - DataModel_SaveRelations
Сохранение нескольких отношений между объектами двух сущностей. internalSaveRelationBatch - -
Получение отношения между объектами двух сущностей. getRelation - DataModel_GetRelation
Получение всех отношений объекта с указанной сущностью. listRelations Произвольный EntityType (берется на проверку из input.entityType и input.relatedEntityType) из ObjectStorage. DataModel_ListRelations
Массовое получение всех отношений объекта с указанной сущностью. listRelationsBatch Произвольный EntityType (берется на проверку из input.entityType и input.relatedEntityType) из ObjectStorage. DataModel_ListRelations
Получение всех отношений объекта. listAllRelations Произвольный EntityType (берется на проверку из input.entityType) из ObjectStorage. DataModel_ListAllRelations
Удаление отношения между объектами двух сущностей. deleteRelation - DataModel_DeleteRelation
Удаление отношений объекта с перечисленными сущностями. deleteRelations - DataModel_DeleteRelations
Удаление всех отношений объекта. deleteAllRelations - DataModel_DeleteAllRelations
Обновление списка отношений одного объекта с указанной сущностью. updateExternalRelations Произвольный EntityType из ObjectStorage. DataModel_UpdateExternalObjectRelations
Переиндексация объекта. reindexObject Произвольный EntityType из ObjectStorage. DataModel_ReindexObject
Получение связи между объектами по ID. getObjectLink - DataModel_GetLink
Получение всех связей объекта. getObjectLinks - DataModel_GetLinks
Получение всех связей между указанными типами. listRelationsByType Произвольный EntityType (берется на проверку из input.entityFrom и input.entityTo) из ObjectStorage. DataModel_ListRelations
Получение связи между объектами по ID. createObjectLink - DataModel_CreateLink
Создание связей между объектами. createObjectsLinks - DataModel_CreateLinks
Удаление связи между объектами по ID. deleteObjectLink - DataModel_DeleteLink
Удаление связей объекта. deleteAllObjectLinks - DataModel_DeleteAllLinks
Получение списка подробной информацией с тегами и родительском объекте файлов. listFilesInfoWithTags - DataModel_ViewFiles
Получение списка тегов с количеством файлов. listTagsWithFilesCount - DataModel_ViewFiles
Получение списка уникальных расширений загруженных в систему файлов. listFileExtensions - DataModel_ViewFileExtensions
Перезаписывание текущих тегов файлов объекта новым списком. writeFileTags - DataModel_WriteFileTags
Удаление тегов из текущего набора тегов для файла объекта. removeFileTags - DataModel_RemoveFileTags
Удаление всех тегов для указанных файлов. removeAllFileTags - DataModel_RemoveAllFileTags
Получение родительских сущностей сущности. getEntityParents - DataModel_GetParents
Скачивание файла. getFile Произвольный EntityType из ObjectStorage. DataModel_GetFile
Перезаписывание текущих ключевых слов объекта новым списком слов. updateKeywords Произвольный EntityType из ObjectStorage. -
Получение ключевых слов объекта. listObjectKeywords - DataModel_ListObjectKeywords
Получение по параметрам поискового запроса списка ключевых слов. listKeywords - DataModel_ListKeywords
Получение максимального значения для поля объекта из data или additionalData. internalGetMaxNumericFieldValue - -

GetFieldTypes (Data-model command)

На выходе

[
  {
    "id": "string",
    "description": "Строка",
    "databaseType": "Varchar(64)",
    "settings": {}
  },
  {
    "id": "dateTime",
    "description": "Дата/время",
    "databaseType": "DateTime",
    "settings": {}
  }
]

Получение списка доступных типов полей для сущностей модели данных.

Имя команды для вызова: getFieldTypes.
Поддерживается только синхронный вызов.
Результат выполнения команды не журналируется.

GetRelationTypes (Data-model command)

На выходе

[
  {
    "id": "one-to-one",
    "title": "1 к 1",
    "description": "Один к одному"
  },
  {
    "id": "many-to-one",
    "title": "Многие к 1",
    "description": "Многие к одному"
  },
  {
    "id": "many-to-many",
    "title": "Многие ко многим",
    "description": "Многие ко многим"
  }
]

Получение доступных типов отношений между сущностями в модели данных.

Имя команды для вызова: getRelationTypes.
Поддерживается только синхронный вызов.
Результат выполнения команды не журналируется.

CreateDataModel (Data-model command)

На входе MigrationDSL в виде списка операций

[
  {
    "operation": "CreateEntity",
    "entityType": "Order",
    "title": "Договор",
    "settings": {
      "titleRule": "title"
    }
  },
  {
    "operation": "AddField",
    "entityType": "Order",
    "fieldId": "date",
    "fieldType": "dateTime",
    "title": "Дата договора",
    "description": "Дата заключения договора",
    "example": 1582966800,
    "nullable": false
  },
  {
    "operation": "AddField",
    "entityType": "Order",
    "fieldId": "number",
    "fieldType": "number",
    "title": "Номер договора",
    "example": 555,
    "nullable": false
  },
  {
    "operation": "AddField",
    "entityType": "Order",
    "fieldId": "title",
    "fieldType": "string",
    "title": "Название договора",
    "example": "Договор аренды",
    "nullable": false,
    "settings": {
      "maxLength": 200
    }
  },
  {
    "operation": "AddField",
    "entityType": "Order",
    "fieldId": "places",
    "fieldType": "catalog",
    "title": "Места заключения договора",
    "nullable": true,
    "settings": {
      "code": "city",
      "multiple": true
    }
  },
  {
    "operation": "CreateEntity",
    "entityType": "Person",
    "title": "Человек"
  },
  {
    "operation": "AddField",
    "entityType": "Person",
    "fieldId": "name",
    "fieldType": "string",
    "title": "ФИО",
    "nullable": false
  },
  {
    "operation": "AddRelation",
    "relationType": "many-to-one",
    "entity1": "Order",
    "entity2": "Person",
    "title1": "Автор договора",
    "title2": "Договора автора",
    "entity1Field": "author",
    "entity2Field": "orders",
    "entity1Settings": {
      "dependencies": [
        {
          "priority": 1,
          "dependencyType": "autofill",
          "dependentFieldCode": "places",
          "dependentEntityTypeRelationField": "authorPlaces"
        }
      ]
    },
    "entity2Settings": {}
  }
]

На выходе признак успешного создания модели данных

true

Создание или изменение модели данных с использованием Migration DSL. Может использоваться для создания новых сущностей или для модификации уже существующих. Фактически, команда применяет переданную ей миграцию для модели данных, модифицируя текущую. Migration DSL позволяет описать создание или изменение модели данных в виде последовательности операций/шагов.

Доступные операции Migration DSL:

Каждой операции соответствует JSON-объект, список которых и образует MigrationDSL-запрос на создание модели данных. Объекты для операций указаны возле них в списке. Они различаются по коду операции, передаваемому в поле operation. Все объекты для описания шагов наследуются от общего типа MigrationDslOperation. Команда получает текущее состояние схемы МД, проверяет, какие из MigrationDslOperation еще не применялись и пробует их применить.

Порядок операций важен! Нельзя добавить поле перед созданием сущности.

Имя команды для вызова: createDataModel.
Поддерживается асинхронный и синхронный вызов.
Результат выполнения команды журналируется.

GetDataModel (Data-model command)

На входе код типа сущностей

"Order"

На выходе JSON-schema

{
  "$schema": "https://json-schema.org/draft/2019-09/schema",
  "definitions": {
    "date": {
      "type": "integer",
      "minimum": 0
    },
    "relation": {
      "type": "string",
      "format": "uuid"
    },
    "catalog": {
      "type": "string",
      "format": "uuid"
    },
    "multi-catalog": {
      "type": "array",
      "items": {
        "type": "string",
        "format": "uuid"
      }
    },
    "file": {
      "type": "object",
      "properties": {
        "fileId": {
          "type": "string",
          "format": "uuid"
        },
        "name": {
          "type": "string"
        },
        "extension": {
          "type": "string"
        },
        "size": {
          "type": "integer",
          "minimum": 0
        },
        "url": {
          "type": "string"
        },
        "additional": {
          "type": "object"
        },
        "created": {
          "type": "integer",
          "minimum": 0
        },
        "modified": {
          "type": "integer",
          "minimum": 0
        },
        "md5": {
          "type": "string",
          "pattern": "^[0-9a-fA-F]{32}$"
        }
      },
      "required": [
        "fileId"
      ]
    }
  },
  "relations": [
    {
      "name": "Order_to_Person_on_author",
      "entity1": "Order",
      "entity2": "Person",
      "relationType": "many-to-one",
      "entity1Field": "author",
      "entity2Field": "orders"
    }
  ],
  "type": "object",
  "properties": {
    "author": {
      "$ref": "#/definitions/relation",
      "additional": false,
      "rawType": "relation",
      "nullable": true,
      "readOnly": true,
      "multiple": false,
      "title": "Authorship",
      "to": "Person",
      "settings": {
        "dependencies": [],
        "to": "Person"
      }
    },
    "date": {
      "$ref": "#/definitions/date",
      "title": "Дата",
      "description": "Дата/время",
      "additional": false,
      "rawType": "dateTime"
    },
    "number": {
      "type": "number",
      "description": "Число",
      "additional": false,
      "rawType": "number"
    },
    "places": {
      "$ref": "#/definitions/multi-catalog",
      "code": "city",
      "multiple": true,
      "title": "Места заключения договора",
      "additional": false,
      "rawType": "catalog",
      "settings": {
        "code": "city",
        "multiple": true
      }
    },
    "title": {
      "type": "string",
      "maxLength": 200,
      "title": "Название договора",
      "additional": false,
      "rawType": "string",
      "example": "Договор аренды",
      "exampleType": "string",
      "settings": {
        "maxLength": 200
      }
    }
  },
  "required": [
    "date",
    "number",
    "title"
  ],
  "settings": {
    "titleRule": "title",
    "revisionConfig": {
      "parentFieldCode": "document",
      "actualityFieldCode": "isActual"
    }
  }
}

Или ошибка, если такой модели данных не существует

{
  "businessError": null,
  "message": "ERROR: Entity object not found",
  "stackTrace": null,
  "data": null
}

Получение описания модели данных для конкретной сущности в виде JSON-Schema.

Имя команды для вызова: getDataModel.
Поддерживается только синхронный вызов.
Результат выполнения команды не журналируется.

ListDataModels (Data-model command)

На выходе

[
  {
    "id": "Order",
    "title": "Договор",
    "description": "Описывает договор между несколькими агентами",
    "settings": {
      "titleRule": "title"
    }
  },
  {
    "id": "Person",
    "title": "Человек",
    "description": "Дополнительные человеческие аттрибуты для пользователя",
    "settings": {}
  }
]

Получение созданных типов сущностей.

Имя команды для вызова: listDataModels.
Поддерживается только синхронный вызов.
Результат выполнения команды не журналируется.

GetAllDataModels (Data-model command)

На выходе

{
  "$schema": "https://json-schema.org/draft/2019-09/schema",
  "definitions": {
    "date": {
      "type": "integer",
      "minimum": 0
    },
    "relation": {
      "type": "string",
      "format": "uuid"
    },
    "catalog": {
      "type": "string",
      "format": "uuid"
    },
    "multi-catalog": {
      "type": "array",
      "items": {
        "type": "string",
        "format": "uuid"
      }
    },
    "file": {
      "type": "object",
      "properties": {
        "fileId": {
          "type": "string",
          "format": "uuid"
        },
        "name": {
          "type": "string"
        },
        "extension": {
          "type": "string"
        },
        "size": {
          "type": "integer",
          "minimum": 0
        },
        "url": {
          "type": "string"
        },
        "additional": {
          "type": "object"
        },
        "created": {
          "type": "integer",
          "minimum": 0
        },
        "modified": {
          "type": "integer",
          "minimum": 0
        },
        "md5": {
          "type": "string",
          "pattern": "^[0-9a-fA-F]{32}$"
        }
      },
      "required": [
        "fileId"
      ]
    },
    "Person": {
      "type": "object",
      "properties": {
        "name": {
          "type": "string",
          "maxLength": 64,
          "description": "Строка",
          "additional": false,
          "rawType": "string"
        }
      },
      "required": [
        "name"
      ],
      "settings": {}
    },
    "Order": {
      "type": "object",
      "properties": {
        "number": {
          "type": "number",
          "description": "Число",
          "additional": false,
          "rawType": "number"
        },
        "date": {
          "$ref": "#/definitions/date",
          "description": "Дата/время",
          "additional": false,
          "rawType": "dateTime"
        },
        "author": {
          "$ref": "#/definitions/relation",
          "additional": false,
          "rawType": "relation",
          "nullable": true,
          "readOnly": true,
          "multiple": false,
          "title": "Authorship",
          "to": "Person",
          "settings": {
            "dependencies": [],
            "to": "Person"
          }
        }
      },
      "required": [
        "number",
        "date"
      ],
      "settings": {}
    }
  },
  "relations": [
    {
      "name": "Order_to_Person_on_author",
      "entity1": "Order",
      "entity2": "Person",
      "relationType": "many-to-one",
      "entity1Field": "author",
      "entity2Field": "orders"
    }
  ],
  "oneOf": [
    {
      "$ref": "#/definitions/Order"
    },
    {
      "$ref": "#/definitions/Person"
    }
  ]
}

Получение JSON-Schema для всех моделей данных.

Имя команды для вызова: getAllDataModels.
Поддерживается только синхронный вызов.
Результат выполнения команды не журналируется.

GetExampleObject (Data-model command)

На входе тип сущности

"Order"

На выходе пример объекта данной сущности

{
  "id": "d4db2633-62c7-4b61-956d-cb5461fe2a3e",
  "externalId": "0000000000000000",
  "entityType": "Order",
  "title": "Order d4db2633-62c7-4b61-956d-cb5461fe2a3e",
  "source": "example",
  "created": 1630326492,
  "modified": 1630326492,
  "data": {
    "date": 1577869200,
    "number": 555,
    "author": "00000000-0000-0000-0000-000000000000"
  },
  "additionalData": {},
  "metadata": {},
  "version": 1,
  "removed": false
}

Получение примера объекта сущности. Объект собирается из примеров полей (example), которые указываются при добавлении поля сущности (AddField).

Генерация полей:

Поле Значение
id Случайный UUID.
externalId 0000000000000000
entityType Равен значению на входе.
title См. ниже.
source example
created Текущий TimeStamp.
modified Текущий TimeStamp.
data Поля этого типа объекта.
additionalData Дополнительные поля этого типа объекта.
version 1

Поле title зависит от поля data.titleRule. Если этого поля нет, то title имеет вид <entityType> <id>.

Значения полей в data зависят от параметра example при создании поля (AddField).

Имя команды для вызова: getExampleObject.
Поддерживается только синхронный вызов.
Результат выполнения команды не журналируется.

SaveObject (Data-model command)

На входе общие свойства сохраняемого объекта и основные атрибуты

{
  "entityType": "Order",
  "source": "manual",
  "attributes": {
    "date": 1577869200,
    "number": 514,
    "itemsRelation": [
      "d1d70690-d972-4ee3-9ec1-ccd972979e72",
      "05c989a2-74cc-4888-a49c-c160bf7f918a"
    ],
    "personRelation": "18b1011b-9db3-4186-a53c-971016030068"
  },
  "createRelations": true
}

Для добавления объекта с файловым полем нужно передать такие входные данные.

{
  "entityType": "NewEntityType",
  "source": "manual",
  "attributes": {
    "someFileField": [
      {
        "fileId": "d22f86e6-7375-44f1-a4c0-681a670a1484"
      }
    ]
  }
}

Id файла можно получить загрузив его в систему с помощью рута apigateway/upload.

На выходе ID созданного объекта

"18b1011b-9db3-4186-a53c-971016030068"

Сохранение объекта сущности.

Имя команды для вызова: saveObject.
Поддерживается асинхронный и синхронный вызов.
Результат выполнения команды журналируется.

SaveObjectBatch (Data-model command)

На входе общие свойства сохраняемых объектов и основные атрибуты

{
  "entityType": "Order",
  "source": "manual",
  "attributes": [
    {
      "date": 1577869200,
      "number": 512,
      "itemsRelation": [
        "d1d70690-d972-4ee3-9ec1-ccd972979e72",
        "05c989a2-74cc-4888-a49c-c160bf7f918a"
      ],
      "personRelation": "18b1011b-9db3-4186-a53c-971016030068"
    },
    {
      "date": 1577869200,
      "number": 513
    },
    {
      "date": 1577869200,
      "number": 514
    }
  ],
  "createRelations": true
}

На выходе список ID созданных объектов

[
  "18b1011b-9db3-4186-a53c-971016030068",
  "20f95899-cd42-4afc-9903-84269db53543",
  "370a9981-ea0a-4830-93fe-e4e27ece167f"
]

Сохранение списка объектов сущности. Порядок в списке возвращаемых идентификаторов соответствует порядку в списке атрибутов attributes.

Имя команды для вызова: saveObjectBatch.
Поддерживается асинхронный и синхронный вызов.
Результат выполнения команды журналируется.

Команда только внутренняя (нельзя вызвать через Api Gateway), не требует аутентификации.

SaveObjectBatchV2 (Data-model command)

На входе общие свойства сохраняемых объектов и основные атрибуты

[
  {
    "entityType": "Order",
    "source": "manual",
    "attributes": {
      "date": 1577869200,
      "number": 512,
      "itemsRelation": [
        "d1d70690-d972-4ee3-9ec1-ccd972979e72",
        "05c989a2-74cc-4888-a49c-c160bf7f918a"
      ],
      "personRelation": "18b1011b-9db3-4186-a53c-971016030068"
    },
    "createRelations": true
  },
  {
    "entityType": "Order",
    "source": "manual",
    "attributes": {
      "date": 1577869200,
      "number": 513
    },
    "metadata": {
      "warnings": []
    },
    "createRelations": true
  },
  {
    "objectId": "370a9981-ea0a-4830-93fe-e4e27ece167f",
    "entityType": "Order",
    "source": "manual",
    "attributes": {
      "date": 1577869200,
      "number": 514
    },
    "metadata": {
      "warnings": []
    },
    "createRelations": true
  }
]

На выходе список ID созданных объектов

[
  "18b1011b-9db3-4186-a53c-971016030068",
  "20f95899-cd42-4afc-9903-84269db53543",
  "370a9981-ea0a-4830-93fe-e4e27ece167f"
]

Сохранение списка объектов сущности. Порядок в списке возвращаемых идентификаторов соответствует исходному порядку.

Имя команды для вызова: saveObjectBatchV2.
Поддерживается асинхронный и синхронный вызов.
Результат выполнения команды журналируется.

Команда только внутренняя (нельзя вызвать через Api Gateway), не требует аутентификации.

SaveExternalObject (Data-model command)

На входе общие свойства сохраняемого объекта и основные атрибуты

{
  "entityType": "Order",
  "externalId": "ExternalOrder",
  "source": "order-client",
  "attributes": {
    "date": 1577869200,
    "number": 514,
    "title": "External Order",
    "itemsRelation": [
      "d1d70690-d972-4ee3-9ec1-ccd972979e72",
      "05c989a2-74cc-4888-a49c-c160bf7f918a"
    ],
    "personRelation": "18b1011b-9db3-4186-a53c-971016030068"
  },
  "createRelations": true
}

На выходе внутренний ID созданного объекта

"18b1011b-9db3-4186-a53c-971016030068"

Сохранение объекта сущности, полученного из внешнего источника.

Имя команды для вызова: saveExternalObject.
Поддерживается асинхронный и синхронный вызов.
Результат выполнения команды журналируется.

Команда только внутренняя (нельзя вызвать через Api Gateway), не требует аутентификации.

GetObject (Data-model command)

На входе ID получаемого объекта и его тип сущности

{
  "entityType": "Order",
  "objectId": "18b1011b-9db3-4186-a53c-971016030068"
}

На выходе данные запрашиваемого объекта

{
  "id": "18b1011b-9db3-4186-a53c-971016030068",
  "externalId": "ExternalOrder",
  "entityType": "Order",
  "title": "Аренда лошади",
  "source": "manual",
  "created": 1630326492,
  "modified": 1630326492,
  "data": {
    "date": 1577869200,
    "number": 514,
    "title": "Аренда лошади",
    "persons": [
      "18b1011b-9db3-4186-a53c-971016030068"
    ],
    "horse": "478bf14a-b1f9-46d4-b7fb-3b7ff3d8ca79",
    "files": {
      "2155c943-5c30-49aa-bc43-28c7447b26eb": "datamodel/Order/18b1011b-9db3-4186-a53c-971016030068"
    }
  },
  "additionalData": {},
  "metadata": {},
  "version": 1,
  "removed": false
}

Пример получения объекта с файловым полем

{
  "id": "5ed35749-c65e-443b-8521-5aa90002e218",
  "externalId": null,
  "entityType": "NewEntityType",
  "title": "NewEntityType 5ed35749-c65e-443b-8521-5aa90002e218",
  "source": "manual",
  "created": 1733812732202,
  "modified": 1733812732202,
  "data": {
    "someFileField": [
      {
        "fileId": "4d3f61a5-fd61-45e2-a397-bd6f55a7df88",
        "name": "rose31.docx",
        "extension": "docx",
        "size": 26070,
        "url": "datamodel\\NewEntityType\\4d3f61a5-fd61-45e2-a397-bd6f55a7df88",
        "additional": {
          "fileContent": "datamodel\\NewEntityType\\601ee896-2002-4ca6-85ac-fb9370ccbddc"
        },
        "created": 1733812732416,
        "modified": 1733812732416,
        "md5": "017D2B9B383249F6F85487A9081906DF"
      }
    ]
  },
  "additionalData": {},
  "metadata": {},
  "version": 1,
  "removed": false
}

Получить файл по указанному url можно, вызвав у apigateway рут /download/\[значение из data.someFileField.url\].

Или ошибка, если объект отсутствует

{
  "businessError": null,
  "message": "ERROR: Entity object not found",
  "stackTrace": null,
  "data": null
}

Получение данных объекта сущности.

Имя команды для вызова: getObject.
Поддерживается только синхронный вызов.
Результат выполнения команды не журналируется.

InternalGetObject (Data-model command)

На входе ID получаемого объекта и его тип сущности

{
  "entityType": "Order",
  "objectId": "18b1011b-9db3-4186-a53c-971016030068"
}

На выходе данные запрашиваемого объекта

{
  "id": "18b1011b-9db3-4186-a53c-971016030068",
  "externalId": "ExternalOrder",
  "entityType": "Order",
  "title": "Аренда лошади",
  "source": "manual",
  "created": 1630326492,
  "modified": 1630326492,
  "data": {
    "date": 1577869200,
    "number": 514,
    "title": "Аренда лошади",
    "persons": [
      "18b1011b-9db3-4186-a53c-971016030068"
    ],
    "horse": "478bf14a-b1f9-46d4-b7fb-3b7ff3d8ca79",
    "files": {
      "2155c943-5c30-49aa-bc43-28c7447b26eb": "datamodel/Order/18b1011b-9db3-4186-a53c-971016030068"
    }
  },
  "additionalData": {},
  "metadata": {},
  "version": 1,
  "removed": false
}

Или ошибка, если объект отсутствует

{
  "businessError": null,
  "message": "ERROR: Entity object not found",
  "stackTrace": null,
  "data": null
}

Получение данных объекта сущности. В отличии от команды getObject, в этой команде не проверяется авторизация.

Имя команды для вызова: internalGetObject.
Поддерживается только синхронный вызов.
Результат выполнения команды не журналируется.

Команда только внутренняя (нельзя вызвать через Api Gateway) и отличается от внешней getObject только отсутствием аутентификации.

GetObjectsBatch (Data-model command)

На входе список из ID и типов сущности получаемых объектов

[
  {
    "entityType": "Order",
    "objectId": "18b1011b-9db3-4186-a53c-971016030068"
  },
  {
    "entityType": "Person",
    "objectId": "c11df8f6-e8be-4e8e-a815-40e0d0a0cfb6"
  }
]

На выходе список объектов

[
  {
    "id": "18b1011b-9db3-4186-a53c-971016030068",
    "externalId": "ExternalOrder",
    "entityType": "Order",
    "title": "Аренда лошади",
    "source": "manual",
    "created": 1630326492,
    "modified": 1630326492,
    "data": {
      "date": 1577869200,
      "number": 514,
      "title": "Аренда лошади"
    },
    "additionalData": {},
    "metadata": {},
    "version": 1,
    "removed": false
  },
  {
    "id": "c11df8f6-e8be-4e8e-a815-40e0d0a0cfb6",
    "externalId": null,
    "entityType": "Person",
    "title": "Person c11df8f6-e8be-4e8e-a815-40e0d0a0cfb6",
    "source": "manual",
    "created": 1645526774115,
    "modified": 1645526774115,
    "data": {
      "name": "Строка длиной не больше 64",
      "orders": [
        "18b1011b-9db3-4186-a53c-971016030068"
      ]
    },
    "additionalData": {},
    "metadata": {},
    "version": 1,
    "removed": false
  }
]

Получение данных объектов по их ID и типу сущности. Порядок объектов в ответе совпадает с порядком идентификаторов в запросе.

Имя команды для вызова: getObjectsBatch.
Поддерживается только синхронный вызов.
Результат выполнения команды не журналируется.

RichGetObject (Data-model command)

На входе ID получаемого объекта, тип его сущности и необходимые поля

{
  "id": {
    "entityType": "Order",
    "objectId": "18b1011b-9db3-4186-a53c-971016030068"
  },
  "fields": [
    "person.title",
    "number",
    "date"
  ],
  "fieldSearches": {
    "person": {
      "query": "title",
      "context": {
        "title": "John"
      }
    }
  }
}

На выходе данные запрашиваемого объекта

{
  "id": "18b1011b-9db3-4186-a53c-971016030068",
  "externalId": "ExternalOrder",
  "entityType": "Order",
  "title": "Аренда лошади",
  "source": "manual",
  "created": 1630326492,
  "modified": 1630326492,
  "data": {
    "person": {
      "_id": "478bf14a-b1f9-46d4-b7fb-3b7ff3d8ca79",
      "_externalId": null,
      "_entityType": "Person",
      "_title": "John",
      "_source": "manual",
      "_created": 1634553248859,
      "_modified": 1634553248859,
      "_version": 1
    },
    "number": 514,
    "date": 1577869200
  },
  "additionalData": {},
  "metadata": {},
  "version": 1,
  "removed": false
}

Или ошибка, если объект отсутствует

{
  "businessError": null,
  "message": "ERROR: Entity object not found",
  "stackTrace": null,
  "data": null
}

Или ошибка, если какое-либо из запрашиваемых полей отсутствует в JSON schema

{
  "businessError": null,
  "message": "ERROR: fields [first_field,second_field] for entityType 'Order' not found",
  "stackTrace": null,
  "data": null
}

Получение данных объекта сущности.

Для указания списка допустимых полей см. Методы Rich*.

Имя команды для вызова: richGetObject.
Поддерживается только синхронный вызов.
Результат выполнения команды не журналируется.

InternalRichGetObject (Data-model command)

На входе ID получаемого объекта, тип его сущности и необходимые поля

{
  "id": {
    "entityType": "Order",
    "objectId": "18b1011b-9db3-4186-a53c-971016030068"
  },
  "fields": [
    "person.title",
    "number",
    "date"
  ],
  "fieldSearches": {
    "person": {
      "query": "title",
      "context": {
        "title": "John"
      }
    }
  }
}

На выходе данные запрашиваемого объекта

{
  "id": "18b1011b-9db3-4186-a53c-971016030068",
  "externalId": "ExternalOrder",
  "entityType": "Order",
  "title": "Аренда лошади",
  "source": "manual",
  "created": 1630326492,
  "modified": 1630326492,
  "data": {
    "person": {
      "_id": "478bf14a-b1f9-46d4-b7fb-3b7ff3d8ca79",
      "_externalId": null,
      "_entityType": "Person",
      "_title": "John",
      "_source": "manual",
      "_created": 1634553248859,
      "_modified": 1634553248859,
      "_version": 1
    },
    "number": 514,
    "date": 1577869200
  },
  "additionalData": {},
  "metadata": {},
  "version": 1,
  "removed": false
}

Или ошибка, если объект отсутствует

{
  "businessError": null,
  "message": "ERROR: Entity object not found",
  "stackTrace": null,
  "data": null
}

Или ошибка, если какое-либо из запрашиваемых полей отсутствует в JSON schema

{
  "businessError": null,
  "message": "ERROR: fields [first_field,second_field] for entityType 'Order' not found",
  "stackTrace": null,
  "data": null
}

Получение данных объекта сущности.

Для указания списка допустимых полей см. Методы Rich*.

Имя команды для вызова: internalRichGetObject.
Поддерживается только синхронный вызов.
Результат выполнения команды не журналируется.

Команда только внутренняя (нельзя вызвать через Api Gateway) и отличается от внешней richGetObject только отсутствием аутентификации.

RichGetObjectsBatch (Data-model command)

На входе список из типов сущностей, идентификаторов и требуемых полей у получаемых объектов

[
  {
    "entityType": "Order",
    "ids": [
      "18b1011b-9db3-4186-a53c-971016030068"
    ],
    "fields": [
      "person.title",
      "date",
      "number"
    ],
    "fieldSearches": {}
  },
  {
    "entityType": "Person",
    "ids": [
      "c11df8f6-e8be-4e8e-a815-40e0d0a0cfb6"
    ],
    "fields": [
      "person.title",
      "name",
      "orders"
    ],
    "fieldSearches": {
      "person": {
        "query": "title",
        "context": {
          "title": "John"
        }
      }
    }
  }
]

На выходе список объектов, сгруппированный по типам сущностей

{
  "Order": [
    {
      "id": "18b1011b-9db3-4186-a53c-971016030068",
      "externalId": "ExternalOrder",
      "entityType": "Order",
      "title": "Аренда лошади",
      "source": "manual",
      "created": 1630326492,
      "modified": 1630326492,
      "data": {
        "date": 1577869200,
        "number": 514,
        "person": {
          "_id": "478bf14a-b1f9-46d4-b7fb-3b7ff3d8ca79",
          "_externalId": null,
          "_entityType": "Person",
          "_title": "John",
          "_source": "manual",
          "_created": 1634553248859,
          "_modified": 1634553248859,
          "_version": 1
        }
      },
      "additionalData": {},
      "metadata": {},
      "version": 1,
      "removed": false
    }
  ],
  "Person": [
    {
      "id": "c11df8f6-e8be-4e8e-a815-40e0d0a0cfb6",
      "externalId": null,
      "entityType": "Person",
      "title": "Person c11df8f6-e8be-4e8e-a815-40e0d0a0cfb6",
      "source": "manual",
      "created": 1645526774115,
      "modified": 1645526774115,
      "data": {
        "orders": [
          "18b1011b-9db3-4186-a53c-971016030068"
        ],
        "name": "Строка длиной не больше 64",
        "person": {
          "_id": "478bf14a-b1f9-46d4-b7fb-3b7ff3d8ca79",
          "_externalId": null,
          "_entityType": "Person",
          "_title": "John",
          "_source": "manual",
          "_created": 1634553248859,
          "_modified": 1634553248859,
          "_version": 1
        }
      },
      "additionalData": {},
      "metadata": {},
      "version": 1,
      "removed": false
    }
  ]
}

Получение данных объектов по их ID, типу сущности и списку требуемых полей. Порядок объектов в ответе совпадает с порядком идентификаторов в запросе.

Для указания списка допустимых полей см. Методы Rich*.

Имя команды для вызова: richGetObjectsBatch.
Поддерживается только синхронный вызов.
Результат выполнения команды не журналируется.

GetExternalObject (Data-model command)

На входе внешний ID получаемого объекта и его тип сущности

{
  "entityType": "Order",
  "externalId": "ExternalOrder"
}

На выходе данные запрашиваемого объекта

{
  "id": "982fa393-423b-4e6b-8e7d-d2b65ff061c8",
  "externalId": "ExternalOrder",
  "entityType": "Order",
  "title": "External Order",
  "source": "order-client",
  "created": 1639748410280,
  "modified": 1639748410280,
  "data": {
    "date": 1577869200,
    "title": "External Order",
    "number": 514
  },
  "additionalData": {},
  "metadata": {},
  "version": 1,
  "removed": false
}

Получение данных объекта сущности.

Имя команды для вызова: getExternalObject.
Поддерживается только синхронный вызов.
Результат выполнения команды не журналируется.

Команда только внутренняя (нельзя вызвать через Api Gateway), не требует аутентификации.

UpdateObject (Data-model command)

На входе общие свойства сохраняемого объекта и основные атрибуты

{
  "entityType": "Order",
  "objectId": "18b1011b-9db3-4186-a53c-971016030068",
  "version": 2,
  "attributes": {
    "date": 1577869200,
    "number": 514,
    "itemsRelation": [
      "d1d70690-d972-4ee3-9ec1-ccd972979e72",
      "05c989a2-74cc-4888-a49c-c160bf7f918a"
    ],
    "personRelation": "18b1011b-9db3-4186-a53c-971016030068"
  },
  "createRelations": true
}

На выходе признак успешного сохранения

true

Или ошибка, если объект не существует

{
  "businessError": null,
  "message": "ERROR: Entity object not found",
  "stackTrace": null,
  "data": null
}

Или ошибка, если объект был обновлен из другого места

{
  "businessError": null,
  "message": "ERROR: object version is not actual (Optimistic Lock)",
  "stackTrace": null,
  "data": null
}

Изменение объекта сущности. Использует оптимистичную блокировку. Если изменяемый объект был изменен параллельно (например, из другой формы другим пользователем), тогда вернется ошибка ERROR: object version is not actual (Optimistic Lock), показывающая, что не произошло обновления из-за некорректной версии.

Имя команды для вызова: updateObject.
Поддерживается асинхронный и синхронный вызов.
Результат выполнения команды журналируется.

UpdateObjectFields (Data-model command)

На входе общие свойства обновляемого объекта, а также JSON-объект, где ключ - это изменяемое поле, а значение - новое значение этого поля

{
  "entityType": "Order",
  "objectId": "18b1011b-9db3-4186-a53c-971016030068",
  "version": 2,
  "updates": {
    "date": 1577869200,
    "title": "External Order",
    "itemsRelation": [
      "d1d70690-d972-4ee3-9ec1-ccd972979e72",
      "05c989a2-74cc-4888-a49c-c160bf7f918a"
    ],
    "personRelation": "18b1011b-9db3-4186-a53c-971016030068"
  },
  "createRelations": true
}

На выходе признак успешного сохранения

true

Или ошибка, если объект не существует

{
  "businessError": null,
  "message": "ERROR: Entity object not found",
  "stackTrace": null,
  "data": null
}

Или ошибка, если объект был обновлен из другого места

{
  "businessError": null,
  "message": "ERROR: object version is not actual (Optimistic Lock)",
  "stackTrace": null,
  "data": null
}

Изменение полей в объекте сущности. Если поле нужно удалить, то его значение указывается как null.
Использует оптимистичную блокировку. Если изменяемый объект был изменен параллельно (например, из другой формы другим пользователем), тогда вернется ошибка ERROR: object version is not actual (Optimistic Lock), показывающая, что не произошло обновления из-за некорректной версии.

Имя команды для вызова: updateObjectFields.
Поддерживается асинхронный и синхронный вызов.
Результат выполнения команды журналируется.

InternalUpdateObjectFields (Data-model command)

Имя команды для вызова: internalUpdateObjectFields.
Поддерживается асинхронный и синхронный вызов.
Результат выполнения команды журналируется.

Команда только внутренняя (нельзя вызвать через Api Gateway).

Логика команды и вход/выход идентичен UpdateObjectFields.

UpdateObjectFieldsList (Data-model command)

На входе параметры списочного запроса, а также JSON-объект, где ключ - это изменяемое поле, а значение - новое значение этого поля

{
  "entityType": "Order",
  "search": {
    "query": "title",
    "context": {
      "title": "External Order"
    }
  },
  "updates": {
    "date": 1577869200,
    "title": "Updated External Order",
    "itemsRelation": [
      "d1d70690-d972-4ee3-9ec1-ccd972979e72",
      "05c989a2-74cc-4888-a49c-c160bf7f918a"
    ],
    "personRelation": "18b1011b-9db3-4186-a53c-971016030068"
  },
  "createRelations": true
}

На выходе количество измененных объектов

42

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

Имя команды для вызова: updateObjectFieldsList.
Поддерживается асинхронный и синхронный вызов.
Результат выполнения команды не журналируется.

Команда только внутренняя (нельзя вызвать через Api Gateway), не требует аутентификации.

Для фильтрации по полям сущности подробности описаны тут.

UpdateObjectFieldsBatch (Data-model command)

На входе перечень ID обновляемых объектов, а также JSON-объект, где ключ - это изменяемое поле, а значение - новое значение этого поля

{
  "entityType": "Order",
  "objectIds": [
    "0808bb23-3e32-4fea-b682-a8287b5f7d05",
    "6895b246-ecb5-4a9b-8094-ed4aeabf2c46"
  ],
  "updates": {
    "date": 1577869200,
    "title": "Updated External Order"
  }
}

На выходе результаты обновления по каждому отдельному объекту

[
  {
    "entityId": "Order",
    "objectId": "0808bb23-3e32-4fea-b682-a8287b5f7d05",
    "result": true
  },
  {
    "entityId": "Order",
    "objectId": "6895b246-ecb5-4a9b-8094-ed4aeabf2c46",
    "result": false,
    "error": "ERROR: Entity object not found",
    "errorCode": 404
  }
]

Массовое изменение полей в объектах сущности по ID объектов.

Имя команды для вызова: updateObjectFieldsBatch.
Поддерживается асинхронный и синхронный вызов.
Результат выполнения команды не журналируется.

Команда только внутренняя (нельзя вызвать через Api Gateway), не требует аутентификации.

UpdateExternalObject (Data-model command)

На входе общие свойства сохраняемого объекта и основные атрибуты

{
  "entityType": "Order",
  "externalId": "ExternalOrder",
  "attributes": {
    "date": 1577869200,
    "number": 514,
    "title": "External Order v2",
    "itemsRelation": [
      "d1d70690-d972-4ee3-9ec1-ccd972979e72",
      "05c989a2-74cc-4888-a49c-c160bf7f918a"
    ],
    "personRelation": "18b1011b-9db3-4186-a53c-971016030068"
  },
  "createRelations": true
}

На выходе признак успешного сохранения

true

Изменение внешнего объекта.

Имя команды для вызова: updateExternalObject.
Поддерживается асинхронный и синхронный вызов.
Результат выполнения команды журналируется.

Команда только внутренняя (нельзя вызвать через Api Gateway), не требует аутентификации.

SoftDeleteObject (Data-model command)

На входе ID получаемого объекта и его тип сущности

{
  "entityType": "Order",
  "objectId": "18b1011b-9db3-4186-a53c-971016030068"
}

На выходе признак успешного удаления

true

Или ошибка, если объекта не существует

{
  "businessError": null,
  "message": "ERROR: Entity object not found",
  "stackTrace": null,
  "data": null
}

Отмечает в БД объект сущности как удаленный. Из-за этого файлы, ссылки и отношения, связанные с этим объектом, не будут участвовать в командах на получение данных ( кроме команд internalGetObject и internalRichGetObject).

Генерируемые события будут созданы как и при обычном удалении.

Имя команды для вызова: softDeleteObject.
Поддерживается асинхронный и синхронный вызов.
Результат выполнения команды журналируется.

DeleteObject (Data-model command)

На входе ID получаемого объекта и его тип сущности

{
  "entityType": "Order",
  "objectId": "18b1011b-9db3-4186-a53c-971016030068"
}

На выходе признак успешного удаления

true

Или ошибка, если объекта не существует

{
  "businessError": null,
  "message": "ERROR: Entity object not found",
  "stackTrace": null,
  "data": null
}

Удаление объекта сущности. Если у объекта есть связи, они тоже будут удалены.

Имя команды для вызова: deleteObject.
Поддерживается асинхронный и синхронный вызов.
Результат выполнения команды журналируется.

SoftDeleteObjectBatch (Data-model command)

На входе список EntityObjectIdentity удаляемых объектов

[
  {
    "entityType": "Patent",
    "objectId": "7cba68ef-10fe-4629-9680-3346e73756bd"
  },
  {
    "entityType": "Document",
    "objectId": "b7bb4a5a-dc0f-4bfc-b7e3-f2258700b47b"
  }
]

На выходе количество успешно удаленных объектов, которые существовали на момент вызова команды

2

Отмечает в БД сущности из списка как удаленные. Из-за этого файлы, ссылки и отношения, связанные с этими объектами, не будут участвовать в командах на получение данных (кроме команд internalGetObject и internalRichGetObject).

Генерируемые события будут созданы как и при обычном удалении.

Принцип работы команды аналогичен работе команды softDeleteObject.

Если входные данные для команды содержит идентификаторы объектов, которые не существуют (например, были удалены ранее или были помечены как удаленные), то считаем что записи отсутствуют и возвращается ошибка с кодом NotFound.

Имя команды для вызова: softDeleteObjectBatch.
Поддерживается асинхронный и синхронный вызов.
Результат выполнения команды журналируется.

Команда только внутренняя (нельзя вызвать через Api Gateway), не требует аутентификации.

DeleteObjectBatch (Data-model command)

На входе список EntityObjectIdentity удаляемых объектов

[
  {
    "entityType": "Patent",
    "objectId": "7cba68ef-10fe-4629-9680-3346e73756bd"
  },
  {
    "entityType": "Document",
    "objectId": "b7bb4a5a-dc0f-4bfc-b7e3-f2258700b47b"
  }
]

На выходе количество успешно удаленных объектов, которые существовали на момент вызова команды

2

Удаление объектов сущностей по списку. Если у объектов есть связи, они тоже будут удалены.

Если входные данные для команды содержит идентификаторы объектов, которые не существуют (например, были удалены ранее), то считаем что записи отсутствуют и возвращается ошибка с кодом NotFound.

Позволяет удалять сущности помеченные на удаление.

Имя команды для вызова: deleteObjectBatch.
Поддерживается асинхронный и синхронный вызов.
Результат выполнения команды журналируется.

Команда только внутренняя (нельзя вызвать через Api Gateway), не требует аутентификации.

SoftDeleteObjectSearch (Data-model command)

На входе EntityTypeId и Search для поиска удаляемых объектов

{
  "entityType": "Patent",
  "search": {
    "query": "title",
    "context": {
      "title": "like %48588d61-6c76-48d0-9318-e9dcfcbe688d%"
    }
  }
}

На выходе количество успешно удаленных объектов

2

Или ошибка, если объекта (объектов) не существует

{
  "businessError": null,
  "message": "ERROR: 'Entity object' not found",
  "stackTrace": null,
  "data": null
}

Отмечает сущности полученные поиском по реестру как удаленные. Из-за этого файлы, ссылки и отношения, связанные с этими объектами, не будут участвовать в командах на получение данных (кроме команд internalGetObject и internalRichGetObject).

Генерируемые события будут созданы как и при обычном удалении.

Если во входных данных есть пейджинг или сортировка, то они будут проигнорированы.

Имя команды для вызова: softDeleteObjectSearch.
Поддерживается асинхронный и синхронный вызов.
Результат выполнения команды журналируется.

DeleteObjectSearch (Data-model command)

На входе EntityTypeId и Search для поиска удаляемых объектов

{
  "entityType": "Patent",
  "search": {
    "query": "title",
    "context": {
      "title": "like %48588d61-6c76-48d0-9318-e9dcfcbe688d%"
    }
  }
}

На выходе количество успешно удаленных объектов

2

Или ошибка, если объекта (объектов) не существует

{
  "businessError": null,
  "message": "ERROR: 'Entity object' not found",
  "stackTrace": null,
  "data": null
}

Удаление объектов сущности поиском по реестру.

Имя команды для вызова: deleteObjectSearch.
Поддерживается асинхронный и синхронный вызов.
Результат выполнения команды журналируется.

Запрос принимает параметры фильтров в параметре Search.
Применяется к полям модели ObjectStore.

Доступные поля для фильтрации и виды фильтров по ним:

Поле Виды фильтров
id или objectid InSetQuery, LikeQuery
externalid InSetQuery, LikeQuery
title InSetQuery, LikeQuery
source InSetQuery, LikeQuery
created InSetQuery, LikeQuery, RangeQuery
modified InSetQuery, LikeQuery, RangeQuery

Для фильтрации по полям сущности подробности описаны тут.

DeleteExternalObject (Data-model command)

На входе внешний ID удаляемого объекта и его тип сущности

{
  "entityType": "Order",
  "externalId": "ExternalOrder"
}

На выходе признак успешного удаления

true

Удаление внешнего объекта сущности. Если у объекта есть связи, они тоже будут удалены.

Имя команды для вызова: deleteExternalObject.
Поддерживается асинхронный и синхронный вызов.
Результат выполнения команды журналируется.

Команда только внутренняя (нельзя вызвать через Api Gateway), не требует аутентификации.

SaveAdditionalInfo (Data-model command)

На входе дополнительные свойства сохраняемого объекта и его ID

{
  "entityType": "Order",
  "objectId": "18b1011b-9db3-4186-a53c-971016030068",
  "additionalData": {
    "keywords": [
      "Договор",
      "аренда",
      "лошадь"
    ]
  }
}

На выходе признак успешного сохранения

true

Сохранение дополнительных полей объекта сущности. Дополняет текущий список дополнительных полей новым. Если поле уже есть, тогда перезаписывает. Передавать полный список не нужно.

Имя команды для вызова: saveAdditionalInfo.
Поддерживается асинхронный и синхронный вызов.
Результат выполнения команды не журналируется.

Команда только внутренняя (нельзя вызвать через Api Gateway), не требует аутентификации.

SaveObjectMetadata (Data-model command)

На входе метаданные сохраняемого объекта и его ID

{
  "entityType": "Order",
  "objectId": "18b1011b-9db3-4186-a53c-971016030068",
  "metadata": {
    "warnings": [
      {
        "fieldCode": "code"
      }
    ]
  }
}

На выходе признак успешного сохранения

true

Сохранение метаданных объекта сущности. Полностью обновляет метаданные.

Имя команды для вызова: saveObjectMetadata.
Поддерживается асинхронный и синхронный вызов.
Результат выполнения команды не журналируется.

Команда только внутренняя (нельзя вызвать через Api Gateway), не требует аутентификации.

SaveObjectMetadataBatch (Data-model command)

На входе массив объектов с метаданными сохраняемых объектов и их ID

[
  {
    "entityType": "Tag",
    "objectId": "7e02feee-3453-42b3-b990-1d9ec83fc0d8",
    "metadata": {
      "warnings": [
        {
          "fieldCode": "title"
        }
      ]
    }
  },
  {
    "entityType": "Order",
    "objectId": "18b1011b-9db3-4186-a53c-971016030068",
    "metadata": {
      "warnings": [
        {
          "fieldCode": "code"
        }
      ]
    }
  }
]

На выходе признак успешного сохранения

true

Сохранение метаданных объектов сущностей батчем. Полностью обновляет метаданные.

Имя команды для вызова: saveObjectMetadataBatch.
Поддерживается асинхронный и синхронный вызов.
Результат выполнения команды не журналируется.

Команда только внутренняя (нельзя вызвать через Api Gateway), не требует аутентификации.

SaveFilesAdditionalInfo (Data-model command)

На входе информация о дополнительных файлах файловых полей

{
  "entityType": "Order",
  "objectId": "18b1011b-9db3-4186-a53c-971016030068",
  "data": [
    {
      "field": "documentFile",
      "key": "documentFileContent",
      "files": {
        "2155c943-5c30-49aa-bc43-28c7447b26eb": "datamodel/Order/47fdb0ce-4b1b-4338-ad9b-31ad5c9e2550"
      }
    }
  ]
}

На выходе количество обновленных файлов

1

Имя команды для вызова: saveFilesAdditionalInfo.
Поддерживается асинхронный и синхронный вызов.
Результат выполнения команды не журналируется.

Команда только внутренняя (нельзя вызвать через Api Gateway), не требует аутентификации.

SaveFilesAdditionalInfoV2 (Data-model command)

На входе информация о дополнительных файлах файловых полей

[
  {
    "key": "documentFileContent",
    "files": {
      "2155c943-5c30-49aa-bc43-28c7447b26eb": "datamodel/Order/47fdb0ce-4b1b-4338-ad9b-31ad5c9e2550"
    }
  },
  {
    "key": "anotherFileContent",
    "files": {
      "2155c943-5c30-49aa-bc43-28c7447b26eb": "datamodel/Order/47fdb0ce-4b1b-4338-ad9b-31ad5c9e2550"
    }
  }
]

На выходе количество обновленных файлов

2

Команда привязывает дополнительные файлы к исходным, добавляя их в поле additionalInfo. В отличии от предыдущей версии, команда не требует указывать данные объекта, к которому привязаны исходные файлы.

Имя команды для вызова: saveFilesAdditionalInfoV2.
Поддерживается асинхронный и синхронный вызов.
Результат выполнения команды не журналируется.

Команда только внутренняя (нельзя вызвать через Api Gateway), не требует аутентификации.

ListObjects (Data-model command)

На входе тип сущности объектов и параметры спискового запроса

{
  "entityType": "Order",
  "search": {
    "query": "",
    "context": {},
    "paging": {
      "page": 1,
      "count": 2
    }
  }
}

На выходе странца со списком объектов запрашиваемой сущности с учетом параметров и общее количество элементов

{
  "items": [
    {
      "id": "18b1011b-9db3-4186-a53c-971016030068",
      "externalId": "ExternalOrder",
      "entityType": "Order",
      "title": "Аренда лошади",
      "source": "manual",
      "created": 1630326492,
      "modified": 1630326492,
      "data": {
        "date": 1577869200,
        "number": 514,
        "title": "Аренда лошади"
      },
      "additionalData": {
        "keywords": "Договор, аренда, лошадь"
      },
      "metadata": {},
      "version": 1,
      "removed": false
    },
    {
      "id": "cbf73923-e043-481e-97b2-8ec5968a10ca",
      "externalId": null,
      "entityType": "Order",
      "title": "",
      "source": "import",
      "created": 1630567604,
      "modified": 1630326492,
      "data": {
        "date": 1567330200,
        "number": 321
      },
      "additionalData": {
        "keywords": "Договор, вагон, паровоз"
      },
      "metadata": {},
      "version": 1,
      "removed": false
    }
  ],
  "total": 3
}

Получение списка объектов запрашиваемой сущности. Запрос принимает параметры сортировки, фильтров и пейджинга в параметре Search.

Имя команды для вызова: listObjects.
Поддерживается только синхронный вызов.
Результат выполнения команды не журналируется.

Доступные поля для фильтрации и виды фильтров по ним:

Поле Виды фильтров
id или objectid InSetQuery
externalid InSetQuery
title InSetQuery, LikeQuery
source InSetQuery
created InSetQuery, RangeQuery
modified InSetQuery, RangeQuery

Для фильтрации по полям сущности подробности описаны тут.

Доступные поля для сортировки:

Поле Примечание
id или objectid -
externalid -
title -
modified -
created -
source При сортировке по возрастанию сначала идут Manual, потом Auto.

Если поле sorting отсутствует, то список сортируется по полю created в порядке возрастания.

Если fieldName не совпадает с вышеперечисленными, то список сортируется по этому полю в data.

InternalListObjects (Data-model command)

Имя команды для вызова: internalListObjects.
Поддерживается только синхронный вызов.
Результат выполнения команды не журналируется.

Команда только внутренняя (нельзя вызвать через Api Gateway).

Логика команды и вход/выход идентичен ListObjects command.

RichListObjects (Data-model command)

На входе тип сущности объектов, список необходимых полей и параметры спискового запроса

{
  "entityType": "Order",
  "fields": [
    "number",
    "person.title"
  ],
  "search": {
    "query": "",
    "context": {},
    "paging": {
      "page": 1,
      "count": 2
    }
  },
  "fieldSearches": {
    "person": {
      "query": "title",
      "context": {
        "title": "John"
      }
    }
  }
}

На выходе странца со списком объектов запрашиваемой сущности с учетом параметров и общее количество элементов.

{
  "items": [
    {
      "id": "18b1011b-9db3-4186-a53c-971016030068",
      "externalId": "ExternalOrder",
      "entityType": "Order",
      "title": "Аренда лошади",
      "source": "manual",
      "created": 1630326492,
      "modified": 1630326492,
      "data": {
        "number": 514,
        "person": {
          "_id": "478bf14a-b1f9-46d4-b7fb-3b7ff3d8ca79",
          "_externalId": null,
          "_entityType": "Person",
          "_title": "John",
          "_source": "manual",
          "_created": 1634553248859,
          "_modified": 1634553248859,
          "_version": 1
        }
      },
      "additionalData": {
        "keywords": "Договор, аренда, лошадь"
      },
      "metadata": {},
      "version": 1,
      "removed": false
    },
    {
      "id": "cbf73923-e043-481e-97b2-8ec5968a10ca",
      "externalId": null,
      "entityType": "Order",
      "title": "",
      "source": "import",
      "created": 1630567604,
      "modified": 1630326492,
      "data": {
        "number": 321,
        "person": null
      },
      "additionalData": {
        "keywords": "Договор, вагон, паровоз"
      },
      "metadata": {},
      "version": 1,
      "removed": false
    }
  ],
  "total": 3
}

Получение списка объектов запрашиваемой сущности. В JSON объекте data, для каждого объекта содержатся только указанные в запросе поля.
Запрос принимает параметры сортировки, фильтров и пейджинга в параметре Search.

Для фильтрации/сортировки по relation полям см. Relation поля.
Для указания списка допустимых полей см. Методы Rich*.

Имя команды для вызова: richListObjects.
Поддерживается только синхронный вызов.
Результат выполнения команды не журналируется.

Доступные поля для фильтрации и виды фильтров по ним:

Поле Виды фильтров
id или objectid InSetQuery
externalid InSetQuery
title InSetQuery, LikeQuery
source InSetQuery
created InSetQuery, RangeQuery
modified InSetQuery, RangeQuery

Для фильтрации по полям сущности подробности описаны тут.

Доступные поля для сортировки:

Поле Примечание
id или objectid -
externalid -
title -
modified -
created -
source При сортировке по возрастанию сначала идут Manual, потом Auto.

Если поле sorting отсутствует, то список сортируется по полю created в порядке возрастания.

InternalRichListObjects (Data-model command)

Имя команды для вызова: internalRichListObjects.
Поддерживается только синхронный вызов.
Результат выполнения команды не журналируется.

Команда только внутренняя (нельзя вызвать через Api Gateway).

Логика команды и вход/выход идентичен RichListObjects command.

ListObjectsMeta (Data-model command)

На входе тип сущности объектов и параметры спискового запроса

{
  "entityType": "Order",
  "search": {
    "query": "",
    "context": {},
    "paging": {
      "page": 1,
      "count": 2
    }
  }
}

На выходе странца со списком объектов запрашиваемой сущности с учетом параметров и общее количество элементов

{
  "items": [
    {
      "id": "18b1011b-9db3-4186-a53c-971016030068",
      "entityType": "Order",
      "title": "Аренда лошади",
      "source": "manual",
      "created": 1630326492,
      "modified": 1630326492,
      "version": 1,
      "removed": false
    },
    {
      "id": "cbf73923-e043-481e-97b2-8ec5968a10ca",
      "entityType": "Order",
      "title": "",
      "source": "import",
      "created": 1630567604,
      "modified": 1630326492,
      "version": 1,
      "removed": false
    }
  ],
  "total": 3
}

Получение списка метаданных объектов запрашиваемой сущности. Запрос принимает параметры сортировки, фильтров и пейджинга в параметре Search.

Имя команды для вызова: listObjectsMeta.
Поддерживается только синхронный вызов.
Результат выполнения команды не журналируется.

Доступные поля для фильтрации и виды фильтров по ним:

Поле Виды фильтров
id или objectid InSetQuery
externalid InSetQuery
title InSetQuery, LikeQuery
source InSetQuery
created InSetQuery, RangeQuery
modified InSetQuery, RangeQuery

Для фильтрации по полям сущности подробности описаны тут.

Доступные поля для сортировки:

Поле Примечание
id или objectid -
externalid -
title -
modified -
created -
source При сортировке по возрастанию сначала идут Manual, потом Auto.

Если поле sorting отсутствует, то список сортируется по полю created в порядке возрастания.

Если fieldName не совпадает с вышеперечисленными, то список сортируется по этому полю в data.

ListObjectTitles (Data-model command)

На входе параметры спискового запроса

{
  "query": "",
  "context": {},
  "paging": {
    "page": 1,
    "count": 2
  }
}

На выходе страница со списком объектов запрашиваемой сущности с учетом параметров и общее количество элементов

{
  "items": [
    {
      "entityType": "Order",
      "objectId": "18b1011b-9db3-4186-a53c-971016030068",
      "title": "Аренда лошади"
    },
    {
      "entityType": "Order",
      "objectId": "cbf73923-e043-481e-97b2-8ec5968a10ca",
      "title": ""
    }
  ],
  "total": 3
}

Получение списка наименований объектов с учетом параметров сортировки, фильтров и пейджинга.

Имя команды для вызова: listObjectTitles.
Поддерживается только синхронный вызов.
Результат выполнения команды не журналируется.

Доступные поля для фильтрации и виды фильтров по ним:

Поле Виды фильтров
id или objectid InSetQuery
externalid InSetQuery
title InSetQuery, LikeQuery
source InSetQuery
created InSetQuery, RangeQuery
modified InSetQuery, RangeQuery

Для фильтрации по полям сущности подробности описаны тут.

Доступные поля для сортировки:

Поле Примечание
id или objectid -
externalid -
title -
modified -
created -
source При сортировке по возрастанию сначала идут Manual, потом Auto.

Если поле sorting отсутствует, то список сортируется по полю created в порядке возрастания.

Если fieldName не совпадает с вышеперечисленными, то список сортируется по этому полю в data.

ListObjectTitlesV2 (Data-model command)

На входе тип сущности объектов и параметры спискового запроса

{
  "entityType": "Order",
  "search": {
    "query": "",
    "context": {},
    "paging": {
      "page": 1,
      "count": 2
    }
  }
}

На выходе страница со списком объектов запрашиваемой сущности с учетом параметров и общее количество элементов

{
  "items": [
    {
      "entityType": "Order",
      "objectId": "18b1011b-9db3-4186-a53c-971016030068",
      "title": "Аренда лошади"
    },
    {
      "entityType": "Order",
      "objectId": "cbf73923-e043-481e-97b2-8ec5968a10ca",
      "title": ""
    }
  ],
  "total": 3
}

Получение списка наименований объектов с учетом параметров сортировки, фильтров и пейджинга.

Имя команды для вызова: listObjectTitlesV2.
Поддерживается только синхронный вызов.
Результат выполнения команды не журналируется.

Доступные поля для фильтрации и виды фильтров по ним:

Поле Виды фильтров
id или objectid InSetQuery
externalid InSetQuery
title InSetQuery, LikeQuery
source InSetQuery
created InSetQuery, RangeQuery
modified InSetQuery, RangeQuery

Для фильтрации по полям сущности подробности описаны тут.

Доступные поля для сортировки:

Поле Примечание
id или objectid -
externalid -
title -
modified -
created -
source При сортировке по возрастанию сначала идут Manual, потом Auto.

Если поле sorting отсутствует, то список сортируется по полю created в порядке возрастания.

Если fieldName не совпадает с вышеперечисленными, то список сортируется по этому полю в data.

GetObjectPosition (Data-model command)

На входе тип сущности объекта, ID искомого объекта и параметры спискового запроса

{
  "entityType": "Order",
  "objectId": "cbf73923-e043-481e-97b2-8ec5968a10ca",
  "search": {
    "query": "",
    "context": {},
    "sorting": "title"
  }
}

На выходе позиция объекта в отфильтрованном и отсортированном списке, начиная с 0:

{
  "position": 1,
  "total": 3
}

Получение позиции объекта в списке объектов, с учетом фильтрации и сортировки.

Имя команды для вызова: getObjectPosition.
Поддерживается только синхронный вызов.
Результат выполнения команды не журналируется.

Доступные поля для фильтрации и виды фильтров по ним:

Поле Виды фильтров
id или objectid InSetQuery
externalid InSetQuery
title InSetQuery, LikeQuery
source InSetQuery
created InSetQuery, RangeQuery
modified InSetQuery, RangeQuery

Для фильтрации по полям сущности подробности описаны тут.

Доступные поля для сортировки:

Поле Примечание
id или objectid -
externalid -
title -
modified -
created -
source При сортировке по возрастанию сначала идут Manual, потом Auto.

Если поле sorting отсутствует, то список сортируется по полю created в порядке возрастания.

Если fieldName не совпадает с вышеперечисленными, то список сортируется по этому полю в data.

ListNonExistingFileId (Data-model command)

На входе список идентификаторов ObjectFileMeta, которые нужно проверить на наличие

[
  "00001111-2222-3333-4444-555566667777",
  "184c85c1-9c75-48aa-8052-e96fe29cc026"
]

На выходе список идентификаторов, которые отсутствуют в БД

[
  "00001111-2222-3333-4444-555566667777"
]

Внутренняя команда для получения списка ID файлов, которые отсутствуют в сервисе. Необходима для фильтрации данных полученных из LAMP командами сервиса fullTextSearch: plagiarismSearchV2 и similaritySearchV2.

Имя команды для вызова: listNonExistingFileId.
Поддерживается только синхронный вызов.
Результат выполнения команды не журналируется.

GetEntityFieldAggregation (Data-model command)

На входе тип сущности, параметры фильтрации, и перечень полей по которым требуется агрегация

{
  "entityType": "Order",
  "search": {
    "query": "",
    "context": {}
  },
  "fields": [
    "title"
  ]
}

На выходе статистика значений указанных полей с учетом фильтрации

{
  "title": [
    {
      "value": "Договор",
      "count": 5
    },
    {
      "value": "Заявление",
      "count": 10
    }
  ]
}

Получение статистики полей модели данных.

Имя команды для вызова: getEntityFieldAggregation.
Поддерживается только синхронный вызов.
Результат выполнения команды не журналируется.

Доступные поля для фильтрации и виды фильтров по ним:

Поле Виды фильтров
id или objectid InSetQuery
externalid InSetQuery
title InSetQuery, LikeQuery
source InSetQuery
created InSetQuery, RangeQuery
modified InSetQuery, RangeQuery

Для фильтрации по полям сущности подробности описаны тут.

SaveRelation (Data-model command)

На входе параметры сущности, отношение между которыми сохраняется, а также ID конкретных объектов, входящих в отношение

{
  "entity1Type": "Order",
  "entity2Type": "Item",
  "entity1Field": "items",
  "object1Id": "18b1011b-9db3-4186-a53c-971016030068",
  "object2Id": "48911128-39a1-418c-93f1-c9773cda224e",
  "source": "manual"
}

На выходе признак успешного сохранения

true

Сохранение отношения между объектами двух сущностей.

Имя команды для вызова: saveRelation.
Поддерживается асинхронный и синхронный вызов.
Результат выполнения команды журналируется.

InternalSaveRelation (Data-model command)

Сохранение отношения между объектами двух сущностей. Логика и вход/выход такие же как в SaveRelation.

Имя команды для вызова: internalSaveRelation.
Поддерживается асинхронный и синхронный вызов.
Результат выполнения команды не журналируется.

Команда только внутренняя (нельзя вызвать через Api Gateway).

SaveRelationBatch (Data-model command)

На входе массив параметров сущностей, отношение между которыми сохраняется, а также ID конкретных объектов, входящих в отношение

[
  {
    "entity1Type": "Order",
    "entity2Type": "Item",
    "entity1Field": "items",
    "object1Id": "18b1011b-9db3-4186-a53c-971016030068",
    "object2Id": "48911128-39a1-418c-93f1-c9773cda224e",
    "source": "manual"
  },
  {
    "entity1Type": "Person",
    "entity2Type": "Item",
    "entity1Field": "items",
    "object1Id": "d1d70690-d972-4ee3-9ec1-ccd972979e72",
    "object2Id": "05c989a2-74cc-4888-a49c-c160bf7f918a",
    "source": "manual"
  }
]

На выходе перечень результатов сохранения для каждого отдельного отношения

[
  {
    "relation": {
      "entity1Type": "Order",
      "entity2Type": "Item",
      "entity1Field": "items",
      "object1Id": "18b1011b-9db3-4186-a53c-971016030068",
      "object2Id": "48911128-39a1-418c-93f1-c9773cda224e",
      "source": "manual"
    },
    "result": true
  },
  {
    "relation": {
      "entity1Type": "Person",
      "entity2Type": "Item",
      "entity1Field": "items",
      "object1Id": "d1d70690-d972-4ee3-9ec1-ccd972979e72",
      "object2Id": "05c989a2-74cc-4888-a49c-c160bf7f918a",
      "source": "manual"
    },
    "result": false,
    "error": "Relation between Person and Item does not exist "
  }
]

Сохранение нескольких отношений между объектами двух сущностей.

Имя команды для вызова: saveRelationBatch.
Поддерживается асинхронный и синхронный вызов.
Результат выполнения команды журналируется.

InternalSaveRelationBatch (Data-model command)

Сохранение нескольких отношений между объектами двух сущностей.

Логика и вход/выход такие же как в SaveRelationBatch.

Имя команды для вызова: internalSaveRelationBatch.
Поддерживается асинхронный и синхронный вызов.
Результат выполнения команды не журналируется.

Команда только внутренняя (нельзя вызвать через Api Gateway).

GetRelation (Data-model command)

На входе параметры сущности, а также ID конкретных объектов, входящих в отношение

{
  "entity1Type": "Order",
  "entity2Type": "Item",
  "entity1Field": "items",
  "object1Id": "18b1011b-9db3-4186-a53c-971016030068",
  "object2Id": "48911128-39a1-418c-93f1-c9773cda224e"
}

На выходе найденное отношение

{
  "entity1Type": "Order",
  "entity2Type": "Item",
  "entity1Field": "items",
  "entity2Field": "order",
  "object1Id": "18b1011b-9db3-4186-a53c-971016030068",
  "object2Id": "48911128-39a1-418c-93f1-c9773cda224e",
  "source": "test"
}

Или ошибка, если отношения не существует

{
  "businessError": null,
  "message": "ERROR: Entity object not found",
  "stackTrace": null,
  "data": null
}

Получение отношения между объектами двух сущностей.

Имя команды для вызова: getRelation.
Поддерживается только синхронный вызов.
Результат выполнения команды не журналируется.

ListRelations (Data-model command)

На входе параметры объекта и сущности, для которых нужно получить отношения

{
  "entityType": "Order",
  "objectId": "48911128-39a1-418c-93f1-c9773cda224e",
  "relatedEntityType": "Person",
  "fieldName": "Author",
  "reversed": false,
  "paging": null
}

На выходе список отношений объекта с указанной сущностью

[
  {
    "id": "134b960a-922d-4bca-b1e8-072de5a5efc1",
    "entityType1": "Order",
    "entityType2": "Person",
    "entity1Field": "author",
    "entity2Field": "orders",
    "object1Id": "48911128-39a1-418c-93f1-c9773cda224e",
    "object2Id": "83a7a3e9-ab24-4e83-b8e9-7470136aeb57",
    "source": "manual"
  }
]

Получение всех отношений объекта с указанной сущностью.

Имя команды для вызова: listRelations.
Поддерживается только синхронный вызов.
Результат выполнения команды не журналируется.

ListRelationsBatch (Data-model command)

На входе перечень параметров объекта и сущности, для которых нужно получить отношения

[
  {
    "entityType": "Order",
    "objectId": "48911128-39a1-418c-93f1-c9773cda224e",
    "relatedEntityType": "Person",
    "fieldName": "Author",
    "reversed": false,
    "paging": null
  }
]

На выходе список отношений указанных объектов с указанными для них сущностями

[
  {
    "id": "134b960a-922d-4bca-b1e8-072de5a5efc1",
    "entityType1": "Order",
    "entityType2": "Person",
    "entity1Field": "author",
    "entity2Field": "orders",
    "object1Id": "48911128-39a1-418c-93f1-c9773cda224e",
    "object2Id": "83a7a3e9-ab24-4e83-b8e9-7470136aeb57",
    "source": "manual"
  }
]

Аналогично ListRelations, но массовое. Порядок relation-ов в ответе совпадает с порядком идентификаторов в запросе.

Имя команды для вызова: listRelationsBatch.
Поддерживается только синхронный вызов.
Результат выполнения команды не журналируется.

ListAllRelations (Data-model command)

На входе параметры объекта, для которого нужно получить все отношения

{
  "entityType": "Order",
  "objectId": "48911128-39a1-418c-93f1-c9773cda224e"
}

На выходе список отношений объекта

[
  {
    "id": "134b960a-922d-4bca-b1e8-072de5a5efc1",
    "entityType1": "Order",
    "entityType2": "Person",
    "entity1Field": "author",
    "entity2Field": "orders",
    "object1Id": "48911128-39a1-418c-93f1-c9773cda224e",
    "object2Id": "83a7a3e9-ab24-4e83-b8e9-7470136aeb57",
    "source": "manual"
  }
]

Получение всех отношений объекта.

Имя команды для вызова: listAllRelations.
Поддерживается только синхронный вызов.
Результат выполнения команды не журналируется.

DeleteRelation (Data-model command)

На входе параметры сущности, отношение между которыми удаляется, а также ID конкретных объектов, входящих в отношение

{
  "entity1Type": "Order",
  "entity2Type": "Item",
  "entity1Field": "items",
  "object1Id": "18b1011b-9db3-4186-a53c-971016030068",
  "object2Id": "48911128-39a1-418c-93f1-c9773cda224e"
}

На выходе признак успешного удаления отношения

true

Или ошибка, если отношения не существует

{
  "businessError": null,
  "message": "ERROR: Entity object not found",
  "stackTrace": null,
  "data": null
}

Удаление отношения между объектами двух сущностей.

Имя команды для вызова: deleteRelation.
Поддерживается асинхронный и синхронный вызов.
Результат выполнения команды журналируется.

DeleteRelations (Data-model command)

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

{
  "entityType": "Order",
  "objectId": "48911128-39a1-418c-93f1-c9773cda224e",
  "relatedEntityTypes": [
    "Person"
  ]
}

На выходе список удаленных отношений

[
  {
    "id": "134b960a-922d-4bca-b1e8-072de5a5efc1",
    "entityType1": "Order",
    "entityType2": "Person",
    "entity1Field": "author",
    "entity2Field": "orders",
    "object1Id": "48911128-39a1-418c-93f1-c9773cda224e",
    "object2Id": "83a7a3e9-ab24-4e83-b8e9-7470136aeb57",
    "source": "manual"
  }
]

Удаление отношений объекта с перечисленными сущностями.

Имя команды для вызова: deleteRelations.
Поддерживается асинхронный и синхронный вызов.
Результат выполнения команды журналируется.

DeleteAllRelations (Data-model command)

На входе параметры объекта, для которого нужно удалить все отношения

{
  "entityType": "Order",
  "objectId": "48911128-39a1-418c-93f1-c9773cda224e"
}

На выходе список удаленных отношений

[
  {
    "id": "134b960a-922d-4bca-b1e8-072de5a5efc1",
    "entityType1": "Order",
    "entityType2": "Person",
    "entity1Field": "author",
    "entity2Field": "orders",
    "object1Id": "48911128-39a1-418c-93f1-c9773cda224e",
    "object2Id": "83a7a3e9-ab24-4e83-b8e9-7470136aeb57",
    "source": "manual"
  }
]

Удаление всех отношений объекта.

Имя команды для вызова: deleteAllRelations.
Поддерживается асинхронный и синхронный вызов.
Результат выполнения команды журналируется.

UpdateExternalRelations (Data-model command)

На входе поля для идентификации связи, и ID объектов, между которыми устанавливается связь

{
  "entity1Type": "Order",
  "entity2Type": "Item",
  "entity1Field": "items",
  "objectId": "Order1",
  "reversed": false,
  "relatedObjectIds": [
    "Item1",
    "Item2"
  ],
  "source": "manual"
}

На выходе перечень результатов сохранения для каждого отдельного отношения

[
  {
    "relatedObjectId": "Item1",
    "success": true
  },
  {
    "relatedObjectId": "Item2",
    "success": false,
    "error": "Not found object with entity type Item and id Item2"
  }
]

Обновление списка отношений одного объекта с указанной сущностью.
Команда полностью заменяет список отношений объекта; таким образом, указанные в теле команды отношения будут созданы, а не указанные — удалены.

Имя команды для вызова: updateExternalRelations.
Поддерживается асинхронный и синхронный вызов.
Результат выполнения команды журналируется.

Команда только внутренняя (нельзя вызвать через Api Gateway), не требует аутентификации.

ReindexObject (Data-model command)

На входе ID объекта и его тип сущности

{
  "entityType": "Order",
  "objectId": "18b1011b-9db3-4186-a53c-971016030068"
}

На выходе признак успешной отправки события переиндексации

true

Имя команды для вызова: reindexObject.
Поддерживается асинхронный и синхронный вызов.
Результат выполнения команды не журналируется.

На входе ID получаемой связи

"4faf020e-d0f6-4cb7-ab54-8412d50a28f4"

На выходе данные запрашиваемой связи между объектами

{
  "id": "4faf020e-d0f6-4cb7-ab54-8412d50a28f4",
  "entityType1": "Order",
  "object1Id": "18b1011b-9db3-4186-a53c-971016030068",
  "entityType2": "Act",
  "object2Id": "e776d20e-28ec-4e90-87d2-35962d7ca60e",
  "linkType": "plagiarism",
  "source": "auto",
  "owner": "plagiarism_mapper",
  "additional": {
    "intersections": 0.85
  }
}

Получение связи между объектами по ID.

Имя команды для вызова: getObjectLink.
Поддерживается только синхронный вызов.
Результат выполнения команды не журналируется.

На входе объект, связи которого нужно получить, список типов связей, и признак прямой или обратной связи

{
  "entityType": "Document",
  "objectId": "18b1011b-9db3-4186-a53c-971016030068",
  "forwardLinks": true
}

На выходе список связей запрашиваемого объекта

[
  {
    "id": "4faf020e-d0f6-4cb7-ab54-8412d50a28f4",
    "entityType1": "Order",
    "object1Id": "18b1011b-9db3-4186-a53c-971016030068",
    "entityType2": "Act",
    "object2Id": "e776d20e-28ec-4e90-87d2-35962d7ca60e",
    "linkType": "plagiarism",
    "source": "auto",
    "owner": "plagiarism_mapper",
    "additional": {
      "intersections": 0.85
    }
  },
  {
    "id": "b9841e89-1e05-4519-8b0e-f15804410039",
    "entityType1": "Order",
    "object1Id": "18b1011b-9db3-4186-a53c-971016030068",
    "entityType2": "Act",
    "object2Id": "e776d20e-28ec-4e90-87d2-35962d7ca60e",
    "linkType": "similarity",
    "source": "auto",
    "owner": "faiss_similarity",
    "additional": {
      "similarity": 0.33
    }
  }
]

Получение всех связей объекта. Объект идентифицируется его ID и типом сущности. Можно указать список типов связи, тогда вернутся связи только указанных типов. Если этот список пустой или отсутствует, тогда вернутся все связи. Обязательно указывать направление связи (все связи всегда направленные). Прямое направление показывает, что искомый объект ищется среди первого узла связи (entity1), а обратное - среди второго (entity2).

Имя команды для вызова: getObjectLinks.
Поддерживается только синхронный вызов.
Результат выполнения команды не журналируется.

ListRelationsByType (Data-model command)

На входе название поля связи и типы объектов, между которыми нужно получить связи

{
  "entityFrom": "ProjectParticipant",
  "entityTo": "Project",
  "field": "project"
}

На выходе список всех связей для указанных типов с данными об объектах

{
  "items": [
    {
      "id": "4faf020e-d0f6-4cb7-ab54-8412d50a28f4",
      "entityType1": "ProjectParticipant",
      "object1": {
        "id": "d4db2633-62c7-4b61-956d-cb5461fe2a3e",
        "externalId": "0000000000000000",
        "entityType": "ProjectParticipant",
        "title": "Order d4db2633-62c7-4b61-956d-cb5461fe2a3e",
        "source": "example",
        "created": 1630326492,
        "modified": 1630326492,
        "data": {
          "date": 1577869200,
          "number": 555,
          "author": "00000000-0000-0000-0000-000000000000"
        },
        "additionalData": {},
        "version": 1
      },
      "entityType2": "Project",
      "object2": {
        "id": "d4db2633-62c7-4b61-956d-cb5461fe2a3e",
        "externalId": "0000000000000000",
        "entityType": "Project",
        "title": "Order d4db2633-62c7-4b61-956d-cb5461fe2a3e",
        "source": "example",
        "created": 1630326492,
        "modified": 1630326492,
        "data": {
          "date": 1577869200,
          "number": 555,
          "author": "00000000-0000-0000-0000-000000000000"
        },
        "additionalData": {},
        "version": 1
      },
      "linkType": "plagiarism",
      "source": "auto"
    }
  ],
  "total": 1
}

Получение всех связей между указанными типами.

Имя команды для вызова: listRelationsByType.
Поддерживается только синхронный вызов.
Результат выполнения команды не журналируется.

На входе параметры создаваемой связи

{
  "entityType1": "Order",
  "object1Id": "18b1011b-9db3-4186-a53c-971016030068",
  "entityType2": "Act",
  "object2Id": "e776d20e-28ec-4e90-87d2-35962d7ca60e",
  "linkType": "plagiarism",
  "source": "auto",
  "owner": "plagiarism_mapper",
  "additional": {
    "intersections": 0.85
  }
}

На выходе ID созданной связи

"4faf020e-d0f6-4cb7-ab54-8412d50a28f4"

Создание связи между объектами. Уникальность связи определяется набором полей: entityType1, object1Id, entityType2, object2Id, linkType, source.

Имя команды для вызова: createObjectLink.
Поддерживается асинхронный и синхронный вызов.
Результат выполнения команды не журналируется.

На входе список создаваемых связей

[
  {
    "entityType1": "Order",
    "object1Id": "18b1011b-9db3-4186-a53c-971016030068",
    "entityType2": "Act",
    "object2Id": "e776d20e-28ec-4e90-87d2-35962d7ca60e",
    "linkType": "plagiarism",
    "source": "auto",
    "owner": "plagiarism_mapper",
    "additional": {
      "intersections": 0.85
    }
  },
  {
    "entityType1": "Order",
    "object1Id": "18b1011b-9db3-4186-a53c-971016030068",
    "entityType2": "Act",
    "object2Id": "da2cf038-973a-4202-a4ac-0bab6960c30c",
    "linkType": "plagiarism",
    "source": "auto",
    "owner": "plagiarism_mapper",
    "additional": {
      "intersections": 0.85
    }
  }
]

На выходе количество созданных связей

2

Создание связей между объектами.

Имя команды для вызова: createObjectsLinks.
Поддерживается асинхронный и синхронный вызов.
Результат выполнения команды не журналируется.

Команда только внутренняя (нельзя вызвать через Api Gateway), не требует аутентификации.

На входе ID удаляемой связи

"4faf020e-d0f6-4cb7-ab54-8412d50a28f4"

На выходе признак успешного удаления

true

Или ошибка, если связи не существует не существует

{
  "businessError": null,
  "message": "ERROR: Entity object not found",
  "stackTrace": null,
  "data": null
}

Удаление связи между объектами по ID.

Имя команды для вызова: deleteObjectLink.
Поддерживается асинхронный и синхронный вызов.
Результат выполнения команды не журналируется.

На входе параметры объекта и его связей для удаления (тип сущности, ID объекта, необязательный тип связей и признак прямых или обратных связей)

{
  "entityType": "Document",
  "objectId": "18b1011b-9db3-4186-a53c-971016030068",
  "linkType": "plagiarism",
  "forwardLinks": true
}

На выходе количество удаленных ссылок

3

Или ошибка, если объекта не существует не существует

{
  "businessError": null,
  "message": "ERROR: Entity object not found",
  "stackTrace": null,
  "data": null
}

Удаление связей объекта. Объект идентифицируется его ID и типом сущности. Можно опционально выбрать только связи определенного типа. Обязательно указывать направление связи (все связи всегда направленные). Прямое направление показывает, что искомый объект ищется среди первого узла связи (entity1), а обратное - среди второго (entity2).

Имя команды для вызова: deleteAllObjectLinks.
Поддерживается асинхронный и синхронный вызов.
Результат выполнения команды не журналируется.

ListFilesInfoWithTags (Data-model command)

На входе параметры для поиска файлов (фильтры, сортировка, номер страницы)

{
  "query": "name",
  "context": {
    "code": "like Doc1%"
  },
  "sorting": null,
  "paging": null
}

На выходе результат поиска файлов по переданным параметрам

{
  "items": [
    {
      "objectIdentity": {
        "entityType": "Document",
        "objectId": "18b1011b-9db3-4186-a53c-971016030068"
      },
      "entityTypeTitle": "Документ",
      "objectTitle": "Document 54a4da2d-05da-448e-88af-b44757ceef40",
      "fileInfo": {
        "fileId": "54a4da2d-05da-448e-88af-b44757ceef40",
        "size": 11830,
        "name": "Doc1.docx",
        "extension": "docx",
        "url": "datamodel/Document/54a4da2d-05da-448e-88af-b44757ceef40",
        "additional": {},
        "created": 1636378607649,
        "modified": 1636378607649,
        "md5": "7EF292CD265BC138C92F069CCF08D32C"
      },
      "tags": [
        "TextFile",
        "DocxFile"
      ]
    }
  ],
  "total": 1
}

Возвращает список файлов с подробной информацией о файле, тегах данного файла и родительском объекте.

Имя команды для вызова: listFilesInfoWithTags.
Поддерживается только синхронный вызов.
Результат выполнения команды не журналируется.

Доступные поля для фильтрации и виды фильтров по ним:

Поле Виды фильтров
fileId InSetQuery
size InSetQuery
name InSetQuery, LikeQuery
extension InSetQuery, LikeQuery
url InSetQuery, LikeQuery
created InSetQuery, RangeQuery
modified InSetQuery, RangeQuery
md5 InSetQuery

Доступные поля для сортировки:

Поле
size
name
extension
url
modified

Если поле sorting отсутствует, то список сортируется по полю created в порядке возрастания. Если поле paging отсутствует, то будет применено ограничение по-умолчанию { "page": 1, "count": 10 }.

ListTagsWithFilesCount (Data-model command)

На входе фильтры для поиска файлов

{
  "query": "name",
  "context": {
    "code": "like Doc1%"
  },
  "sorting": null,
  "paging": null
}

На выходе список тегов с количеством привязанных файлов, которые были найдены по переданным параметрам

{
  "TextFile": 1,
  "NULL": 10
}

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

Имя команды для вызова: listTagsWithFilesCount.
Поддерживается только синхронный вызов.
Результат выполнения команды не журналируется.

Доступные поля для фильтрации и виды фильтров по ним:

Поле Виды фильтров
fileId InSetQuery
size InSetQuery
name InSetQuery, LikeQuery
extension InSetQuery, LikeQuery
url InSetQuery, LikeQuery
created InSetQuery, RangeQuery
modified InSetQuery, RangeQuery
md5 InSetQuery

Сортировка и пагинация для данной команды не применяются.

ListFileExtensions (Data-model command)

На входе никаких параметры не требуется

null

На выходе список уникальных расширений загруженных в систему файлов

[
  "docx",
  "txt",
  "pdf"
]

Возвращает список уникальных расширений загруженных в систему файлов.

Имя команды для вызова: listFileExtensions.
Поддерживается только синхронный вызов.
Результат выполнения команды не журналируется.

WriteFileTags (Data-model command)

На входе список идентификаторов файла с новыми тегами

[
  {
    "fileId": "54a4da2d-05da-448e-88af-b44757ceef40",
    "tags": [
      "TextFile",
      "DocxFile"
    ]
  }
]

На выходе количество записаных тегов

2

Перезаписывает текущие теги файла объекта новым списком, полученным в параметрах команды.

Имя команды для вызова: writeFileTags.
Поддерживается асинхронный и синхронный вызов.
Результат выполнения команды не журналируется.

RemoveFileTags (Data-model command)

На входе список идентификаторов файлов с тегами, которые нужно удалить

[
  {
    "fileId": "54a4da2d-05da-448e-88af-b44757ceef40",
    "tags": [
      "DocxFile"
    ]
  }
]

На выходе количество успешно удаленных тегов

1

Удаляет из текущего набора тегов для файла объекта те теги, которые переданы в параметрах команды.

Имя команды для вызова: removeFileTags.
Поддерживается асинхронный и синхронный вызов.
Результат выполнения команды не журналируется.

RemoveAllFileTags (Data-model command)

На входе список идентификаторов файла

[
  "54a4da2d-05da-448e-88af-b44757ceef40"
]

На выходе количество успешно удаленных тегов

2

Удаляет все теги для указанных файлов.

Имя команды для вызова: removeAllFileTags.
Поддерживается асинхронный и синхронный вызов.
Результат выполнения команды не журналируется.

GetEntityParents (Data-model command)

На входе код типа сущностей

"RfbrDocument"

На выходе все родительские сущности

[
  {
    "entityType": "Patent",
    "fieldId": "patent",
    "nested": [
      {
        "entityType": "links",
        "fieldId": "links",
        "nested": []
      }
    ]
  },
  {
    "entityType": "1thesis",
    "fieldId": "thesis",
    "nested": []
  }
]

Имя команды для вызова: getEntityParents.
Поддерживается только синхронный вызов.
Результат выполнения команды не журналируется.

GetFile (Data-model command)

На входе полный идентификатор файла

{
  "fileId": "54a4da2d-05da-448e-88af-b44757ceef40",
  "entityType": "1thesis",
  "objectId": "54a4da2d-05da-448e-88af-b44757ceef40"
}

На выходе информация о файле (предназначена только для сервиса api-gateway)

{
  "id": "1c689788-9617-4c93-bcee-6eae8909a0ba",
  "path": "temp/1c689788-9617-4c93-bcee-6eae8909a0ba",
  "bucket": "temp"
}

Данная команда предназначена для скачивания файла после проверки прав.

Имя команды для вызова: getFile.
Поддерживается только синхронный вызов.
Результат выполнения команды журналируется.

Скачивание файла (Data-model)

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

UpdateKeywords (Data-model command)

На входе тип и идентификатор объекта и список его ключевых слов (фраз)

{
  "entityType": "Patent",
  "objectId": "6f1c4255-952b-4b5c-b463-3fd1662ccd4e",
  "keywords": [
    {
      "keyword": "Сталь",
      "pos": "NOUN",
      "weight": 0.94
    },
    {
      "keyword": "Дерево",
      "pos": "NOUN",
      "weight": 0.78
    },
    {
      "keyword": "бронзА и олово",
      "pos": "NOUN",
      "weight": 1
    }
  ]
}

На выходе количество созданных связей между ключевым словом и объектом

3

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

Имя команды для вызова: updateKeywords.
Поддерживается асинхронный и синхронный вызов.
Результат выполнения команды не журналируется.

Команда только внутренняя (нельзя вызвать через Api Gateway), не требует аутентификации.

ListObjectKeywords (Data-model command)

На входе тип и идентификатор объекта

{
  "entityType": "Patent",
  "objectId": "8505d418-371f-466e-9cb3-6a8cbbf7a610"
}

На выходе объект с ключевыми словами

{
  "objectId": "8505d418-371f-466e-9cb3-6a8cbbf7a610",
  "keywords": [
    {
      "keywordId": "894c334c-cd9d-4e9a-9ecd-d35623412ad6",
      "keyword": "сталь",
      "pos": "NOUN",
      "weight": 1.0
    },
    {
      "keywordId": "fce6be0f-a2ca-4f9d-92ff-0aaa4c8cb2b8",
      "keyword": "пластик",
      "pos": "NOUN",
      "weight": 0.78
    }
  ]
}

Команда позволяет по типу и идентификатору объекта получить его ключевые слова.

Имя команды для вызова: listObjectKeywords.
Поддерживается асинхронный и синхронный вызов.
Результат выполнения команды не журналируется.

ListKeywords (Data-model command)

На входе параметры поискового запроса (объект Search)

{
  "query": "title",
  "context": {
    "title": "like %ронза%"
  },
  "paging": {
    "page": 1,
    "count": 10
  }
}

На выходе страница найденых ключевых слов

{
  "items": [
    {
      "id": "ebad64c4-9fa4-450d-bb49-94aa439a7289",
      "title": "бронза",
      "pos": "NOUN"
    },
    {
      "id": "434e6425-774c-43b3-b94c-40bd4ee869f2",
      "title": "бронза и олово",
      "pos": "NOUN"
    }
  ],
  "total": 2
}

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

Имя команды для вызова: listKeywords.
Поддерживается асинхронный и синхронный вызов.
Результат выполнения команды не журналируется.

По умолчанию сортировка производится по полю title.

Запрос принимает параметры сортировки, фильтров и пейджинга в параметре Search.
Применяется к полям модели Keyword.

Доступные поля для фильтрации и виды фильтров по ним:

Поле Виды фильтров
keywordId InSetQuery, LikeQuery
title InSetQuery, LikeQuery

Доступные поля для сортировки:

Поле
title

InternalGetMaxNumericFieldValue (Data-model command)

На входе название поля, тип объекта и параметры поискового запроса (объект Search)

{
  "field": "numm",
  "entityType": "Tag",
  "search": {
    "query": "tagType.id",
    "context": {
      "tagType.id": "01f6c03f-d6db-44eb-b8c4-7ee6e5fc2454"
    }
  }
}

На выходе найденное максимальное значение или 'null' если нет данных или не заполнено ни одного значения

6

Или ошибка, если такого поля в модели данных не существует

{
  "businessError": null,
  "message": "ERROR: fields [numm] for entityType 'Tag' not found",
  "stackTrace": null,
  "data": null
}

Команда позволяет по типу объекта и параметрам поискового запроса получить максимальное значение для поля объекта из data или additionalData. Метод необходим для нумерации объектов сторонним сервисом.

Имя команды для вызова: internalGetMaxNumericFieldValue.
Поддерживается только синхронный вызов.
Результат выполнения команды не журналируется.

Команда только внутренняя (нельзя вызвать через Api Gateway).

Объекты сервиса модели данных

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

FieldType (Data-model)

Тип поля сущности.

Поле Тип Описание
id String Строковый код типа поля.
description String Название типа поля для вывода в UI.
databaseType String Тип поля в БД.
settings JSON Произвольные настройки, применяемые для данного типа поля.

RelationType (Data-model)

Тип отношения между сущностями.

Поле Тип Описание
id String Строковый код типа отношения.
title String Название типа отношения.
description String Развернутое описание типа отношения.

MigrationDslOperation (Data-model)

Базовый тип операции Migration DSL для создания модели данных. Реализации:

CreateEntity (Data-model)

Операция создания типа сущности.

Поле Тип Обязательное Описание
operation String Да Должно быть CreateEntity.
entityType String Да Строковый код создаваемого типа сущности.
title String Да Название типа сущности для вывода в UI.
description String Нет Развернутое описание типа сущности.
settings JSON Нет Настройки типа сущности.

UpdateEntity (Data-model)

Операция изменения типа сущности.

Поле Тип Обязательное Описание
operation String Да Должно быть UpdateEntity.
entityType String Да Строковый код изменяемого типа сущности.
title String Да Название типа сущности для вывода в UI.
description String Нет Развернутое описание типа сущности.
settings JSON Нет Настройки типа сущности.

DeleteEntity (Data-model)

Операция удаления типа сущности.

Поле Тип Обязательное Описание
operation String Да Должно быть DeleteEntity.
entityType String Да Строковый код удаляемого типа сущности.

AddField (Data-model)

Операция добавления поля к типу сущности. Для разных типов полей предусмотрены разные допустимые настройки.

Поле Тип Обязательное Описание
operation String Да Должно быть AddField.
entityType String Да Строковый код типа сущности, которому добавляется поле.
fieldId String Да Строковый код (название) добавляемого поля.
fieldType String Да Строковый код типа добавляемого поля. Все доступные типы полей можно получить с помощью команды Список типов полей.
title String Да Название добавляемого поля для вывода в UI.
description String Нет Развернутое описание добавляемого поля.
example требуемый тип Нет Пример значения поля, см. ниже.
nullable Boolean Нет Необязательное или обязательное. Необязательное, когда указано true.
settings JSON Нет Произвольные настройки.
defaultValue требуемый тип если поле обязательное и уже есть объекты сущности Значение поля, которое установится для уже имеющихся объектов сущности.

Параметр example

AddAdditionalField (Data-model)

Операция добавления дополнительного поля к типу сущности. Для разных типов полей предусмотрены разные допустимые настройки.

Поле Тип Обязательное Описание
operation String Да Должно быть AddAdditionalField.
entityType String Да Строковый код типа сущности, которому добавляется поле.
fieldId String Да Строковый код (название) добавляемого поля.
fieldType String Да Строковый код типа добавляемого поля.
title String Да Название добавляемого поля для вывода в UI.
description String Нет Развернутое описание добавляемого поля.
example требуемый тип Нет Пример значения поля. Применяется в конструкторе UI. Заполняется значением нужного типа. Если строка, тогда строка. Если число или дата - тогда число. Будет в таком же виде возвращено в конструктор.
settings JSON Нет Произвольные настройки.

DeleteField (Data-model)

Операция удаления поля у типа сущности. Поддерживает как простые, так и дополнительные поля.

Поле Тип Обязательное Описание
operation String Да Должно быть DeleteField.
entityType String Да Строковый код типа сущности, у которой удаляется поле.
fieldId String Да Строковый код (название) удаляемого поля.

UpdateField (Data-model)

Операция изменения поля у типа сущности.

Поле Тип Обязательное Описание
operation String Да Должно быть UpdateField.
entityType String Да Строковый код типа сущности, которому добавляется поле.
fieldId String Да Строковый код (название) добавляемого поля.
title String Да Название добавляемого поля для вывода в UI.
description String Нет Развернутое описание добавляемого поля.
example требуемый тип Нет Пример значения поля. Применяется в конструкторе UI. Заполняется значением нужного типа. Если строка, тогда строка. Если число или дата - тогда число. Будет в таком же виде возвращено в конструктор.
nullable Boolean Нет Необязательное или обязательное. Необязательное, когда указано true.
settings JSON Нет Произвольные настройки.
fieldType String Нет Строковый код нового типа поля.
defaultValue требуемый тип Если поле обязательное и уже есть объекты сущности Значение поля, которое установится для уже имеющихся объектов сущности (если ранее отсутствовало).

EntityTypeSettings (Data-model)

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

Название Тип Описание Пример
titleRule String Правило указания наименования объекта, которое будет выводиться в UI. В качестве значения передается название поля, которое содержит наименование конкретного объекта. Если правило не задано, то наименование будет считаться как "{entityType} {objectId}". "titleRule": "title"
revisionConfig String Настройки для Сущности-ревизии {"parentFieldCode": "parent", "actualityFieldCode": "isActual"}

FieldSettings (Data-model)

Создаваемые поля поддерживают различные настройки. Их набор и формат зависит от типа поля. Эти настройки в дальнейшем влияют на обработку поля и отражаются в JSON схеме.

На текущий момент поддерживаются настройки для следующих типов полей:

StringFieldSettings (Data-model)

Настройки для строкового поля.

Поле Тип Обязательное Описание
maxLength Int Нет Максимальная длина для вводимой строки. Используется для валидации. Если значение не указано, используется 64 по умолчанию.
multiple Boolean Да Признак множественного выбора.

TextFieldSettings (Data-model)

Настройки для текстового поля.

Поле Тип Обязательное Описание
multiple Boolean Да Признак множественного выбора.

CatalogFieldSettings (Data-model)

Настройки для поля с элементами справочника.

Поле Тип Обязательное Описание
code String Да Код справочника, элементы которого можно сохранить в этом поле.
multiple Boolean Да Признак множественного выбора. Если выбрано true, тогда для поля будет использоваться multiselect, а также значение будет передаваться массивом id, а не просто одиночным значением.

FileFieldSettings (Data-model)

Настройки для поля с файлами.

Поле Тип Обязательное Описание Ограничения
multiple Boolean Да Признак множественного выбора. Если выбрано true, тогда в поле будет храниться несколько файлов. Как и в случае одиночного поля данные передаются массивом.
maxCount Int Нет Признак максимального количества файлов, присваивается полю maxItems в JSON-схеме сущности. Используется только если multiple=true, иначе maxItems будет присвоено 1. По умолчанию 10. - Не может быть больше 100
- Не может быть меньше 1.

RevisionConfig (Data-model)

Настройки для Сущности-ревизии

Поле Тип Обязательное Описание Ограничения
parentFieldCode String да Поле сущности, ссылающееся на родительский объект, по отношению к которому он является ревизией. Должно иметь тип many-to-one и ссылаться на entity1 (другими словами, many-to-one в сторону родительской сущности, а не в сторону ревизии).
actualityFieldCode String да Boolean - поле, обозначающее актуальность ревизии. Должно быть обязательным (not-null) boolean полем.

AddRelation (Data-model)

Операция добавления отношения между типами сущностей. В дальнейшем отношение однозначно идентифицируется по комбинации entity1+entity2+entity1Field.

Поле Тип Обязательное Описание
operation String Да Должно быть AddRelation.
relationType String Да Тип отношения между сущностями.
entity1 String Да Строковый код первого типа сущности.
entity2 String Да Строковый код второго типа сущности.
title1 String Да Название добавляемого отношения для вывода в UI (со стороны entity1).
title2 String Нет Название добавляемого отношения для вывода в UI (со стороны entity2).
entity1Field String Да Строковый код нового виртуального поля первой сущности.
entity2Field String Нет Строковый код нового виртуального поля второй сущности.
entity1Settings JSON Нет Произвольные настройки поля первой сущности.
entity2Settings JSON Нет Произвольные настройки поля второй сущности.

UpdateRelationMigration (Data-model)

Операция изменения атрибутов (entity2Field, relationType, title1, title2) отношения между типами сущностей.

Поле Тип Обязательное Описание
operation String Да Должно быть UpdateRelation.
entity1 String Да Строковый код первого типа сущности.
entity2 String Да Строковый код второго типа сущности.
entity1Field String Да Строковый код виртуального поля первой сущности.
entity2Field String Нет Новый строковый код виртуального поля второй сущности.
relationType String Да Новый тип отношения между сущностями.
title1 String Да Новое название добавляемого отношения для вывода в UI (со стороны entity1).
title2 String Нет Новое название добавляемого отношения для вывода в UI (со стороны entity2).
entity1Settings JSON Нет Произвольные настройки поля первой сущности.
entity2Settings JSON Нет Произвольные настройки поля второй сущности.

RelationSettings (Data-model)

Создаваемые связи по сути определяют 2 поля. Для каждого из них можно задать настройки. Их набор и формат определяются потребностями пользователя. Эти настройки в дальнейшем влияют на обработку поля и отражаются в JSON схеме. На текущий момент предполагается хранение в настройках связей (полях связи) информации о зависимостях между атрибутами объекта.

Служебные атрибуты: при генерации JSON схемы настройки properties порождаемых объектами Relation уже были в схеме и генерировались автоматически. Автоматически создавался атрибут "to" ссылающийся на EntityType сущности, на которую ссылалось property. Следует избегать в своих настройках добавления в корень настроек этого ключа во избежание конфликтного затирания.

DeleteRelationMigration (Data-model)

Операция удаления отношения между типами сущностей.

Поле Тип Обязательное Описание
operation String Да Должно быть DeleteRelation.
entity1 String Да Строковый код первого типа сущности.
entity2 String Да Строковый код второго типа сущности.
entity1Field String Да Строковый код виртуального поля первой сущности.

PrefixMigration (Data-model)

Операция, применяемая для всех сущностей с указанным префиксом.

Поле Тип Обязательное Описание
entityPrefix String Да Префикс сущностей.
migration JSON Да Сама миграция (см. ниже).

Миграции, которые можно указывать в поле migration:

EntityType (Data-model)

Тип сущности в модели данных.

Поле Тип Описание
id String Строковый код типа сущности.
title String Название типа сущности для вывода в UI.
description String Развернутое описание типа сущности.
settings JSON Настройки типа сущности.

AddEntityObject (Data-model)

Создание объекта сущности.

Поле Тип Обязательное Описание
entityType String Да Строковый код типа сущности.
source String Да Источник данных для объекта. Для введенных вручную - manual.
attributes JSON Да JSON с полями добавляемого объекта.
createRelations Boolean Нет Включение создания новых relation в рамках команды.

AddEntityObjectBatch (Data-model)

Создание списка объектов сущности.

Поле Тип Обязательное Описание
entityType String Да Строковый код типа сущности.
source String Да Источник данных для объекта. Для введенных вручную - manual.
attributes List[JSON] Да Список JSON с полями добавляемых объектов.
createRelations Boolean Нет Включение создания новых relation в рамках команды.

AddEntityObjectForBatchV2 (Data-model)

Создание списка объектов сущностей.

Поле Тип Обязательное Значение по умолчанию Описание
objectId UUID Нет UUID.randomUUID ID объекта (Если не указано - используется сгенерированное значение).
entityType String Да - Строковый код типа сущности.
source String Да - Источник данных для объекта. Для введенных вручную - manual.
attributes JSON Да - Список JSON-ов с полями добавляемых объектов.
metadata JSON Нет {} JSON с метаданными.
createRelations Boolean Нет false Включение создания новых relation в рамках команды.

AddExternalEntityObject (Data-model)

Создание объекта сущности, полученного из внешнего клиента.

Поле Тип Обязательное Описание
entityType String Да Строковый код типа сущности.
externalId String Да Внешний ID объекта.
source String Да Источник данных.
attributes JSON Да JSON с полями добавляемого объекта.
createRelations Boolean Нет Включение создания новых relation в рамках команды.

UpdateEntityObject (Data-model)

Изменение объекта сущности.

Поле Тип Обязательное Описание
entityType String Да Строковый код типа сущности.
objectId UUID Да ID объекта.
version Int Да Версия объекта. Нужна для оптимистичных блокировок.
attributes JSON Да JSON с полями объекта. Должен содержать все поля объекта.
createRelations Boolean Нет Включение создания новых relation в рамках команды.

UpdateEntityObjectFields (Data-model)

Изменение части полей объекта.

Поле Тип Обязательное Описание
entityType String Да Строковый код типа сущности.
objectId UUID Да ID объекта.
version Int Да Версия объекта. Нужна для оптимистичных блокировок.
updates JSON Да JSON с изменяемыми полями объекта и их новыми значениями.
createRelations Boolean Нет Включение создания новых relation в рамках команды.

UpdateEntityObjectFieldsList (Data-model)

Изменение части полей объектов (по поисковому запросу).

Поле Тип Обязательное Описание
entityType String Да Строковый код типа сущности.
search Search Да Параметры списочного запроса.
updates JSON Да JSON с изменяемыми полями объекта и их новыми значениями.
createRelations Boolean Нет Включение создания новых relation в рамках команды.

UpdateEntityObjectFieldsBatch (Data-model)

Изменение части полей объектов (по ID).

Поле Тип Обязательное Описание
entityType String Да Строковый код типа сущности.
objectIds List[UUID] Да ID объектов.
updates JSON Да JSON с изменяемыми полями объекта и их новыми значениями.

UpdateExternalEntityObject (Data-model)

Изменение объекта сущности.

Поле Тип Обязательное Описание
entityType String Да Строковый код типа сущности.
external String Да Внешний ID объекта.
attributes JSON Да JSON с полями объекта. Должен содержать все поля объекта.
createRelations Boolean Нет Включение создания новых relation в рамках команды.

EntityObjectIdentity (Data-model)

Полный идентификатор объекта сущности.

Поле Тип Обязательное Описание
entityType String Да Строковый код типа сущности.
objectId UUID Да ID объекта.

EntityObjectExternalIdentity (Data-model)

Полный идентификатор внешнего объекта сущности.

Поле Тип Обязательное Описание
entityType String Да Строковый код типа сущности.
externalId String Да Внешний ID объекта.

TitledEntityObjectIdentity (Data-model)

Полный идентификатор и наименование объекта сущности.

Поле Тип Обязательное Описание
entityType String Да Строковый код типа сущности.
objectId UUID Да ID объекта.
title String Да Наименование объекта.

EntityObjectFields (Data-model)

Идентификатор объекта сущности и список полей данного объекта.

Поле Тип Обязательное Описание
id EntityObjectIdentity Да Идентификатор объекта сущности.
fields List[String] Да Список необходимых полей.
fieldSearches JSON Нет см. Фильтры для связанных сущностей.

EntityObjectsBatchWithFields (Data-model)

Идентификаторы объектов сущности и список полей для данного набора объектов.

Поле Тип Обязательное Описание
entityType String Да Строковый код типа сущности.
ids List[UUID] Да Идентификаторы объектов заданного типа сущности.
fields List[String] Да Список необходимых полей.
fieldSearches JSON Нет См. Фильтры для связанных сущностей.

SaveObjectAdditionalInfo (Data-model)

Сохранение дополнительных атрибутов объекта сущности. Дополнительные атрибуты.

Поле Тип Обязательное Описание
entityType String Да Строковый код типа сущности.
objectId UUID Да ID объекта.
additionalData JSON Да JSON с дополнительными полями. Поля добавляются к существующим. Не обязательно передавать все.

SaveObjectMetadata (Data-model)

Сохранение метаданных объекта сущности.

Поле Тип Обязательное Описание
entityType String Да Строковый код типа сущности.
objectId UUID Да ID объекта.
metadata JSON Да JSON с метаданными.

SaveFilesAdditionalInfo (Data-model)

Сохранение дополнительных файлов для файловых полей объекта сущности.

Поле Тип Обязательное Описание
entityType String Да Строковый код типа сущности.
objectId UUID Да ID объекта.
data List[FileAdditionalInfo] Да Информация по файловым полям.

FileAdditionalInfo (Data-model)

Сохранение дополнительных файлов для отдельного файлового поля объекта сущности.

Поле Тип Обязательное Описание
field String Да Строковый код файлового поля.
key String Да Код атрибута.
data Map[UUID, File] Да Существующие файлы ассоциированные с новыми дополнительными файлами.

SaveFilesAdditionalInfoV2 (Data-model)

Сохранение дополнительных файлов для файловых полей объекта сущности.

Поле Тип Обязательное Описание
key String Да Код атрибута.
files Map[UUID, File] Да Существующие файлы ассоциированные с новыми дополнительными файлами.

EntityObjectMeta (Data-model)

Метаданные объекта сущности.

Поле Тип Описание
id UUID ID объекта.
externalId String Внешний ID объекта.
entityType String Тип сущности объекта.
title String Название объекта. Может быть пустой строкой, если нет необходимых полей в data.
source String Источник данных для объекта.
created TimeStamp Дата и время создания объекта.
modified TimeStamp Дата и время последнего изменения объекта.
version Int Версия объекта для оптимистичных блокировок. Передается назад на бэкэнд при модификации данных.
removed Boolean Признак того, считается ли объект удаленным.

ListObjects (Data-model)

Получение списка объектов сущности.

Поле Тип Обязательное Описание
entityType String Да Строковый код типа сущности.
search Search Да Параметры списочного запроса.

RichListObjects (Data-model)

Получение списка объектов сущности только с указанными полями.

Поле Тип Обязательное Описание
entityType String Да Строковый код типа сущности.
fields List[String] Да Список строк с названиями полей сущности.
search Search Да Параметры списочного запроса.
fieldSearches JSON Нет См. Фильтры для связанных сущностей.

GetObjectPosition (Data-model)

Запрос позиции объекта в отфильтрованном и отсортированном списке.

Поле Тип Обязательное Описание
entityType String Да Строковый код типа сущности.
objectId UUID Да ID искомого объекта.
search Search Да Параметры списочного запроса.

GetEntityFieldAggregation (Data-model)

Параметры запроса на агрегацию значений полей.

Поле Тип Обязательное Описание
entityType String Да Строковый код типа сущности.
search Search Да Параметры списочного запроса. Параметры sorting и paging не учитываются.
fields List[String] Да Перечень полей, для которых нужна агрегация.

FieldAggregatedValue (Data-model)

Статистика значения поля.

Поле Тип Обязательное Описание
value произвольный Да Значение поля.
count Number Да Количество записей с таким значением поля.

AddObjectRelation (Data-model)

Добавление отношения между объектами сущностей. Название отношения соответствует комбинации типов сущностей ${entity1Type}_to_${entity2Type}_on_${entity1Field}.

Поле Тип Обязательное Описание
entity1Type String Да Тип первой сущности из отношения.
entity2Type String Да Тип второй сущности из отношения.
entity1Field String Да Виртуальное поле отношения из первой сущности.
object1Id UUID Да ID объекта первой сущности.
object2Id UUID Да ID объекта второй сущности.
source String Да Источник данных для отношений. Для введенных вручную - manual.

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

AddObjectRelationResult (Data-model)

Результат добавления отношения между объектами сущностей.

Поле Тип Обязательное Описание
relation AddObjectRelation Да Описание запроса.
result Boolean Да Признак успешности.
error String Нет Описание ошибки, если произошла.

ObjectProcessingResult (Data-model)

Результат обработки (например изменения) объекта.

Поле Тип Обязательное Описание
entityType String Да Тип сущности обработанного объекта.
objectId UUID Да ID обработанного объекта.
result Boolean Да Признак успешности.
error String Нет Описание ошибки, если произошла.
errorCode Int Нет HTTP-код ошибки, если произошла.

ObjectRelation (Data-model)

Описание сохраненного отношения между объектами сущностей.

Поле Тип Обязательное Описание
entity1Type String Да Тип первой сущности из отношения.
entity2Type String Да Тип второй сущности из отношения.
entity1Field String Да Виртуальное поле отношения из первой сущности.
entity2Field String Нет Виртуальное поле отношения из первой сущности.
object1Id UUID Да ID объекта первой сущности.
object2Id UUID Да ID объекта второй сущности.
source String Да Источник данных для отношений. Для введенных вручную - manual.

GetObjectRelation (Data-model)

Получение отношения между объектами сущностей.

Поле Тип Обязательное Описание
entity1Type String Да Тип первой сущности из отношения.
entity2Type String Да Тип второй сущности из отношения.
entity1Field String Да Виртуальное поле отношения из первой сущности.
entity2Field String Нет Виртуальное поле отношения из второй сущности.
object1Id UUID Да ID объекта первой сущности.
object2Id UUID Да ID объекта второй сущности.

ListObjectRelations (Data-model)

Получение списка всех отношений между объектов и указанной сущностью.

Поле Тип Обязательное Описание
entityType String Да Тип сущности объекта.
objectId UUID Да ID объекта.
relatedEntityType UUID Да Тип связанной сущности.
fieldName String Да Поле, по которому построена связь.
reversed Boolean Да В каком направлении связь.
paging Paging Нет Параметры пейджинга.

DeleteObjectRelation (Data-model)

Удаление отношения между объектами сущностей. Название отнощения соответствует комбинации типов сущностей ${entity1Type}_to_${entity2Type}_on_${entity1Field}.

Поле Тип Обязательное Описание
entity1Type String Да Тип первой сущности из отношения.
entity2Type String Да Тип второй сущности из отношения.
entity1Field String Да Виртуальное поле отношения из первой сущности.
object1Id UUID Да ID объекта первой сущности.
object2Id UUID Да ID объекта второй сущности.

DeleteObjectRelations (Data-model)

Удаление отношения между объектами сущностей.

Поле Тип Обязательное Описание
entityType String Да Тип сущности.
objectId UUID Да ID объекта сущности.
relatedEntityTypes List[UUID] Да Перечень связанных типов сущностей.

UpdateExternalObjectRelations (Data-model)

Обновление списка отношений объекта с сущностью.

Поле Тип Обязательное Описание
entity1Type String Да Тип первой сущности из отношения.
entity2Type String Да Тип второй сущности из отношения.
entity1Field String Да Виртуальное поле отношения из первой сущности.
reversed Boolean Нет (по умолчанию false) Направление отношения. Если false, то objectId - объект сущности entity1Type, иначе - entity2Type.
objectId String Да Внешний ID объекта, для которого обновляются отношения.
relationObjectIds List[String] Да Внешний ID объектов, связанных отношением с обновляемым объектом.
source String Да Источник данных для отношений.

UpdateExternalObjectRelationResult (Data-model)

Результат добавления отношения между внешними объектами.

Поле Тип Обязательное Описание
relationObjectId String Да ID связанного объекта.
success Boolean Да Признак успешности создания связи.
error String Нет Описание ошибки, если произошла.

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

Поле Тип Описание
id UUID ID связи.
entityType1 String Тип сущности первого объекта из связи.
object1Id UUID ID первого объекта из связи.
entityType2 String Тип сущности второго объекта из связи.
object2Id UUID ID второго объекта из связи.
linkType String Тип связи, строковый код.
source String Источник связи. Для введенных вручную - manual, для созданных в сервисах интеллектуализации - auto.
owner String Создатель связи. Это может быть id пользователя, создавшего связь вручную, код или ID сервиса, создавшего связь автоматически.
additional JSON Произвольный JSON объект с дополнительными данными, специфичными для конкретного типа связи.

ObjectLinkWithObjects (Data-model)

Связь между двумя объектами сущностей. Включает информацию об объектах.

Поле Тип Описание
id UUID ID связи.
entityType1 String Тип сущности первого объекта из связи.
object1 EntityObject Первый объект.
entityType2 String Тип сущности второго объекта из связи.
object2 EntityObject Второй объект.
linkType String Тип связи, строковый код.
source String Источник связи. Для введенных вручную - manual, для созданных в сервисах интеллектуализации - auto.
owner String Создатель связи. Это может быть id пользователя, создавшего связь вручную, код или ID сервиса, создавшего связь автоматически.
additional JSON Произвольный JSON объект с дополнительными данными, специфичными для конкретного типа связи.

Получение списка связей объекта.

Поле Тип Обязательное Описание
entityType String Да Тип сущности объекта, для которого запрашиваются связи.
objectId UUID Да ID объекта, для которого запрашиваются связи.
linkTypes List[String] Нет Типы запрашиваемых связей. Может содержать несколько значений. Может быть пустым, тогда вернутся все доступные связи.
forwardLinks Boolean Да Признак получения прямых или обратных связей. Если true, тогда связи прямые, тогда искомый объект - это первый объект из связи (object1). Если false, тогда искомый объект - это второй объект из связи (object2).
linkedEntityType String Нет Тип сущности объектов на "другом конце" связи. Если связи прямые, то тип linkedEntityType должны иметь все вторые объекты из связи, а если обратные - то первый.

GetObjectRelationsByType (Data-model)

Получение списка связей для типов объектов.

Поле Тип Обязательное Описание
entityFrom String Да Тип сущности объекта, от которого идут запрашиваемые связи.
entityTo String Да Тип сущности объекта, к которому идут запрашиваемые связи.
field String Да Название поля, по которому идет связь.

Создание связи между объектами сущностей.

Поле Тип Обязательное Описание
entityType1 String Да Тип сущности первого объекта из связи.
object1Id UUID Да ID первого объекта из связи.
entityType2 String Да Тип сущности второго объекта из связи.
object2Id UUID Да ID второго объекта из связи.
linkType String Да Тип связи, строковый код. Длина не более 64 символов.
source String Да Источник связи. Для введенных вручную - manual, для созданных в сервисах интеллектуализации - auto. Длина не более 64 символов.
owner String Нет Создатель связи. Это может быть id пользователя, создавшего связь вручную, код или ID сервиса, создавшего связь автоматически. Длина не более 64 символов.
additional JSON Нет Произвольный JSON объект с дополнительными данными, специфичными для конкретного типа связи.
fileId1 UUID Нет Идентификатор файла из первого объекта, если связь строится на основании файла.
fileId2 UUID Нет Идентификатор файла из второго объекта, если связь строится на основании файла.

Удаление связей объекта.

Поле Тип Обязательное Описание
entityType String Да Тип сущности объекта, для которого удаляются связи.
objectId UUID Да ID объекта, для которого удаляются связи.
linkType String Нет Тип удаляемых связей. Может быть пустым, тогда удалятся все имеющиеся связи.
forwardLinks Boolean Да Признак удаления прямых или обратных связей. Если true, тогда связи прямые, тогда искомый объект - это первый объект из связи (object1). Если false, тогда искомый объект - это второй объект из связи (object2).

ObjectFileWithTags (Data-model)

ID файла и список его тегов.

Поле Тип Обязательное Описание
fileId UUID Да ID файла объекта.
tags List[String] Да Список тегов файла (кодов элемента справочника тегов).

FileInfoWithTags (Data-model)

Информация о файле, включая его теги и ссылку на родительский объект.

Поле Тип Обязательное Описание
objectIdentity EntityObjectIdentity Да ID объекта.
entityTypeTitle String Да Наименование типа объекта.
objectTitle String Да Наименование объекта.
fileInfo ObjectFileMeta Да Информация о файле.
tags List[String] Да Список тегов файла (кодов элемента справочника тегов).

ObjectFileMeta (Data-model)

Полная информация о файле.

Поле Тип Обязательное Описание
fileId UUID Да ID файла.
name String Нет Имя файла с расширением.
extension String Нет Расширение файла.
size Long Нет Размер файла в байтах.
url String Нет Ссылка на скачивание файла из файлового хранилища.
additional JSON Нет Объект с дополнительными параметрами.
created TimeStamp Нет Время загрузки файла.
modified TimeStamp Нет Время редактирования данной записи.
md5 String Нет Хеш файла.

FileIdentity (Data-model)

Полный идентификатор файла.

Поле Тип Обязательное Описание
fileId String Да ID файла.
entityType String Да Наименование типа объекта.
objectId String Да ID объекта.

ObjectWithKeywordsDTO (Data-model)

Тип и ID объекта и список его ключевых слов.

Поле Тип Обязательное Описание
entityType String Да Тип сущности объекта.
objectId UUID Да ID объекта.
keywords List[KeywordDTO] Да Список ключевых слов объекта.

KeywordDTO (Data-model)

Информация о ключевом слове.

Поле Тип Обязательное Описание
keyword String Да Ключевое слово.
pos String Да Часть речи.
weight Double Нет Вес ключевого слова по отношению к объекту.

ObjectWithKeywords (Data-model)

Тип и ID объекта и список его ключевых слов.

Поле Тип Обязательное Описание
objectId UUID Да ID объекта.
keywords List[KeywordWithWeight] Да Список ключевых слов объекта.

KeywordWithWeight (Data-model)

Информация о ключевом слове совмещенная с весом ключевого слова в объекте.

Поле Тип Обязательное Описание
keywordId UUID Да ID ключевого слова.
keyword String Да Ключевое слово.
pos String Да Часть речи.
weight Double Нет Вес ключевого слова по отношению к объекту.

Keyword (Data-model)

Ключевое слово.

Поле Тип Обязательное Описание
id UUID Да ID ключевого слова.
title String Да Ключевое слово.
pos String Да Часть речи.

GetMaxNumericFieldValue (Data-model)

Изменение части полей объектов (по поисковому запросу).

Поле Тип Обязательное Описание
entityType String Да Строковый код типа сущности.
search Search Да Параметры списочного запроса.
field String Да Название поля для которого нужно найти максимум.

ParentRelation (Data-model)

Родительская модель.

Поле Тип Обязательное Описание
entityType String Да Наименование типа объекта.
fieldId String Да Строковый код (название) поля.
nested List[ParentRelation] Да Все вышележащие родители.

ObjectStore (Data-model)

Объект сущности (модель базы данных).

Поле Тип Обязательное Описание
id UUID Да ID объекта.
externalId String Нет Внешний ID объекта.
title String Да Название объекта.
source String Да Источник данных для объекта.
created TimeStamp Да Дата и время создания объекта.
modified TimeStamp Да Дата и время последнего изменения объекта.
data JSON Да JSON с полями объекта.
additionalData JSON Да JSON с дополнительными полями объекта.
metadata JSON Да JSON с метаданными.
version Int Да Версия объекта для оптимистичных блокировок.
removed Boolean Да Признак того, считается ли объект удаленным.

EntityObject (Data-model)

Объект сущности.

Поле Тип Обязательное Описание
id UUID Да ID объекта.
externalId String Нет Внешний ID объекта.
entityType String Да Тип сущности объекта.
title String Да Название объекта.
source String Да Источник данных для объекта.
created TimeStamp Да Дата и время создания объекта.
modified TimeStamp Да Дата и время последнего изменения объекта.
data JSON Да JSON с полями объекта.
additionalData JSON Да JSON с дополнительными полями объекта.
metadata JSON Да JSON с метаданными.
version Int Да Версия объекта для оптимистичных блокировок.
removed Boolean Да Признак того, считается ли объект удаленным.

EntityObjectEvent (Data-model)

Событие об изменении сущности.

Поле Тип Обязательное Описание
eventType String Да Тип события (create, update, delete, reindex).
payloadId UUID Да ID объекта.
payloadType String Да Тип объекта (EntityTypeId).
payload EntityObject Да Сам объект.

EntityTypeEvent (Data-model)

Событие об изменении модели.

Поле Тип Обязательное Описание
eventType String Да Тип события (create, update, delete).
payloadId String Да Тип объекта (EntityTypeId).
payloadType String Да Константа, всегда равен EntityType.
payload EntityTypeEventBody Да Сам объект.

EntityTypeEventBody (Data-model)

Поле Тип Обязательное Описание
entityType EntityType Да Информация о сущности.

Работа с фильтрацией сервиса Data-model

Типы фильтров для полей сущности (Data-model)

Если поле для фильтрации имеет вид data.something или additionaldata.something, то фильтрация идет по соответствующим полям в data или additionalData. Для этих фильтров поддерживаются виды InSetQuery, LikeQuery, RangeQuery и AllInSetQuery (Только для вложенных полей-массивов. Не будет работать для relation-полей.). Каждый тип поля поддерживает свои типы фильтров. Таблица соответствия которых приведена ниже.

Тип поля Виды фильтров
Int, Double, Long, Float, Number InSetQuery, RangeQuery
TimeStamp InSetQuery, RangeQuery, LikeQuery
String InSetQuery, LikeQuery
UUID InSetQuery, LikeQuery
Boolean InSetQuery

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

Relation поля (Data-model)

Для указания фильтров или сортировки по определенному полю, можно использовать названия как полей конкретного типа сущности EntityObject, так и relation-полей для данного типа сущности.
Для фильтра/сортировки указывается полное название поля, относительно структуры EntityObject.
Также поддерживаются поля объектов, связанных через несколько relation с исходным, глубина не ограничена.

Примеры:

Фильтрация по разным значениям одного поля (Data-model)

Если есть необходимость фильтровать по сложному составному запросу, в котором имя одного поля появляется несколько раз, то можно воспользоваться тегами для полей. Например, можно составить такой запрос:

{
  "search": {
    "query": "(code:1 && title:1) || (code:2 && title:2)",
    "context": {
      "code:1": "10",
      "title:1": "like документ%",
      "code:2": "20",
      "title:2": "like журнал%"
    }
  }
}

Благодаря тегам, которые указываются после двоеточия в конце, появляется возможность различать фильтры в зависимости от их положения в query. Тегом может быть произвольная строка, содержащая в себе латинские символы, цифры и знаки _ и - (т.е. регулярное выражение ^[a-zA-Z0-9_-]*$).

Фильтрация по полям сущности (Data-model)

В рамках очередной доработки стали поддерживаться следующие варианты написания ключей кастомных полей в Search.query.

  1. Без указания data
    • Поле my_field принадлежит к текущей сущности, в Search.query можно указывать my_field
    • Поле my_field принадлежит к связанной сущности (поле relation_obj1) целевого объекта, в Search.query можно указывать relation_obj.my_field
    • Поле my_field принадлежит к связанной сущности (поле relation_obj2) для связанной сущности (поле relation_obj1) целевого объекта, в Search.query можно указывать relation_obj1.relation_obj2.my_field
  2. Указываем data иногда
    • Поле my_field принадлежит к связанной сущности (поле relation_obj1) целевого объекта с одинаковым результатом, в Search.query можно указывать:
      • data.relation_obj.my_field
      • relation_obj.data.my_field
    • Поле my_field принадлежит к связанной сущности (поле relation_obj2) для связанной сущности (поле relation_obj1) целевого объекта с одинаковым результатом, в Search.query можно указывать:
      • data.relation_obj1.relation_obj2.my_field
      • relation_obj1.data.relation_obj2.my_field
      • relation_obj1.relation_obj2.data.my_field
  3. Указываем data везде
    • Поле my_field принадлежит к текущей сущности, в Search.query можно указывать data.my_field
    • Поле my_field принадлежит к связанной сущности по полю relation_obj, в Search.query можно указывать data.relation_obj.data.my_field
    • Поле my_field принадлежит к связанной сущности (поле relation_obj2) для связанной сущности (поле relation_obj1) целевого объекта, в Search.query можно указывать data.relation_obj1.data.relation_obj2.data.my_field

Дополнительные уточнения по логике работы таких фильтров ниже.

Использование префикса data (Data-model)

Если поле содержится только среди системных полей объекта:

  1. указано значение без префикса data - возвращаются только объекты со значениями системных полей, удовлетворяющих условию фильтрации;
  2. указано значение c префиксом data - возвращается пустой список, т.к. "кастомного" поля, указанного в фильтре, не существует.

Если поле содержится только среди кастомных полей объекта:

  1. указано значение без префикса data - возвращаются все объекты со значениями кастомных полей, удовлетворяющих условию фильтрации;
  2. указано значение c префиксом data - возвращаются все объекты со значениями кастомных полей, удовлетворяющих условию фильтрации.

Если поля с одинаковым названием содержатся и в системных и в кастомных полях объекта:

  1. указано значение без префикса data - возвращаются все объекты со значениями системных полей, удовлетворяющих условию фильтрации;
  2. указано значение c префиксом data - возвращаются все объекты со значениями кастомных полей, удовлетворяющих условию фильтрации.

Методы Rich* (Data-model)

При получении объектов с помощью Rich* методов, помимо основных параметров, передаются требуемые поля объектов.
Поля могут быть из data или additionalData. Системные поля тоже можно указывать, но они в любом случае возвращаются всегда.
Для каждого возвращенного объекта JSON будет содержать только указанные в запросе поля.
Если нужно запросить все поля, то можно использовать символ * вместо имени конкретного поля (relation поля не будут возвращены).
Если никакое поле не указывать, то будут возвращены только системные поля. Это поведение сохраняется не только для корневого объекта, но и для связанных объектов.

Для указания списка допустимых полей для корневого объекта (не relation), используются "короткие" варианты названия полей (без указания поля data), т.к. все поля всегда находятся в JSON-объекте поля data.

При запросе полей relation-объекта, также происходит фильтрация его полей по списку "fields", но системные поля добавляются всегда (с префиксом, указанным в DATA_MODEL_RELATION_SYSTEM_FIELDS_PREFIX). Также можно запрашивать поля объектов, связанных через несколько relation с исходным, глубина не ограничена.

Запрашиваемые поля без данных или равных null не добавляются в результат.

Список системных полей из объекта EntityObject, которые добавляются всегда:
id, externalId, entityType, title, created, modified, version.

Для указания полей для relation-объектов, можно использовать все поля, которые есть в EntityObject, включая поля с файлами.

Примеры Rich-запросов (Data-model)

Для примеров используется следующая модель данных:

Order(number: String, name: String)
Person(name: String)
Address(text: String)
Order ссылается на Person через поле authors: Person[].
Person ссылается на Address через поле address: Option[Address].

Пример запроса RichGetObjects с указанием нужных полей

{
  "id": {
    "entityType": "Order",
    "objectId": "18b1011b-9db3-4186-a53c-971016030068"
  },
  "fields": [
    "name",                 // Order.name
    "authors.data.name",    // Полный путь к Person.name
    "authors.name",         // Короткая запись Person.name
    "authors.id",           // Системное поле EntityObject
    "authors",              // Запрос всех системных полей у всех связанных объектов (поле authors является списком)
    "authors.*",            // Wildcard для запроса всех существующих полей у связанного объекта (relation поля не возвращаются)
    "authors.address.text", // Длинный путь до поля у глубоко вложенного объекта
    "authors.address", // Запрос всех системных полей у глубоко вложенного объекта
    "authors.address.*"
    // Wildcard для запроса всех существующих полей у глубоко вложенного объекта (relation поля не возвращаются)
  ]
}

Результатом запроса будет объект EntityObject с полями связанных объектов в data

{
  "id": "18b1011b-9db3-4186-a53c-971016030068",
  "externalId": "ExternalOrder",
  "entityType": "Order",
  "title": "Аренда лошади",
  "source": "manual",
  "created": 1630326492,
  "modified": 1630326492,
  "data": {
    "name": "Test order",
    "authors": [
      {
        "_id": "505e7939-94e4-4c1a-b175-b622258d00fc",
        "_externalId": null,
        "_entityType": "Person",
        "_title": "First author",
        "_source": "manual",
        "_created": 1634553248859,
        "_modified": 1634553248859,
        "_version": 1,
        "name": "First author",
        "address": {
          "_id": "478bf14a-b1f9-46d4-b7fb-3b7ff3d8ca79",
          "_externalId": null,
          "_entityType": "Address",
          "_title": "Baker street",
          "_source": "manual",
          "_created": 1634553248859,
          "_modified": 1634553248859,
          "_version": 1,
          "text": "Baker street"
        }
      },
      {
        "_id": "66806625-ea74-4c9e-8fca-ccf1e1366e8b",
        "_externalId": null,
        "_entityType": "Person",
        "_title": "Second author",
        "_source": "manual",
        "_created": 1634553248859,
        "_modified": 1634553248859,
        "_version": 123,
        "name": "Second author",
        "address": null
      }
    ]
  },
  "additionalData": {},
  "version": 1
}

Фильтры для связанных сущностей (Data-model)

Обычные фильтры по связанным элементам влияют на корневой список элементов - в него попадают те объекты, для которых хотя бы один связанный объект удовлетворяет упомянутым фильтрам. На списки самих связанных объектов повлиять этими фильтрами нельзя - там все равно будут все элементы, которые связаны с корневыми.

Пример запроса RichGetObjects с указанием fieldSearches

{
  "id": {
    "entityType": "Order",
    "objectId": "18b1011b-9db3-4186-a53c-971016030068"
  },
  "fields": [
    "authors.data.name",
  ],
  "fieldSearches": {
    "authors": {
      "query": "data.name",
      "context": {
        "data.name": "like Иванов%"
      }
    }
  }
}

В rich запросах дополнительно можно указывать фильтры, которые будут применены только к связанным сущностям. На корневой список элементов они не повлияют.

Например, в примере запроса RichGetObjects, с помощью можно поля fieldSearches мы отфильтровываем авторов заказов ( authors) по префиксу для поля data.name.

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

{
  "entityType": "documentAPI",
  "search": {
    "query": "UNKNOWN.data.source",
    "context": {
      "UNKNOWN.data.source": "manual"
    },
    "sorting": {
      "fieldName": "created",
      "order": "asc"
    },
    "paging": {
      "page": 1,
      "count": 10
    }
  }
}

Revisions (Data-model)

Существует механизм версионирования для сущностей, у которых указано поле revisionConfig в settings. Такие сущности обладают двумя особенностями:

1) При создании новой актуальной ревизии (или выставлении этого признака у существующей) предыдущая становится неактуальной. 2) При изменении, создании или удалении актуальной ревизии посылается событие об изменении родительского объекта.

Поле revisionConfig имеет следующий вид:

{
  "parentFieldCode": "parent",
  "actualityFieldCode": "isActual"
}

parentFieldCode - поле, ссылающееся на родительскую сущность, по отношению к которой эта сущность является версией.

actualityFieldCode - поле сущности, индикатор актуальности версии. Это должно быть обязательное поле типа Boolean.

Использование AllInSet в запросах (Data-model)

Запрос для поиска книг с рыжими и темноволосыми авторами (на данный момент не работает)

Search(
  query = "authors.data.hairColor",
  context = Map(
    "authors.data.hairColor" -> Json.arr(Json.fromString("black"), Json.fromString("red")),
    "kind" -> Json.fromString("all")
  )
)

Запрос для поиска книг с авторами, знающими русский и английский языки (на данный момент не работает)

Search(
  query = "authors.data.languages",
  context = Map(
    "authors.data.languages" -> Json.arr(Json.fromString("ru"), Json.fromString("en")),
    "kind" -> Json.fromString("all")
  )
)

На данный момент AllInSetQuery не работает для relation-полей.

Если объект Book связан с объектом Person по полю authors, то мы не сможем найти только книги у которых в массиве авторов, есть и рыжие, и черноволосые авторы, с помощью запроса AllInSet.

Также если объект Book связан с объектом Person по полю authors, а у Person есть поле-массив languages, то мы не сможем найти все книги, в которых конкатенация языков авторов содержит и русский, и английский, с помощью запроса AllInSet.

Публикуемые события (Data-model)

Сервис отправляет события об изменении модели и объектов в топик DATA_MODEL_KAFKA_ENTITY_OBJECT_EVENT_TOPIC.

События об изменении объектов (Data-model)

{
  "eventType": "create",
  "payloadId": "1627c316-6de9-4c16-b43a-4d293a7805ea",
  "payloadType": "Company_0D33",
  "payload": {
    "additionalData": null,
    "entityObject": {
      "additionalData": {},
      "created": 1739953317862,
      "data": {
        "title": "123435"
      },
      "entityType": "Company_0D33",
      "externalId": null,
      "id": "1627c316-6de9-4c16-b43a-4d293a7805ea",
      "metadata": {},
      "modified": 1750742233664,
      "removed": false,
      "source": "manual",
      "title": "123435",
      "version": 1
    }
  }
}

Тип данных - EntityObjectEvent

Примечание - при удалении сущности посылается события на удаление всех ее существующих объектов.

События об изменении модели (Data-model)

События посылаются только на миграции CreateEntity, UpdateEntity, DeleteEntity. Изменение полей или relation сущности не посылают события.

{
  "eventType": "create",
  "payloadId": "Test2",
  "payloadType": "EntityType",
  "payload": {
    "entityType": {
      "description": "",
      "id": "Test2",
      "settings": {},
      "title": "test"
    }
  }
}

Тип данных - EntityTypeEvent

Data-model-client: клиент для сервиса Data-model

client.saveObject(EntityTypeId("test"), TestClass("kek", 123), "manual")
client.getObject[TestClass](EntityTypeId("test"), objectId)

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

Регистрация в distage

case class ClientsModule[F[_]: Async: ContextShift: TagK]() extends ModuleDef {
    make[DataModelClient[F]].from { (dispatcher: Dispatcher) =>
        new DataModelClientImpl(dispatcher)
    }
}

В distage сам клиент можно зарегистрировать следующим способом:

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

make[DataModelMigratorF[F]].from { (client: DataModelClient[F], migrations: Seq[Migration]) =>
    new DataModelMigratorF(client, migrations)
}

Мигратор можно подключить следующим образом:

Далее, чтобы запустить миграции можно получить DataModelMigrator из контейнера и выполнить migrator.migrate.

Метод migrate вызывает комманду сервиса createDataModel(). В случае каких-то проблем из метода возвращается ошибка, повторная отправка запросов не производится.

Команда Метод клиента
getFieldTypes getFieldTypes
getRelationTypes getRelationTypes
getDataModel getDataModel
getAllDataModels getAllDataModels
getEntityParents getEntityParents
createDataModel createDataModel
listDataModels listDataModels
saveObject saveObject
saveObjectBatch saveObjectBatch
saveExternalObject saveExternalObject
updateObject updateObject
updateExternalObject updateExternalObject
updateObjectFields updateFields
internalUpdateObjectFields internalUpdateFields
updateObjectFieldsList updateFieldsList
updateObjectFieldsBatch updateFieldsBatch
deleteObject deleteObject
softDeleteObject softDeleteObject
deleteObjectBatch deleteObjectBatch
softDeleteObjectBatch softDeleteObjectBatch
deleteObjectSearch deleteObjectSearch
softDeleteObjectSearch softDeleteObjectSearch
deleteExternalObject deleteExternalObject
saveAdditionalInfo saveObjectAdditionalInfo
saveObjectMetadata saveObjectMetadata
saveObjectMetadataBatch saveObjectMetadataBatch
saveFilesAdditionalInfo saveFilesAdditionalInfo
getObject getObject
internalGetObject internalGetObject
getExternalObject getExternalObject
getExampleObject getExampleObject
listObjects listObjects
listNonExistingFileId listNonExistingFileId
getObjectsBatch getObjectBatch
richGetObject richGetObject
internalRichGetObject internalRichGetObject
internalRichListObject internalRichListObject
richListObjects richListObjects
richGetObjectsBatch richGetObjectsBatch
listObjectsMeta listObjectsMeta
listObjectTitles listObjectTitles
listObjectTitlesV2 listObjectTitlesV2
getObjectPosition getObjectPosition
getEntityFieldAggregation getEntityFieldAggregation
reindexObject reindexObject
saveRelation saveRelation
saveRelationBatch saveRelationBatch
getRelation getRelation
listRelations listObjectRelations
listAllRelations listAllRelations
listRelationsBatch listRelationsBatch
listRelationsByType listRelationsByType
deleteRelation deleteRelation
deleteRelations deleteRelations
deleteAllRelations deleteAllRelations
updateExternalRelations updateExternalRelations
getObjectLink getLink
getObjectLinks getLinks
createObjectLink createLink
createObjectsLinks createObjectLinks
deleteObjectLink deleteObjectLink
deleteAllObjectLinks deleteAllObjectLinks
listFilesInfoWithTags listFilesInfoWithTags
listTagsWithFilesCount listTagsWithFilesCount
listFileExtensions listFileExtensions
writeFileTags writeFileTags
removeFileTags removeFileTags
removeAllFileTags removeAllFileTags
getFile getFile
updateKeywords updateKeywords
listObjectKeywords listObjectKeywords
listKeywords listKeywords
internalGetMaxNumericFieldValue internalGetMaxNumericFieldValue

Erika: сервис печатных форм

В сервисе реализованы следующие команды:

Конфигурирование сервиса Erika

Список переменных окружения сервиса Erika

Переменная Тип Обязательная Значение по умолчанию Описание
SERVER_PORT int нет 8080 Порт, на котором слушает HTTP-сервер.
SERVICE_TIMEOUTS_ENABLED bool нет false Действуют ли переменные SERVER_IDLE_TIMEOUT и SERVER_RESPONSE_TIMEOUT.
SERVER_IDLE_TIMEOUT duration string нет 2 hours Period of Time a connection can remain idle before the connection is timed out and disconnected. Не рекомендован к использованию, так как не отменяет операцию обработки файла. По умолчанию отключен. Для аналогичных целей можно рассмотреть использование PROCESSING_TIMEOUT и query-параметра timeoutSeconds.
SERVER_RESPONSE_TIMEOUT duration string нет 1 hour Time from when the request is made until a response line is generated before a 503 response is returned and the HttpApp is canceled. Не рекомендован к использованию, так как не отменяет операцию обработки файла. По умолчанию отключен. Для аналогичных целей можно рассмотреть использование PROCESSING_TIMEOUT и query-параметра timeoutSeconds.
PROCESSING_QUEUE_SIZE int нет 5 Размер очереди для всех задач, т.е. уровень буферизации.
PROCESSING_WORKERS_COUNT int нет 2 Количество воркеров, т.е. уровень параллельности.
PROCESSING_FILE_READ_CHUNK_SIZE int нет 16384 Размер буфера в байтах для результатов генерации отчетов.
PROCESSING_TIMEOUT duration string нет 10 minutes Таймаут на выполнение задачи воркером. Отменяет операцию обработки файла.
PROCESSING_GROUP_MAX_PARALLELISM int нет 5 Параллелизм обработки групп отчетов.
PROCESSING_IMAGES_DIR string нет /tmp Директория для скачивания изображений.
PROCESSING_FIX_JUSTIFY bool нет false Костыль для корректного отображения на фронте сгенерированных pdf файлов.
PROCESSING_FULLNESS_LIMIT int нет 10 Тоже отчасти костыль, который ограничивает время, в течении которого все воркеры могут быть заняты. Добавлен, т.к. spire.doc регулярно падает в бесконечный цикл, и свободные воркеры заканчиваются.
PROCESSING_WATCHER_DURATION duration string нет 5 seconds Периодичность проверки на исчерпание воркеров. При достижении PROCESSING_FULLNESS_LIMIT следующая проверка завершит приложение.
SPIRE_DOC_LICENSE_KEY string нет "" Лицензионный ключ библиотеки spire.doc Если оставить пустым то будет работать в режиме trial-версии.
PROCESSING_PDF_BUCKET string нет pdf Название бакета в файловом хранилище для хранения pdf-файлов. Бакет с указанным именем автоматически создается при старте сервиса. Если эта переменная равна пустой строке, то бакет не создается при старте.
PROCESSING_REPORT_BUCKET string нет report Название бакета в файловом хранилище для хранения сгенерированных отчетов. Бакет с указанным именем автоматически создается при старте сервиса. Если эта переменная равна пустой строке, то бакет не создается при старте.
PROCESSING_GENERATION_VERSION int нет 1 Версия генерации отчёта. Подробнее: страница Confluence посвященная шаблонам.
VERDI_CONSUL string нет (если сервис используется без verdi) http://localhost:8500 Адрес Consul.
VERDI_CONSUL_AUTH_USER string нет "" Название учетной записи Сonsul. Если название не указано, то настройки авторизации не будут применены.
VERDI_CONSUL_AUTH_PASSWORD string нет "" Пароль учетной записи Сonsul.
VERDI_KAFKA_AUTH_PRINCIPAL string нет "" Principal учетной записи Kafka в Kerberos(в случае соединения с kafka через Kerberos).
VERDI_KAFKA_AUTH_KEYTAB_PATH string нет "" Путь до keytab-файла (в случае соединения с kafka через Kerberos).
VERDI_KAFKA_ADDRESS string да localhost:9092 Адрес брокера Kafka.
VERDI_KAFKA_TOPIC string нет commandevents Название кафка-топика для отправки сообщений со статусами выполняемых команд. ОБЯЗАТЕЛЬНО должно соответствовать названию этого топика в сервисе статуса команд.
VERDI_COMMANDS_TOPIC string нет erika Название топика для команд.
VERDI_CONSUMER_GROUP string нет erika_consumer_group Название consumer-группы для чтения команд.
VERDI_KAFKA_AUTH_USER string нет "" Название учетной записи Kafka. Если название не указано, то настройки авторизации не будут применены.
VERDI_KAFKA_AUTH_PASSWORD string нет "" Пароль учетной записи Kafka.
VERDI_KAFKA_AUTH_TRUSTSTORE_LOCATION string нет "" Путь до хранилища сертификатов (Java key store). Если путь не указан, то сертификат применяться не будет.
VERDI_KAFKA_AUTH_TRUSTSTORE_PASSWORD string нет "" Пароль к хранилищу сертификатов.
VERDI_KAFKA_AUTH_MODE string нет "" Режим аутентификации: static - одна учетная запись на все запросы, mapping - учетная запись зависит от запроса.
VERDI_KAFKA_AUTH_CONFIG string нет "" Настройки для аутентификации: если AuthMode = mapping, то необходим JSON с List[KafkaAuthConfig]. Переменная соответствует полю authConfig из KafkaAuthSettings.
VERDI_KAFKA_AUTH_CACHE_SIZE int нет Максимальный размер кеша для Kafka producer (количество активных соединений).
VERDI_KAFKA_CONNECTION_CHECK_TEST_MESSAGES_INTERVAL duration string нет 4 minutes Применяется только для producer-ов со способом аутентификации kerberos. Интервал отправки тестовых сообщений кафки в топик connectionCheck.testMessagesTopicName. Тестовые сообщения (null, service producer test) отправляются регулярно с этим интервалом.
VERDI_KAFKA_CONNECTION_CHECK_INTERVAL duration string нет 60 seconds Применяется только для producer-ов со способом аутентификации kerberos. Интервал проверки того, сколько тестовых сообщений было отправлено за данный период. Если количество сообщений за этот период равно количеству сообщений за прошлый период, то начинается отсчет периода без сообщений.
VERDI_KAFKA_CONNECTION_CHECK_FAILED_AFTER_INTERVAL duration string нет 5 minutes Применяется только для producer-ов со способом аутентификации kerberos. Максимальная продолжительность периода без успешно отправленных тестовых сообщений. По ее достижении сервис будет объявлен больным.
VERDI_KAFKA_AUTH_CACHE_TTL duration string нет Время жизни Kafka producer в кеше.
VERDI_HOST string нет (если сервис используется без verdi) localhost Хост, публикуемый в ServiceDiscovery. По нему на данный сервис будут обращаться другие через HTTP. Указанный адрес должен быть виден другим сервисам. Пример: имя kubernetes/docker_swarm service.
VERDI_TTL duration string нет 30 seconds Период после последней отправки health check, в течение которого ServiceDiscovery считает данный сервис живым.
VERDI_HEALTH_CHECK duration string нет 10 seconds Периодичность отправки health check в ServiceDiscovery.
VERDI_COMMAND_STORAGE_UPDATE_PERIOD duration string нет 1 minutes Время кэширования данных по командам из CommandDiscovery.
VERDI_SERVICE_DISCOVERY_UPDATE_PERIOD duration string нет 30 seconds Время кэширования данных по сервисам из ServiceDiscovery.
VERDI_ALLOW_INTERNAL_COMMANDS bool нет true Можно ли сервису отправлять внутрисистемные команды.
VERDI_CONSIDER_ALL_COMMANDS_AS_INTERNAL boolean Нет false Флаг, определяющий будут ли все обращения в другие сервисы являться внутренними (т.е. не требовать авторизацию). Детальное описание механизма: Внутренние команды.
VERDI_CONSUL_CONNECTION_MAX_RETRY int нет 5 Максимальное количество попыток подключений к Consul.
VERDI_CONSUL_CONNECTION_RETRY_DELAY duration string нет 1 seconds Таймаут между неудачными попытками подключения к Consul.
FS_URI url string нет (если сервис используется без verdi) http://localhost:9002 Адрес S3 файлового хранилища minio.
FS_ACCESS_KEY_ID string нет (если сервис используется без verdi) admin Идентификатор доступа к minio.
FS_SECRET_ACCESS_KEY string нет (если сервис используется без verdi) admin Секретный ключ доступа к minio.
FS_UPLOAD_PARALLELISM int нет 4 Параллелизм загрузки файлов в minio.
FS_AUTH_MODE string нет static Режим аутентификации: static - одна учетная запись на все запросы, mapping - учетная запись зависит от запроса.
FS_AUTH_CONFIG string нет "" Настройки для аутентификации: если AuthMode = mapping, то необходим JSON с маппингом учетных записей.
FS_CACHE_SIZE int нет 1 Максимальный размер кеша клиентов для хранилища файлов (количество активных соединений).
FS_CACHE_TTL duration string нет Время жизни клиента в кеше.
FS_RETRY_ATTEMPTS int нет 5 Количество ретраев, которое будет произведено в случае Exception-а в операции FSClient-а и при вычитывании стрима в get операциях FSClient-а.
FS_RETRY_DELAY duration string нет 10 millis Задержка между ретраями операций FSClient-а.
FS_ZIO_SHORT_MESSAGE_MODE boolean нет false Флаг включения режима сохранения ошибок работы с файловым хранилищем в сервисе журналирования nestor. При включении режима ошибки в логах будут отображаться в сокращенном формате: Short zio message mode. ExceptionType: ТИП ОШИБКИ, Exception id: 'СГЕНЕРИРОВАННЫЙ UUID' added to journal. Указанный id будет фиксироваться в event записи nestor'а в поле data.id
VERDI_ALLOWED bool нет true Интеграция сервиса с verdi.
VERDI_COMMANDS_HTTP_RETRY_ATTEMPTS int нет 5 Поле attempts из RetrySettings.
VERDI_COMMANDS_HTTP_RETRY_DELAY duration string нет 5 seconds Поле delay из RetrySettings.
VERDI_COMMANDS_HTTP_RETRY_KIND string нет OnSomeExceptions(ConnectException) CommandResultRetryConditionKind.
DISABLE_FONTS_DOWNLOAD bool нет false Определяет, будет ли отключено скачивание шрифтов. Если указать значение "true", то перед стартом сервиса будет выполняться загрузка шрифтов. Если загрузка завершиться с ошибкой, то сервис не будет запущен.
S3_FONTS_STORE_DIR string нет (если DISABLE_FONTS_DOWNLOAD != true) /usr/share/fonts/truetype/msttcorefonts/ Путь до папки куда будут скачены шрифты.
S3_FONTS_URL string нет (если DISABLE_FONTS_DOWNLOAD != true) Адрес S3, в котором хранятся шрифты. Например, https://storage.yandexcloud.net.
S3_FONTS_PATH string нет (если DISABLE_FONTS_DOWNLOAD != true) erika-fonts/fonts Путь до бакета, который содержит файлы со шрифтами (один файл = один шрифт). Например, erika-fonts/fonts.
S3_FONTS_ACCESS_KEY string нет (если DISABLE_FONTS_DOWNLOAD != true) Идентификатор доступа к S3-совместимому хранилищу.
S3_FONTS_SECRET_KEY string нет (если DISABLE_FONTS_DOWNLOAD != true) Секретный ключ доступа к S3-совместимому хранилищу.
JOURNAL_MODE string нет WriteToJournal Режим журналирования Nestor. Допустимые значения: WriteToJournal (Отправка в сервис журналирования), WriteToTopic (Отправка события в очередь)
JOURNAL_TOPIC string да, если переменная JOURNAL_MODE = WriteToTopic "" Название очереди журналирования. Для режима WriteToJournal значение игнорируется.

Поддерживаемые форматы для конвертации сервиса Erika

Модели сервиса Erika

Progress

Прогресс генерации группы отчетов

Название поля Тип Описание
id UUID Идентификатор генерации
rowCount Int Общее кол-во групп
rowNumber Int Кол-во обработанных групп

StampedDocumentForm

Форма для конвертации документа со штампом

Название поля Тип Описание
file File Документ для конвертации
stamp File Штамп
stampHeight Float Высота штампа
stampWidth Float Ширина штампа

MergeMode

Тип-сумма режимов объединения групп документов

AllInOne

Группа документов объединяется в один документ. Часть тип-суммы MergeMode

Zip

Группа документов объединяется в один архив. Часть тип-суммы MergeMode

GenerateMode

Тип-сумма режимов генерации отчетов

Single

Режим генерации единичного отчета. Часть тип-суммы GenerateMode

GroupGeneration

Режим генерации группы отчетов. Часть тип-суммы GenerateMode

Название поля Тип Описание
mergeMode MergeMode Режим объединения групп документов
progressQueue Option[zio.Queue[Progress]] Опциональная очередь для отслеживания прогресса

ReportCommand

Данные для генерации отчета

Название поля Тип Обязательное Описание
mode GenerateMode да Режим генерации отчета
name string нет Имя файла. Расширение (и имя, если не указано) подставляется от шаблона.
templateFile com.embedika.verdi.fsClient.StoredFile да Ссылка на шаблон отчета
json io.circe.JsonObject да Данные отчета
ownerUserId UserId нет Идентификатор пользователя, которому будет предоставлен доступ к сгенерированному файлу через контроль доступа fsclient.

ConvertToPdf2Command

Данные для конвертации файла в pdf

Название поля Тип Обязательное Описание
file com.embedika.verdi.fsClient.StoredFile да Исходный файл
ownerUserId UserId да Идентификатор пользователя, которому будет предоставлен доступ к сгенерированному файлу через контроль доступа fsclient.

Команды сервиса Erika

createReport

На входе данные для генерации отчета

{
  "mode": "single",
  "name": "new_report",
  "templateFile": "/tmp/55497df9-bf03-4364-bada-881bbd5531f8",
  "json": {
    "key": "value"
  },
  "ownerUserId": "32d96be5-2945-4605-8962-b4ff2797653e"
}

В результате ссылка на файл отчета

"/report/55497df9-bf03-4364-bada-881bbd5531f8"

Создание отчета. При указании в переданном ReportCommand значения в ownerUserId, полученный файл будет доступен для скачивания только пользователю с указанным идентификатором.

Имя вызова команды: createReport.
Поддерживается только синхронный вызов.
Результат выполнения команды не журналируется.

createReportAsync

На входе данные для генерации отчета

{
  "mode": "single",
  "name": "new_report",
  "templateFile": "/tmp/55497df9-bf03-4364-bada-881bbd5531f8",
  "json": {
    "key": "value"
  },
  "ownerUserId": "32d96be5-2945-4605-8962-b4ff2797653e"
}

В результате ссылка на файл отчета

"/report/55497df9-bf03-4364-bada-881bbd5531f8"

Создание отчета. При указании в переданном ReportCommand значения в ownerUserId, полученный файл будет доступен для скачивания только пользователю с указанным идентификатором.

Асинхронная версия команды createReport.

Имя вызова команды: createReportAsync.
Поддерживается асинхронный и синхронный вызов.
Результат выполнения команды не журналируется.

extractVars

На входе ссылка на шаблона отчета

"/tmp/55497df9-bf03-4364-bada-881bbd5531f8"

В результате возвращаются переменные из шаблона в виде строки с JSON массивом

"[ \"key1\", \"key2\" ]"

Извлечение переменных.

Имя вызова команды: extractVars.
Поддерживается только синхронный вызов.
Результат выполнения команды не журналируется.

extractVarsAsync

На входе ссылка на шаблона отчета

"/tmp/55497df9-bf03-4364-bada-881bbd5531f8"

В результате возвращаются переменные из шаблона в виде строки с JSON массивом

"[ \"key1\", \"key2\" ]"

Извлечение переменных.

Асинхронная версия команды extractVars.

Имя вызова команды: extractVarsAsync.
Поддерживается асинхронный и синхронный вызов.
Результат выполнения команды не журналируется.

convertToPdf

На входе ссылка на файл для конвертации

"temp/55497df9-bf03-4364-bada-881bbd5531f8"

В результате ссылка на pdf версию

"pdf/55497df9-bf03-4364-bada-881bbd5531f8"

Конвертация в pdf без реализации контроля доступа к сгенерированному файлу. Поддерживаются файлы с расширениями. Исходный файл для конвертации поднимается из файлового хранилища без проверки на доступ для текущего пользователя.

Имя вызова команды: convertToPdf.
Поддерживается только синхронный вызов.
Результат выполнения команды не журналируется.

convertToPdfAsync

На входе ссылка на файл для конвертации

"temp/55497df9-bf03-4364-bada-881bbd5531f8"

В результате ссылка на pdf версию

"pdf/55497df9-bf03-4364-bada-881bbd5531f8"

Конвертация в pdf без реализации контроля доступа к сгенерированному файлу. Поддерживаются файлы с расширениями. Исходный файл для конвертации поднимается из файлового хранилища без проверки на доступ для текущего пользователя.

Асинхронная версия команды convertToPdf.

Имя вызова команды: convertToPdfAsync.
Поддерживается асинхронный и синхронный вызов.
Результат выполнения команды не журналируется.

convertToPdf2

На входе данные для конвертации

{
  "file": "temp/55497df9-bf03-4364-bada-881bbd5531f8",
  "ownerUserId": "55497df9-bf03-4364-bada-881bbd5531f8"
}

В результате ссылка на pdf версию

"pdf/55497df9-bf03-4364-bada-881bbd5531f8"

Конвертация в pdf c контролем доступа к сгенерированному файлу. Поддерживаются файлы с расширениями. В отличии от ConvertToPdf исходный файл для конвертации поднимается из файлового хранилища с проверкой на доступ для текущего пользователя.

Имя вызова команды: convertToPdf2.
Поддерживается только синхронный вызов.
Результат выполнения команды не журналируется.

convertToPdf2Async

На входе данные для конвертации

{
  "file": "temp/55497df9-bf03-4364-bada-881bbd5531f8",
  "ownerUserId": "55497df9-bf03-4364-bada-881bbd5531f8"
}

В результате ссылка на pdf версию

"pdf/55497df9-bf03-4364-bada-881bbd5531f8"

Конвертация в pdf c контролем доступа к сгенерированному файлу (асинхронная версия). Поддерживаются файлы с расширениями. В отличии от ConvertToPdf исходный файл для конвертации поднимается из файлового хранилища с проверкой на доступ для текущего пользователя.

Асинхронная версия команды convertToPdf2.

Имя вызова команды: convertToPdf2Async.
Поддерживается асинхронный и синхронный вызов.
Результат выполнения команды не журналируется.

Работа с сервисом erika без использования apigateway

К сервису erika можно обращаться напрямую, без использования apigateway. Для этого существуют следующие http-руты:

/report

Аналог команды createReport.

На входе(режим конвертации single)

curl --request POST \
--url http://myhost/report/single?timeoutSeconds=20 \
--header 'content-type: multipart/form-data' \
--form 'file=@myFile.docx' \
--form 'json=@one.json'
curl --request POST \
--url http://myhost/report/merge?timeoutSeconds=20 \
--header 'content-type: multipart/form-data' \
--form 'file=@myFile.docx' \
--form 'json=@mergeJson.json'
curl --request POST \
--url http://myhost/report/zip?timeoutSeconds=20 \
--header 'content-type: multipart/form-data' \
--form 'file=@myFile.docx' \
--form 'json=@mergeJson.json'

Query-параметр timeoutSeconds во всех случаях является опциональным и определяет то, через сколько секунд после начала обработки файла воркером стоит отменить эту операцию. В эту обработку входит как загрузка файла, так и создание отчета, но не входит время ожидания в очереди файлов на обработку. Если параметр timeoutSeconds не был передан, то операция будет отменена только в том случае, если сработает таймаут PROCESSING_TIMEOUT. При этом PROCESSING_TIMEOUT не сработает, если timeoutSeconds был передан. Таймауты SERVER_IDLE_TIMEOUT и SERVER_RESPONSE_TIMEOUT продолжают действовать даже при наличии timeoutSeconds.

На выходе (режим конвертации single)

Бинарное содержимое файла с расширением .docx и header Content-Disposition. В файл myFile.docx подставлены данные из one.json.

На выходе (режим конвертации merge)

Бинарное содержимое файла с расширением .docx и header Content-Disposition. В файл myFile.docx поочередно подставлены данные из массива внутри mergeJson.json. Получено несколько файлов .docx, которые склеены в один большой .docx файл, возвращенный в результате.

На выходе (режим конвертации zip)

Бинарное содержимое файла с расширением .zip и header Content-Disposition. В файл myFile.docx поочередно подставлены данные из массива внутри mergeJson.json. Получено несколько файлов .docx, которые упакованы в zip-архив, возвращенный в результате.

Подробнее про формирование header-а Content-Disposition можно прочитать в документации сервиса apigateway

/convert

Аналог команды convertToPdf.

На входе

curl --request POST \
--url 'http://myhost/convert?timeoutSeconds=20' \
--header 'content-type: multipart/form-data' \
--form 'file=@myFile.doc'

Query-параметр timeoutSeconds во всех случаях является опциональным и определяет то, через сколько секунд после начала обработки файла воркером стоит отменить эту операцию. В эту обработку входит как загрузка файла, так и создание отчета, но не входит время ожидания в очереди файлов на обработку. Если параметр timeoutSeconds не был передан, то операция будет отменена только в том случае, если сработает таймаут PROCESSING_TIMEOUT. При этом PROCESSING_TIMEOUT не сработает, если timeoutSeconds был передан. Таймауты SERVER_IDLE_TIMEOUT и SERVER_RESPONSE_TIMEOUT продолжают действовать даже при наличии timeoutSeconds.

На выходе

Бинарное содержимое файла с расширением .pdf и header Content-Disposition. Подробнее про формирование header-а можно прочитать в документации сервиса apigateway

Event-status: сервис информации о событиях

Сервис принимает запросы для работы со статусом обработки событий. На данный момент все состояние сервиса хранится в памяти. Команды могут приходить как по HTTP, так и через Kafka в топик event_status_commands.

В сервисе реализованно 2 команды:

Сервис разбит на несколько модулей, в виде sbt проектов:

Информация по добавлению команд можно прочитать в описании шаблона

Локальный запуск сервиса Event Status

При запуске сервиса ожидается, что уже развернута необходимая инфраструктура:

Запуск из консоли с помощью SBT сервиса Event Status

EVENT_STATUS_DB_HOST=localhost EVENT_STATUS_DB_PORT=5432 EVENT_STATUS_DB_NAME=eventStatus_db EVENT_STATUS_DB_USER=$EVENT_STATUS_DB_USER EVENT_STATUS_DB_PASSWORD=$EVENT_STATUS_DB_PASSWORD sbt boot/run

Список переменных окружения сервиса Event Status

Все доступные переменные окружения для настройки сервиса.

Переменная Тип Обязательная Значение по умолчанию Описание
EVENT_STATUS_HTTP_HOST string нет "0.0.0.0" Хост, на котором слушает HTTP-сервер
EVENT_STATUS_HTTP_PORT int нет 8192 Порт, на котором слушает HTTP-сервер
EVENT_STATUS_KAFKA_SERVERS string да "localhost:9092" Адрес Kafka
EVENT_STATUS_KAFKA_TOPIC string нет "event_status_commands" Название кафка-топика для получения команд. Сервис получает кафка-команды по нему, но и также сам публикует это название в CommandDiscovery.
EVENT_STATUS_KAFKA_CONSUMER_GROUP string нет "event_status_consumer_group" Имя consumer-группы для чтения из кафка-топика команд. Не должна меняться и не должна быть пустой, иначе сервис перечитает свои команды при перезапуске.
EVENT_STATUS_KAFKA_PARTITIONS int нет 10 Число читаемых партиций из кафка-топика команд.
EVENT_STATUS_KAFKA_CONSUMER_RESTART_MIN_BACKOFF duration string нет 1 second Изначальная задержка до рестарта консьюмера после падения (увеличивается в 2 раза после каждого рестарта)
EVENT_STATUS_KAFKA_CONSUMER_RESTART_MAX_BACKOFF duration string нет 30 seconds Максимальное задержка до рестарта консьюмера после падения
EVENT_STATUS_KAFKA_CONSUMER_RESTART_RANDOM_FACTOR double нет 0.2 Коэффициент величины дополнительной случайной задержки (jitter) относительно основной задержки (При значении 0.2 задержка может быть до 20% больше, чем при 0). Если после умножения задержки на EVENT_STATUS_KAFKA_CONSUMER_RESTART_RANDOM_FACTOR получится меньше 1 миллисекунды, то jitter будет приравнен к нулю.
EVENT_STATUS_KAFKA_CONSUMER_RESTART_MAX_RESTARTS int нет 5 Максимальное число рестартов консьюмера после падения (в пределах EVENT_STATUS_KAFKA_CONSUMER_RESTART_MAX_RESTARTS_WITHIN). После превышения этого числа сервис будет объявлен больным. Все рестарты для каждого отдельного сообщения увеличивают и общий счетчик рестартов консьюмера, поэтому при использовании EVENT_STATUS_KAFKA_CONSUMER_PER_MESSAGE_RESTART_MAX_RESTARTS нужно указывать EVENT_STATUS_KAFKA_CONSUMER_RESTART_MAX_RESTARTS > EVENT_STATUS_KAFKA_CONSUMER_PER_MESSAGE_RESTART_MAX_RESTARTS или не указывать EVENT_STATUS_KAFKA_CONSUMER_PER_MESSAGE_RESTART_MAX_RESTARTS совсем
EVENT_STATUS_KAFKA_CONSUMER_RESTART_MAX_RESTARTS_WITHIN duration string нет 5 minutes Временной отрезок, в который EVENT_STATUS_KAFKA_CONSUMER_RESTART_MAX_RESTARTS ограничивает число рестартов
EVENT_STATUS_KAFKA_CONSUMER_PER_MESSAGE_RESTART_MAX_RESTARTS int нет 2 Максимальное количество раз, которое консьюмер перезапустится с неизменной очередью сообщений (в пределах DATA_MODEL_KAFKA_CONSUMER_RESTART_MAX_RESTARTS_WITHIN), прежде чем проигнорировать сообщение, на котором происходит ошибка (Указано количество рестартов, а не прочтений. Если EVENT_STATUS_KAFKA_CONSUMER_RESTART_MAX_RESTARTS = 2, то ошибочное сообщение будет обработано 3 раза, после чего произойдет 3ий рестарт и оно будет проигнорировано). Если указать 0, то перезапуск произойдет, но сообщение будет обработано только в первый раз, когда произошла ошибка. Если указать значение меньше 0, то перезапуски все равно будут происходить, но игнорирование сообщений, вызывающих ошибку, будет отключено.
EVENT_STATUS_KAFKA_CONSUMER_PER_MESSAGE_RESTART_CACHE_SIZE int нет 100 Для каждого сообщения счетчик перепрочтений хранится в кэше. Максимальное количество значений в этом кэше.
EVENT_STATUS_KAFKA_CONSUMER_PER_MESSAGE_RESTART_CACHE_TTL duration string нет 5 minutes Для каждого сообщения счетчик перепрочтений хранится в кэше. Максимальное время жизни элемента в этом кэше. В случае отсутствия значения время жизни элемента не будет ограничено.
EVENT_STATUS_KAFKA_CONSUMER_POLL_TIMEOUT duration string нет 10 milliseconds timeout запроса poll для kafka consumer
EVENT_STATUS_KAFKA_CONSUMER_POLL_INTERVAL duration string нет 100 milliseconds интервал между запросами poll для kafka consumer
EVENT_STATUS_KAFKA_CONSUMER_PROPS string нет "max.poll.records=500;max.partition.fetch.bytes=524288" дополнительные параметры для kafka consumer в формате "key1=value1;key2=value2"
EVENT_STATUS_KAFKA_COMMANDEVENT_TOPIC string да "commandevents" Название кафка-топика для отправки сообщений со статусами выполняемых команд. ОБЯЗАТЕЛЬНО должно соответствовать названию этого топика в сервисе статуса команд.
EVENT_STATUS_KAFKA_AUTH_USER string нет "" Название учетной записи Kafka. Если название не указано, то настройки авторизации не будут применены.
EVENT_STATUS_KAFKA_AUTH_PASSWORD string нет "" Пароль учетной записи Kafka.
EVENT_STATUS_KAFKA_AUTH_PRINCIPAL string нет "" Principal учетной записи Kafka в Kerberos(в случае соединения с kafka через Kerberos).
EVENT_STATUS_KAFKA_AUTH_KEYTAB_PATH string нет "" Путь до keytab-файла (в случае соединения с kafka через Kerberos).
EVENT_STATUS_KAFKA_AUTH_TRUSTSTORE_LOCATION string нет "" Путь до хранилища сертификатов (Java key store). Если путь не указан, то сертификат применятся не будет.
EVENT_STATUS_KAFKA_AUTH_TRUSTSTORE_PASSWORD string нет "" Пароль к харнилищу сертификатов.
EVENT_STATUS_KAFKA_AUTH_MODE string нет "" Режим аутентификации: static - одна учетная запись на все запросы, mapping - учетная запись зависит от запроса
EVENT_STATUS_KAFKA_AUTH_CONFIG string нет "" Настройки для аутентификации: если AuthMode = mapping, то необходим JSON с List[KafkaAuthConfig] соответствует полю authConfig KafkaAuthSettings
EVENT_STATUS_KAFKA_AUTH_CACHE_SIZE int нет Максимальный размер кэша для Kafka producer (количество активных соединений).
EVENT_STATUS_KAFKA_CONNECTION_CHECK_TEST_MESSAGES_INTERVAL duration string нет 4 minutes Применяется только для producer-ов со способом аутентификации kerberos. Интервал отправки тестовых сообщений кафки в топик connectionCheck.testMessagesTopicName. Тестовые сообщения (null, service producer test) отправляются регулярно с этим интервалом.
EVENT_STATUS_KAFKA_CONNECTION_CHECK_INTERVAL duration string нет 60 seconds Применяется только для producer-ов со способом аутентификации kerberos. Интервал проверки того, сколько тестовых сообщений было отправлено за данный период. Если количество сообщений за этот период равно количеству сообщений за прошлый период, то начинается отсчет периода без сообщений.
EVENT_STATUS_KAFKA_CONNECTION_CHECK_FAILED_AFTER_INTERVAL duration string нет 5 minutes Применяется только для producer-ов со способом аутентификации kerberos. Максимальная продолжительность периода без успешно отправленных тестовых сообщений. По ее достижении сервис будет объявлен больным.
EVENT_STATUS_KAFKA_AUTH_CACHE_TTL duration string нет Время жизни Kafka producer в кэше.
EVENT_STATUS_CONSUL_ADDR url string нет "http://localhost:8500" Адрес Сonsul.
EVENT_STATUS_CONSUL_AUTH_USER string нет "" Название учетной записи Сonsul. Если название не указано, то настройки авторизации не будут применены.
EVENT_STATUS_CONSUL_AUTH_PASSWORD string нет "" Пароль учетной записи Сonsul.
EVENT_STATUS_TRACE_DURATION boolean нет false Признак необходимости трассировки выполнения команд
EVENT_STATUS_DISCOVERABLE_ID string нет "another_EVENT_STATUS_service_instance" ID сервиса в ServiceDiscovery
EVENT_STATUS_DISCOVERABLE_NAME string нет "eventStatus" Имя сервиса в ServiceDiscovery
EVENT_STATUS_DISCOVERABLE_HOST string да "localhost" Хост, публикуемый в ServiceDiscovery. По нему на данный сервис будут обращаться другие через HTTP. Указанный адрес должен быть виден другим сервисам. Пример: имя kubernetes/docker_swarm service
EVENT_STATUS_DISCOVERABLE_PORT int нет Порт, публикуемый в ServiceDiscovery. По нему на данный сервис будут обращаться другие через HTTP. По умолчанию указывается порт, который слушает HTTP-сервер.
EVENT_STATUS_DISCOVERABLE_LIVETIME duration string нет 2 minutes Период после последней отправки health check, в течение которого ServiceDiscovery считает данный сервис живым.
EVENT_STATUS_DISCOVERABLE_HEALTHPASS string нет 1 minute Периодичность отправки health check в ServiceDiscovery
EVENT_STATUS_SERVICE_TITLE string нет "Event Status" Название сервиса для отображения
EVENT_STATUS_SERVICE_DESCRIPTION string нет "Service EVENT_STATUS" Описание сервиса для отображения
EVENT_STATUS_AKKA_HTTP_CLIENT_MAXCON int нет 512 Максимальное число одновременных исходящих HTTP-соединений
EVENT_STATUS_AKKA_HTTP_CLIENT_MAXREQ int нет 1024 Максимальное число одновременных исходящих HTTP-запросов
EVENT_STATUS_AKKA_HTTP_SERVER_MAXCON int нет 1024 Максимальное число одновременных входящих HTTP-соединений
EVENT_STATUS_INTERNALCMD_ALLOW bool нет false Можно ли сервису отправлять внутрисистемные команды
EVENT_STATUS_SENDERLIB_CONSIDER_ALL_COMMANDS_AS_INTERNAL boolean Нет false Флаг, определяющий будут ли все обращения в другие сервисы являться внутренними (т.е. не требовать авторизацию). Детальное описание механизма: Внутренние команды.
EVENT_STATUS_SENDERLIB_COMMANDS_CACHE_UPDATEPERIOD duration string нет 10 minutes Время кэширования данных по командам из CommandDiscovery
EVENT_STATUS_SENDERLIB_SERVICES_CACHE_UPDATEPERIOD duration string нет 30 seconds Время кэширования данных по сервисам из ServiceDiscovery
EVENT_STATUS_SENDERLIB_CONSUL_CONNECTION_RETRY_MAX int нет 5 Количество попыток переподключения к Consul
EVENT_STATUS_SENDERLIB_CONSUL_CONNECTION_RETRY_DELAY duration string нет 1 second Задержка при попытках переподключения к Consul
EVENT_STATUS_DB_HOST string да Хост БД
EVENT_STATUS_DB_PORT int да Порт БД
EVENT_STATUS_DB_NAME string да Имя базы в БД
EVENT_STATUS_DB_URL jdbc url string нет JDBC-url для соединения с БД. По умолчанию собирается из других обязательных переменных. Можно указать только его, если не хочется отдельно указывать хост/порт/имя базы.
EVENT_STATUS_DB_USER string да Пользователь БД
EVENT_STATUS_DB_PASSWORD string да Пароль пользователя БД
EVENT_STATUS_DB_THREADS int нет 10 Количество потоков в пуле потоков для соединения с БД
EVENT_STATUS_DB_QUEUE_SIZE int нет 300 Размер очереди для действий базы данных, которые не могут быть выполнены немедленно, когда все потоки заняты. За пределами этого значения новые действия немедленно завершаются неудачей
EVENT_STATUS_DB_CONN_MAX int нет 10 Максимальное количество одновременных подключений к БД
EVENT_STATUS_DB_CONN_TIMEOUT duration string нет 20 second Максимальное время ожидания ответа для соединения к БД. Если это время превышено, а соединение не становится доступным, будет брошено исключение SQLException. 1000 мс — минимальное значение.
EVENT_STATUS_DB_ISOLATION string нет "READ_COMMITTED" Уровень изоляции транзакций для новых подключений. Допустимые значения: NONE, READ_COMMITTED, READ_UNCOMMITTED, REPEATABLE_READ, SERIALIZABLE.
EVENT_STATUS_DB_READONLY boolean нет false Read-only SQL транзакция может изменять только временные таблицы. Этот параметр управляет статусом «только для чтения» по умолчанию для каждой новой транзакции.
EVENT_STATUS_DB_CONN_MIN int нет = DB_THREADS Минимальное количество одновременных подключений к БД
EVENT_STATUS_DB_VALIDATION_TIMEOUT duration string нет 1 seconds Максимальное время, в течение которого соединение будет проверяться на работоспособность. 1000 мс — минимальное значение.
EVENT_STATUS_DB_IDLE_TIMEOUT duration string нет 10 minutes Максимальное время, в течение которого соединению разрешено простаивать в пуле. Значение 0 означает, что простаивающие соединения никогда не удаляются из пула.
EVENT_STATUS_DB_MAX_LIFETIME duration string нет 30 minutes Максимальное время жизни соединения в пуле. Когда простаивающее соединение достигает этого времени ожидания, даже если оно недавно использовалось, оно будет удалено из пула. Значение 0 указывает на отсутствие максимального срока службы.
EVENT_STATUS_DB_INITIALIZATION_FAIL_FAST string нет false Deprecated, начиная с версии Slick 3.3.0. Определяет, будет ли пул «быстро выходить из строя», если пул не может быть успешно заполнен начальными соединениями. Если соединения не могут быть созданы во время запуска пула, будет выдано исключение RuntimeException. Это свойство не имеет никакого эффекта, если minConnections равно 0.
EVENT_STATUS_DB_LEAK_DETECTION_THRESHOLD int нет 0 Время, в течение которого соединение может находиться вне пула, прежде чем будет зарегистрировано сообщение, указывающее на возможную утечку соединения. Значение 0 означает, что обнаружение утечек отключено. Наименьшее приемлемое значение для включения обнаружения утечек составляет 10 с.
EVENT_STATUS_DB_CONNECTION_TEST_QUERY string нет "SELECT 1" Выражение, которое будет выполнено непосредственно перед получением соединения из пула для проверки того, что соединение с базой данных все еще активно. Оно зависит от базы данных и должно представлять собой запрос, требующий минимальной обработки базой данных (например, «VALUES 1»). Если этот параметр не установлен, вместо него используется метод JDBC4 Connection.isValid().
EVENT_STATUS_DB_AUTO_COMMIT boolean нет true Это свойство определяет то, как будут вести себя по умолчанию возвращаемые соединения относительно autocommit-а.
EVENT_STATUS_DB_SCHEMA string нет "public" Устанавливает schema по умолчанию
EVENT_STATUS_DB_ISOLATE_INTERNAL_QUERIES boolean нет false Определяет то, изолируются ли с помощью транзакций внутренние запросы пула (например запрос connection alive test). Свойство применяется только если autoCommit выключен.
EVENT_STATUS_DB_INITIALIZATION_FAIL_TIMEOUT int нет 1 Работает, начиная с версии Slick 3.3.0. Определяет, будет ли пул «быстро выходить из строя», если пул не может быть успешно заполнен начальными соединениями. Любое положительное число считается числом миллисекунд для попытки получить начальное соединение;поток приложения будет заблокирован в течение этого периода. Если соединение не может быть получено до истечения этого времени, будет брошено исключение. Данный таймаут применяется после периода connectionTimeout. Если значение равно нулю (0),HikariCP попытается получить и проверить подключение. Если соединение получено, но проверка не пройдена, будет брошено исключение, и пул не будет запущен. Однако, если соединение не может быть получено, пул запустится, но последующие попытки получить соединение могут потерпеть неудачу. Значение меньше нуля пройдет любую первоначальную попытку подключения, и пул немедленно запустится, пытаясь получить соединения в фоновом режиме. Следовательно, последующие попытки получить соединение могут потерпеть неудачу.
EVENT_STATUS_DB_REGISTER_MBEANS boolean нет false Зарегистрированы ли JMX Management Beans («MBeans»)
EVENT_STATUS_AUTHZFORCE_ADDR string нет "http://localhost:8080/authzforce-ce" Адрес AuthZforce server
EVENT_STATUS_AUTHZFORCE_DOMAIN string нет "" Доступный DomainID в AuthZforce server
EVENT_STATUS_EVENT_CACHE_MAX_SIZE int нет 1000 Максимальное количество событий в кэше
EVENT_STATUS_EVENT_CACHE_EXPIRE_AFTER_WRITE_SECONDS int нет 60 Время в секундах, после которого элементы убираются из кэша
EVENT_STATUS_JOURNAL_MODE string Нет "WriteToJournal" Режим журналирования Nestor. Допустимые значения: WriteToJournal (Отправка в сервис журналирования), WriteToTopic (Отправка события в очередь)
EVENT_STATUS_JOURNAL_TOPIC string Да, если переменная EVENT_STATUS_JOURNAL_MODE = WriteToTopic "" Название очереди журналирования. Для режима WriteToJournal значение игнорируется.

Список команд сервиса Event Status

Команды сервиса информации о событиях:

Команда EntityType Actions
eventStatus_http_publishHandledEvent - -
eventStatus_longPool_waitForEvent - -
eventStatus_longPool_waitForMultipleEvents - -

publishHandledEvent

На входе описание события

{
  "eventType": "test",
  "payloadType": "test",
  "payloadId": "test",
  "serviceName": "test",
  "payloadVersion": 5
}

На выходе ничего

{
  "status": "Completed",
  "timestamp": 1683184345008,
  "value": {}
}

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

Имя команды для вызова eventStatus_http_publishHandledEvent.
Поддерживает только синхронный вызов.
Результат выполнения команды не журналируется.

waitForEvent

На входе описание события и таймаут

{
  "timeoutSeconds": 30,
  "eventToWait": {
    "eventType": "test",
    "payloadType": "test",
    "payloadId": "test",
    "serviceName": "test",
    "payloadVersion": 5
  }
}

На выходе true, если событие уже обработано

{
  "status": "Completed",
  "timestamp": 1683184345008,
  "value": true
}

Дожидается публикации информации о событии в сервисе. Работает через механизм Long-Pool

Имя команды для вызова eventStatus_longPool_waitForEvent.
Поддерживает только синхронный вызов.
Результат выполнения команды не журналируется.

waitForMultipleEvents

На входе описание событий и timeout

{
  "timeoutSeconds": 5,
  "eventsToWait": [
    {
      "eventType": "test",
      "payloadType": "test",
      "payloadId": "test",
      "serviceName": "test",
      "payloadVersion": 5
    }
  ]
}

На выходе список Boolean, аналогично waitForEvent

{
  "status": "Completed",
  "timestamp": 1683184345008,
  "value": [
    true
  ]
}

Дожидается публикации информации о всех событиях в сервисе. По истечению timeout возвращает результат по каждому событию.

Имя команды для вызова eventStatus_longPool_waitForMultipleEvents.
Поддерживает только синхронный вызов.
Результат выполнения команды не журналируется.

Объекты сервиса EventStatus

HandledEventDto

Модель для уведомления, что serviceName обработал событие. Хранится в verdi-models.

Поле Тип Обязательное Описание
eventType String да Тип события
payloadType String да Тип объекта в событии
payloadId String да Id объекта в событии
serviceName String да Имя сервиса, обработкал событие
payloadVersion Long нет Версия объекта в событии

WaitForEventDto

Модель для ожидания события. Хранится в verdi-models.

Поле Тип Обязательное Описание
timeoutSeconds Int да Максимальное ожидание в секундах
eventToWait HandledEventDto да Событие, которого нужно дождаться

WaitForEventsDto

Модель для ожидания события. Хранится в verdi-models.

Поле Тип Обязательное Описание
timeoutSeconds Int да Максимальное ожидание в секундах
eventsToWait HandledEventDto да События, которых нужно дождаться

Exporter: библиотека для экспорта данных в различные форматы

Библиотека содержит:

Экспорт в Excel

Экспорт в Excel генерирует xlsx таблицу с фильтрами и обводкой. Используется Apache POI.

Поддерживает режимы:

В будущем при необходимости можно добавить поддержку других форматов:

FS-client: библиотека для работы с файловым хранилищем

Предоставляемый функционал FSClient

Библиотека предоставляет интерфейс и реализацию клиента файлового хранилища.

Предоставляемые реализации клиента LiveFSClient, LiveFSClientCached обеспечивают логику ограничения прав доступа к загруженным файлам через опциональный атрибут контроля, хранящий идентификатор пользователя в поле ownerUserId FileMeta. При отсутствии в нем какого-либо значения файл будет считаться доступным всем. При отсутствии доступа будет возвращена ошибка DownloadForbidden.

Фиксация атрибута контроля доступа происходит при использовании апи uploadPrivate(), copyAndUpdateAccessSettings().

Отключение механизма контроля происходит через передачу пустого параметра ownerUserId: Option[UserId] в методы апи: get(), getMeta(), getManaged().

Управление бакетами

/**
 * Создать бакет если он еще не создан
 * @param bucket Бакет
 * @return Существовал ли бакет до вызова метода
 */
def createBucketIfNotExist(bucket: String): ZIO[FSClient, FSError, Boolean]

Работа с файлами

  /**
 * Получить файл с опциональной проверкой на наличие доступа при переданном ownerUserId
 * @param storedFile Описание хранимого файла
 * @param ownerUserId Идентификатор пользователя
 * @return Стрим из файла и метаданные файла
 */
def get(
    storedFile: StoredFile,
    ownerUserId: Option[UserId] = None
): ZIO[FSClient, FSError, (Stream[FSError, Byte], FSMetadata)]

/**
 * Получить файл как ресурс с опциональной проверкой на наличие доступа при переданном ownerUserId
 * @param storedFile Описание хранимого файла
 * @param ownerUserId Идентификатор пользователя
 * @return InputStream открытый только в рамках ресурс и метаданные файла
 */
def getManaged(storedFile: StoredFile, ownerUserId: Option[UserId] = None): ZManaged[FSClient, FSError, (InputStream, FSMetadata)]

/**
 * Получить метаданные файла без самого файла с опциональной проверкой на наличие доступа при переданном ownerUserId
 * @param storedFile Описание хранимого файла
 * @param ownerUserId Идентификатор пользователя
 * @return Метаданные файла
 */
def getMeta(storedFile: StoredFile, ownerUserId: Option[UserId] = None): ZIO[FSClient, FSError, FSMetadata]

/**
 * Загрузка файла. Загруженный файл будет доступен всем.
 * @param storedFile описание сохраняемого файла
 * @param name имя
 * @param body стрим из файла
 * @param parallelism уровень параллелизма загрузки
 * @return
 */
def upload(
    storedFile: StoredFile,
    name: String,
    body: Stream[Throwable, Byte],
    parallelism: Int,
    contentType: Option[String] = None
): ZIO[FSClient, FSError, Unit]

/**
 * Загрузка файла с установкой атрибута для последующего контроля доступа к файлу (загруженный файл будет доступен 
 * только пользователю с идентификатором ownerUserId).
 * @param storedFile описание сохраняемого файла
 * @param name имя
 * @param body стрим из файла
 * @param parallelism уровень параллелизма загрузки
 * @param ownerUserId Идентификатор пользователя
 * @return
 */
def uploadPrivate(
    storedFile: StoredFile,
    name: String,
    body: Stream[Throwable, Byte],
    parallelism: Int,
    ownerUserId: UserId,
    contentType: Option[String] = None
 ): ZIO[FSClient, FSError, Unit]

/**
 * Перемещение файла. При изменении бакета у файла будут сброшены опциональные настройки доступа.
 * @param source Описание исходного хранимого файла для перемещения
 * @param destination Описание желаемого места, куда перемещается файл
 * @return
 */
def move(source: StoredFile, destination: StoredFile): ZIO[FSClient, FSError, FSMetadata]

/**
 * Перемещение файла с сохранением исходного опционального атрибута для контроля доступа к файлу
 * @param source Описание исходного хранимого файла для перемещения
 * @param destination Описание желаемого места, куда перемещается файл
 * @return
 */
def moveWithAccessControl(source: StoredFile, destination: StoredFile): ZIO[FSClient, FSError, FSMetadata]

/**
 * Копирование файла. При изменении бакета у копии будут сброшены опциональные настройки доступа.
 * @param source Описание исходного хранимого файла для перемещения
 * @param destination Описание желаемого места, куда копируется файл
 * @return
 */
def copy(source: StoredFile, destination: StoredFile): ZIO[FSClient, FSError, FSMetadata]

/**
 * Копирование файла с сохранением исходного опционального атрибута для контроля доступа к файлу
 * @param source Описание исходного хранимого файла для перемещения
 * @param destination Описание желаемого места, куда копируется файл
 * @return
 */
def copyWithAccessControl(source: StoredFile, destination: StoredFile): ZIO[FSClient, FSError, FSMetadata]

/**
 * Копирование файла с принудительной установкой атрибута для последующего контроля доступа к файлу-копии
 * ВАЖНО: метод не реализует проверку наличия доступа к исходному файлу
 * @param source Описание исходного хранимого файла для перемещения
 * @param destination Описание желаемого места, куда копируется файл
 * @param ownerUserId Идентификатор пользователя
 * @return
 */
def copyAndUpdateAccessSettings(
    source: StoredFile,
    destination: StoredFile,
    ownerUserId: UserId
): ZIO[FSClient, FSError, FSMetadata]

/**
 * Получить список файлов
 * @param bucket путь
 * @return Список с описанием файлов бакетов
 */
def list(bucket: String, path: Path = Path.of("")): URIO[FSClient, Stream[FSError, FileListEntity]]

/**
 * Удаление файла
 * @param storedFile Описание хранимого файла
 * @return
 */
def delete(storedFile: StoredFile): ZIO[FSClient, FSError, Unit]

Структуры FSClient

FSConfigRep (FSClient)

Отображение FSConfig в "плоской форме", как он выглядит в конфиге приложения application.conf.

Поле Тип Обязательное Описание Ограничения
uri String Да Адрес файлового хранилища для подключения. Не пустое
uploadParallelism Int Да Параллелизм загрузки файлов в файловое хранилище. > 0
accessKeyId String Да, если authMode=Static ID для подключения (не зависит от бакета). Не пустое
secretAccessKey String Да, если authMode=Static Key для подключения (не зависит от бакета). Не пустое
authMode String Нет Режим аутентификации клиента: Static - данные для подключения не зависят от бакета, Mapping - данные зависят от бакета. По-умолчанию Static. "Static", "Mapping"
authConfig String Да, если authMode=Mapping Настройки для выбранного режима аутентификации. Если authMode=Mapping, то ожидается Seq[FSBucketConfig] в формате JSON.
clientsCache VerdiCacheConfig Нет Настройки кеша для клиентов файлового хранилища.
retrySettings RetrySettings Нет Настойки для повтороного вызова функций файлового хранилища.
zioShortMessageMode Boolean Нет Флаг включения режима сохранения ошибок работы с файловым хранилищем в сервисе журналирования nestor. При включении режима ошибки в логах клиентского приложения будут отображаться в сокращенном формате: Short zio message mode. ExceptionType: ТИП ОШИБКИ, Exception id: 'СГЕНЕРИРОВАННЫЙ UUID' added to journal. Указанный id будет фиксироваться в event записи nestor'а в поле data.id

FSConfig (FSClient)

Конфигурация клиента файлового хранилища.

Поле Тип Обязательное Описание Ограничения
uri String Да Адрес файлового хранилища для подключения Не пустое
uploadParallelism Int Да Параллелизм загрузки файлов в файловое хранилище > 0
credentials Seq[FSBucketConfig] Да Список данных для учетных записей для подключения к бакетам
clientsCache VerdiCacheConfig Да Настройки кеша для клиентов файлового хранилища
retrySettings RetrySettings Нет Настойки для повтороного вызова функций файлового хранилища.
zioShortMessageMode Boolean Нет Флаг включения режима сохранения ошибок работы с файловым хранилищем в сервисе журналирования nestor. При включении режима ошибки в логах клиентского приложения будут отображаться в сокращенном формате: Short zio message mode. ExceptionType: ТИП ОШИБКИ, Exception id: 'СГЕНЕРИРОВАННЫЙ UUID' added to journal. Указанный id будет фиксироваться в event записи nestor'а в поле data.id

FSBucketConfig (FSClient)

Данные для аутентификации, которые привязаны к конкретному бакету.

Поле Тип Обязательное Описание Ограничения
bucketName String Да Название бакета. Если значение пустое, то данные подходят для любого бакета.
bucketAlias List[String] Нет Список альтернативных названий бакета. Не пустое
credentials FSCredentials Да Данные учетной записи для подключения к бакету.

FSCredentials (FSClient)

Данные для аутентификации.

Поле Тип Обязательное Описание Ограничения
accessKeyId String Да ID для подключения Не пустое
secretAccessKey String Да Key для подключения Не пустое

StoredFile

Информация о файле. Становится строкой в формате "{bucket}/{path}/{id}" при конвертации в json.

Поле Тип Обязательное Описание
id string да ID файла
path string да Путь по папкам до файла внутри бакета
bucket string да Бакет для хранения файла

FileMeta

Метаинформация о файле

Поле Тип Обязательное Описание
filename string да Имя файла
checksum string да Значение контрольной суммы
ownerUserId UserId нет Идентификатор пользователя, у которого есть доступ к файлу. При отсутствии значения файл считается доступным всем

FSMetadata

Метаинформация о файле, возвращаемая при запросах к файловому хранилищу.

Поле Тип Обязательное Описание
contentType string да Тип содержимого файла
contentLength Long да Длина содержимого файла в байтах
fileName string да Имя файла
md5 string да Контрольная сумма файла в формате MD5
ownerUserId UserId нет Идентификатор пользователя, у которого есть доступ к файлу. При отсутствии значения файл считается доступным всем

FileMetadata

Поле Тип Обязательное Описание
fileId string да Идентификатор файла
name string да Имя файла
size long да Размер файла в байтах
url string да url файла в S3
md5 string да MD5 хеш файла
contentType string да Content-Type файла

Indexation: сервис индексаций

В сервисе реализованы следующие команды

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

Сервис индексирует объекты из модели данных. Индексирование может изменять состояние объекта в сервисах верди, например обновлять объект в модели данных или делать объект доступным для полнотекстового поиска, возможно индексирование без изменения состояния - например наполнение индексов LAMP для последующего использования. Индексация определенного типа описывается как последовательность шагов Step. Шаги могут зависеть друг от друга. Зависимость может быть 2 типов: шаг Б использует результаты шага А для определенной сущности, шаг Б полагается на выполнение шага А для всех сущностей. Некоторые шаги (сейчас только Lamp) после выполнения работы над определенной сущностью возвращают словарь вида: имяполя->результатработы. Зависящие от них шаги, могут использовать эти результаты в свой работе. Если дочерний шаг должен дождаться завершения индексации всех сущностей на родительском шаге - то при описании дочернего шага нужно указывать флаг oneLevel = false.

Сервис индексаций содержит следующие таблицы:

Конфигурирование сервиса индексаций

Требования к запуску сервиса индексаций

Запуск сервиса осуществляется локально через sbt, на стенде в docker на jvm. Для корректной минимальной работы сервиса требуется обязательное подключение к PostgreSQL, Kafka, Consul, MinIO и Remote Lamp Client Для нормальной работы сервису дополнительно требуется окружение Verdi: CommandStatus и ApiGateway.

Список переменных окружения сервиса индексаций

Переменная Тип Обязательная Значение по умолчанию Описание
SERVER_PORT int нет 8080 Порт, на котором слушает HTTP-сервер
SERVER_AUTHORIZER_KIND string нет "authzforce" Вид авторизатора, который используется в сервисе. Допустимые значения: "authzforce", "oberto". При указании неизвестного значения будет использовано значение по-умолчанию.
CONSUMER_TOPIC string нет entityObjectEvents Название кафка-топика для событий по объектам
CONSUMER_GROUP string нет indexation Имя группы-консьюмеров сервиса индексаций
FIXED_CONSUMER_GROUP string нет indexationFixed Имя группы-консьюмеров без перебалансировки
CONSUMER_STEP_TOPIC string нет step Название кафка-топика для шагов индексации
CONSUMER_PROGRESS_TOPIC string нет progress Название кафка-топика для прогресса по плагинам
CONSUMER_STEP_FINISH_TOPIC string нет stepFinish Название кафка-топика для отслеживания завершения выполнения всех шагов по определенной сущности. Топик должен иметь только 1 партицию. Топик для внутреннего использования
CONSUMER_INDEXATION_TOPIC string нет indexationInner Название кафка-топика для выполнения массовой индексации сущностей определенного типа. Топик должен иметь только 1 партицию
CONSUMER_INDEXATION_INTERRUPT_TOPIC string нет indexationInterrupt Название кафка-топика для принудительного прерывания индексации. Топик должен иметь только 1 партицию. Топик для внутреннего использования
CONSUMER_STEP_PARTITION_PARALLELISM int нет 10 Параллелизм чтения из step партиции. Значения > 1 нарушают at-most-once семантику, но значительно ускоряют массовую индексацию
CONSUMER_FILE_EVENTS_TOPIC string нет fileEvents Название кафка-топика для событий с файлами из dataModel
VERDI_CONSUL url string да http://localhost:8500 Адрес Consul
VERDI_CONSUL_AUTH_USER string нет "" Название учетной записи Сonsul. Если название не указано, то настройки авторизации не будут применены.
VERDI_CONSUL_AUTH_PASSWORD string нет "" Пароль учетной записи Сonsul.
VERDI_KAFKA_ADDRESS string да localhost:9092 Адрес брокера Kafka.
VERDI_KAFKA_TOPIC string нет commandevents Название кафка-топика для отправки сообщений со статусами выполняемых команд. ОБЯЗАТЕЛЬНО должно соответствовать названию этого топика в сервисе статуса команд.
VERDI_KAFKA_AUTH_USER string нет "" Название учетной записи Kafka. Если название не указано, то настройки авторизации не будут применены.
VERDI_KAFKA_AUTH_PASSWORD string нет "" Пароль учетной записи Kafka.
VERDI_KAFKA_AUTH_PRINCIPAL string нет "" Principal учетной записи Kafka в Kerberos(в случае соединения с kafka через Kerberos).
VERDI_KAFKA_AUTH_KEYTAB_PATH string нет "" Путь до keytab-файла(в случае соединения с kafka через Kerberos).
VERDI_KAFKA_AUTH_TRUSTSTORE_LOCATION string нет "" Путь до хранилища сертификатов (Java key store). Если путь не указан, то сертификат применяться не будет.
VERDI_KAFKA_AUTH_TRUSTSTORE_PASSWORD string нет "" Пароль к хранилищу сертификатов.
VERDI_KAFKA_AUTH_MODE string нет "" Режим аутентификации: static - одна учетная запись на все запросы, mapping - учетная запись зависит от запроса
VERDI_KAFKA_AUTH_CONFIG string нет "" Настройки для аутентификации: если AuthMode = mapping, то необходим JSON с List[KafkaAuthConfig]. Переменная соответствует полю authConfig из KafkaAuthSettings.
VERDI_KAFKA_AUTH_CACHE_SIZE int нет Максимальный размер кеша для Kafka producer (количество активных соединений).
VERDI_KAFKA_AUTH_CACHE_TTL duration string нет Время жизни Kafka producer в кеше.
VERDI_KAFKA_CONNECTION_CHECK_TEST_MESSAGES_INTERVAL duration string нет 4 minutes Применяется только для producer-ов со способом аутентификации kerberos. Интервал отправки тестовых сообщений кафки в топик connectionCheck.testMessagesTopicName. Тестовые сообщения (null, service producer test) отправляются регулярно с этим интервалом.
VERDI_KAFKA_CONNECTION_CHECK_INTERVAL duration string нет 60 seconds Применяется только для producer-ов со способом аутентификации kerberos. Интервал проверки того, сколько тестовых сообщений было отправлено за данный период. Если количество сообщений за этот период равно количеству сообщений за прошлый период, то начинается отсчет периода без сообщений.
VERDI_KAFKA_CONNECTION_CHECK_FAILED_AFTER_INTERVAL duration string нет 5 minutes Применяется только для producer-ов со способом аутентификации kerberos. Максимальная продолжительность периода без успешно отправленных тестовых сообщений. По ее достижении сервис будет объявлен больным.
VERDI_KAFKA_PRODUCER_PROPS string нет "max.request.size=1048576" Дополнительные параметры для Kafka producer. Заполняются по шаблону "key1=value1;key2=value2".
VERDI_HOST string да localhost Хост, публикуемый в ServiceDiscovery. По нему на данный сервис будут обращаться другие через HTTP. Указанный адрес должен быть виден другим сервисам. Пример: имя kubernetes/docker_swarm service
VERDI_TTL duration string нет 30 seconds Период после последней отправки health check, в течение которого ServiceDiscovery считает данный сервис живым.
VERDI_HEALTH_CHECK duration string нет 10 seconds Периодичность отправки health check в ServiceDiscovery
VERDI_COMMAND_STORAGE_UPDATE_PERIOD duration string нет 1 minutes Время кэширования данных по командам из CommandDiscovery
VERDI_SERVICE_DISCOVERY_UPDATE_PERIOD duration string нет 30 seconds Время кэширования данных по сервисам из ServiceDiscovery
VERDI_ALLOW_INTERNAL_COMMANDS bool нет true Можно ли сервису отправлять внутрисистемные команды
VERDI_CONSIDER_ALL_COMMANDS_AS_INTERNAL boolean Нет false Флаг, определяющий будут ли все обращения в другие сервисы являться внутренними (т.е. не требовать авторизацию). Детальное описание механизма: Внутренние команды.
VERDI_CONSUL_CONNECTION_MAX_RETRY int нет 5 Максимальное количество попыток подключений к Consul
VERDI_CONSUL_CONNECTION_RETRY_DELAY duration string нет 1 seconds Таймаут между неудачными попытками подключения к Consul
VERDI_KAFKA_SYNC_POLLING_PERIOD duration string нет 1 seconds Периодичность запроса статуса verdi команд в sender-lib
VERDI_KAFKA_SYNC_POLLING_TIMEOUT duration string нет 10 seconds Максимальное время ожидания выполнения verdi команды в sender-lib
DB_JDBC_URL jdbc url string да jdbc:postgresql://127.0.0.1:5432/indexation JDBC-url для соединения с БД
DB_USER string да Пользователь БД
DB_PASSWORD string да Пароль пользователя БД
DB_THREADS int нет 10 Количество потоков в пуле потоков для соединения с БД
DB_QUEUE_SIZE int нет 300 Размер очереди для действий базы данных, которые не могут быть выполнены немедленно, когда все потоки заняты. За пределами этого значения новые действия немедленно завершаются неудачей
DB_CONN_MAX int нет 10 Максимальное количество одновременных подключений к БД
DB_CONN_TIMEOUT duration string нет 20 second Максимальное время ожидания ответа для соединения к БД. Если это время превышено, а соединение не становится доступным, будет брошено исключение SQLException. 1000 мс — минимальное значение.
DB_ISOLATION string нет "READ_COMMITTED" Уровень изоляции транзакций для новых подключений. Допустимые значения: NONE, READ_COMMITTED, READ_UNCOMMITTED, REPEATABLE_READ, SERIALIZABLE.
DB_READONLY boolean нет false Read-only SQL транзакция может изменять только временные таблицы. Этот параметр управляет статусом «только для чтения» по умолчанию для каждой новой транзакции.
DB_CONN_MIN int нет = DB_THREADS Минимальное количество одновременных подключений к БД
DB_VALIDATION_TIMEOUT duration string нет 1 seconds Максимальное время, в течение которого соединение будет проверяться на работоспособность. 1000 мс — минимальное значение.
DB_IDLE_TIMEOUT duration string нет 10 minutes Максимальное время, в течение которого соединению разрешено простаивать в пуле. Значение 0 означает, что простаивающие соединения никогда не удаляются из пула.
DB_MAX_LIFETIME duration string нет 30 minutes Максимальное время жизни соединения в пуле. Когда простаивающее соединение достигает этого времени ожидания, даже если оно недавно использовалось, оно будет удалено из пула. Значение 0 указывает на отсутствие максимального срока службы.
DB_INITIALIZATION_FAIL_FAST string нет false Deprecated, начиная с версии Slick 3.3.0. Определяет, будет ли пул «быстро выходить из строя», если пул не может быть успешно заполнен начальными соединениями. Если соединения не могут быть созданы во время запуска пула, будет выдано исключение RuntimeException. Это свойство не имеет никакого эффекта, если minConnections равно 0.
DB_LEAK_DETECTION_THRESHOLD int нет 0 Время, в течение которого соединение может находиться вне пула, прежде чем будет зарегистрировано сообщение, указывающее на возможную утечку соединения. Значение 0 означает, что обнаружение утечек отключено. Наименьшее приемлемое значение для включения обнаружения утечек составляет 10 с.
DB_CONNECTION_TEST_QUERY string нет "SELECT 1" Выражение, которое будет выполнено непосредственно перед получением соединения из пула для проверки того, что соединение с базой данных все еще активно. Оно зависит от базы данных и должно представлять собой запрос, требующий минимальной обработки базой данных (например, «VALUES 1»). Если этот параметр не установлен, вместо него используется метод JDBC4 Connection.isValid().
DB_REGISTER_MBEANS boolean нет false Зарегистрированы ли JMX Management Beans («MBeans»)
DB_AUTO_COMMIT boolean нет true Это свойство определяет то, как будут вести себя по умолчанию возвращаемые соединения относительно autocommit-а.
DB_SCHEMA string нет "public" Устанавливает schema по умолчанию
DB_ISOLATE_INTERNAL_QUERIES boolean нет false Определяет то, изолируются ли с помощью транзакций внутренние запросы пула(например запрос connection alive test). Свойство применяется только если autoCommit выключен.
DB_INITIALIZATION_FAIL_TIMEOUT int нет 1 Работает, начиная с версии Slick 3.3.0. Определяет, будет ли пул «быстро выходить из строя», если пул не может быть успешно заполнен начальными соединениями. Любое положительное число считается числом миллисекунд для попытки получить начальное соединение;поток приложения будет заблокирован в течение этого периода. Если соединение не может быть получено до истечения этого времени,будет брошено исключение. Данный таймаут применяется после периода connectionTimeout. Если значение равно нулю (0),HikariCP попытается получить и проверить подключение. Если соединение получено,но проверка не пройдена, будет брошено исключение, и пул не будет запущен. Однако,если соединение не может быть получено, пул запустится,но последующие попытки получить соединение могут потерпеть неудачу.Значение меньше нуля пройдет любую первоначальную попытку подключения, и пул немедленно запустится,пытаясь получить соединения в фоновом режиме.Следовательно, последующие попытки получить соединение могут потерпеть неудачу.
FS_URI url string да http://localhost:9002 Адрес S3 файлового хранилища minio
FS_ACCESS_KEY_ID string да admin Идентификатор доступа к minio
FS_SECRET_ACCESS_KEY string да admin Секретный ключ доступа к minio
FS_UPLOAD_PARALLELISM int нет 10 Параллелизм загрузки файлов в minio
FS_AUTH_MODE string нет static Режим аутентификации: static - одна учетная запись на все запросы, mapping - учетная запись зависит от запроса
FS_AUTH_CONFIG string нет "" Настройки для аутентификации: если AuthMode = mapping, то необходим JSON с List[FSBucketConfig] соответствует полю authConfig FSConfigRep
FS_CACHE_SIZE int нет 1 Максимальный размер кеша клиентов для хранилища файлов (количество активных соединений).
FS_CACHE_TTL duration string нет Время жизни клиента в кеше
FS_RETRY_ATTEMPTS int нет 5 Количество ретраев, которое будет произведено в случае Exception-а в операции FSClient-а и при вычитывании стрима в get операциях FSClient-а.
FS_RETRY_DELAY duration string нет 10 millis Задержка между ретраями операций FSClient-а.
FS_ZIO_SHORT_MESSAGE_MODE boolean нет false Флаг включения режима сохранения ошибок работы с файловым хранилищем в сервисе журналирования nestor. При включении режима ошибки в логах будут отображаться в сокращенном формате: Short zio message mode. ExceptionType: ТИП ОШИБКИ, Exception id: 'СГЕНЕРИРОВАННЫЙ UUID' added to journal. Указанный id будет фиксироваться в event записи nestor'а в поле data.id
LAMP_ENABLE bool нет true Пытаться ли подключиться к lamp(true) или не устанавливать соединение с lamp(false)
LAMP_USE_VERSION_2 bool нет false Использовать ли LAMP2 (true) или LAMP1 (false). Аналогичная переменная есть и в сервисах плагинов индексации
LAMP_BUFFER_SIZE int нет 10 Буфер на отправку сообщений в клиент LAMP
LAMP_RECONNECT_SCHEDULE schedule string нет I(2 seconds) Стратегия переподключения клиента LAMP (формат см. lamp.transport.model.Schedule)
LAMP_HOST url string нет lamp-dev.dev.embedika.ru Адрес клиента LAMP(должен быть непустым, если LAMP_ENABLE=true)
LAMP_PORT int нет 443 Порт клиента LAMP(должен быть непустым, если LAMP_ENABLE=true)
LAMP_TLS bool нет true Признак защищенного подключения к LAMP
LAMP_TLS_CERTIFICATE string нет "" Путь файла с сертификатом для подключения к LAMP
LAMP_TLS_PRIVATE_KEY string нет "" Путь файла с приватным ключем для подключения к LAMP
LAMP_TLS_ROOT_TRUSTED_CERTS string нет "" Путь файла с центром сертификации (Certification Authority, CA) для подключения к LAMP
LAMP_TIMEOUT duration string нет 1 minute Таймаут отправки сообщения и получения результатов через клиент LAMP
LAMP_MAX_MESSAGE_SIZE int нет 524288000 Максимальный допустимый размер сообщений в LAMP
LAMP_QUERY_PARALLELISM int нет 10 Параллелизм обработки в LAMP файлов одного объекта
APP_FILE_BUCKET string нет document S3 bucket, в котором следует искать файлы объектов
APP_ROUTE_MAPPING string нет Extraction:extraction_route;Keyword:cursor_v0.1_keyword;Plagiarism:cursor_v0.1_plagiarism;Similarity:cursor_v0.1_similarity Маппинг сервисных имен LAMP роутов с реальными LAMP роутами. Формат indexation1:route1;indexation2:route2. Список сервисные роуты см. LampRoute
APP_CLEAN_ROUTE_MAPPING string нет Plagiarism:cursor_v0.1_plagiarism_clean;Similarity:cursor_v0.1_similarity_clean Маппинг имен LAMP индексаций с LAMP роутами для удаления документов
APP_COMMAND_COMPLETION_TIMEOUT duration string нет 20 seconds Максимальное время ожидания команд после выполнения шага индексации
APP_COMMAND_PROCESSING_PARALLELISM int нет 5 Параллелизм обработки событий verdi
APP_MAX_STEP_ATTEMPTS int нет 10 Максимальное кол-во попыток выполнения шага индексации
APP_ASYNC_COMMAND_POLL_INTERVAL duration string нет 1 second Периодичность запроса статуса verdi команд
APP_ASYNC_COMMAND_TIMEOUT duration string нет 10 seconds Максимальное время ожидания выполнения verdi команды
APP_INDEXATION_DATA_BATCH int нет 100 Размер данных, получаемых за 1 раз из сервиса МД для индексации. С увеличением параметра увеличится время ожидания для принудительного прерывания, с уменьшением - увеличится нагрузка на МД
APP_INDEXATION_ENTITY_TIMEOUT duration string нет 5 minutes Время ожидания завершения всех шагов по сущности TODO Возможно стоит скалировать это время пропорционально кол-ву шагов, ведь оно может быть сильно разным
APP_INDEXATION_PARALLELISM int нет 4 Параллелизм массового индексирования
APP_VERDI_PARALLELISM int нет 4 Размер пула потоков для sender-lib
APP_VERDI_MAX_RETRY int нет 10 Максимальное число ретраев для verdi команд
APP_VERDI_RETRY_DELAY duration string нет 5 seconds Таймаут между неудачными вызовами verdi команд
APP_DEFAULT_WHITE_LISTS string нет Erika:doc,docx;PDFView:pdf Дефолтные фильтры файлов по расширениям
APP_FILE_PARALLELISM int нет 10 Лимит на одновременное число запросов к minio
PDF_VIEW_HOST string нет http://localhost:3333 Адрес сервиса для извлечения json из pdf
PDF_VIEW_TIMEOUT duration string нет 5 minutes Таймаут для запроса в сервис извлечения json из pdf
PDF_VIEW_ADDITIONAL_FIELD_NAME string нет pdfJson Ключ, под которым сохраняются результаты извлечения json из pdf
PDF_VIEW_EXTRACT_PART_NAME string нет file Ключ, под которым нужно передавать pdf для извлечения json
INDEXATION_AUTHZFORCE_ADDR url string нет http://localhost:8080/authzforce-ce Адрес сервиса authzforce
INDEXATION_AUTHZFORCE_DOMAIN string нет "" Доступный DomainID в Authzforce server
INDEXATION_AUTHZFORCE_CONNECT_TIMEOUT duration string нет 5 seconds Максимальное время ожидания ответа от Authzforce
INDEXATION_READABLE_NAME string нет "Сервис индексаций" Читаемое название этого сервиса
INDEXATION_DESCRIPTION string нет "Предназначен для индексации" Читаемое описание этого сервиса
VERDI_COMMANDS_HTTP_RETRY_ATTEMPTS int нет 5 Поле attempts из RetrySettings
VERDI_COMMANDS_HTTP_RETRY_DELAY duration string нет "5 seconds" Поле delay из RetrySettings
VERDI_COMMANDS_HTTP_RETRY_KIND string нет "OnSomeExceptions(ConnectException)" CommandResultRetryConditionKind
APP_JOURNAL_REQUIRED_STEPS string нет "Erika,FullTextSearch,FullTextCompletion,Lamp,PDFView,Keyword" Строка с перечислением типов шагов через запятую, которые обязательно должны завершиться успешно для объекта, чтобы при журналировании завершения индексации этот объект попал в число успешно обработанных. При этом если ошибка возникнет в шаге, который не входит в этот список, обработка объекта все равно будет зажурналирована как успешная. Не влияет на команду indexationStatistics
INDEXATION_JOURNAL_MODE string нет WriteToJournal Режим журналирования Nestor. Допустимые значения: WriteToJournal (Отправка в сервис журналирования), WriteToTopic (Отправка события в очередь)
INDEXATION_JOURNAL_TOPIC string да, если переменная INDEXATION_JOURNAL_MODE = WriteToTopic "" Название очереди журналирования. Для режима WriteToJournal значение игнорируется.

Команды для сервиса индексации

Список реализованных в сервисе команд, моделей EntityType и действий Actions, которые можно использовать при настройке авторизации.

Название команды EntityType Actions
createIndexationDescription indexationDescription indexation_indexationDescription_CreateIndexationDescription
getIndexationDescription indexationDescription indexation_indexationDescription_GetIndexationDescription
deleteIndexationDescription indexationDescription indexation_indexationDescription_DeleteIndexationDescription
updateIndexationDescription indexationDescription indexation_indexationDescription_UpdateIndexationDescription
listIndexationDescription indexationDescription indexation_indexationDescription_ListIndexationDescription
listIndexationDescriptionPages indexationDescription indexation_indexationDescription_ListIndexationDescriptionPages
indexationRowsList row indexation_row_row
indexationRestartStep row indexation_row_row
startIndexation indexation indexation_indexation_StartIndexation
fixIndexation indexation indexation_indexation_FixIndexation
indexationStatistics indexation indexation_indexation_IndexationStatistics
getIndexation indexation indexation_indexation_GetIndexation
getIndexations indexation indexation_indexation_GetIndexations

Команды сервиса индексаций

createIndexationDescription

Создание описания индексации.
Указываемый id должен совпадать с entityType индексируемой сущности в сервисе Модели данных.

На входе описание индексации

{
  "id": "NewEntityType",
  "steps": [
    {
      "children": [],
      "payload": {
        "type": "Erika",
        "fields": [
          "files"
        ]
      },
      "extensionFilter": {
        "type": "WhiteList",
        "allowed": [
          "docx"
        ]
      }
    }
  ]
}

В результате возвращается идентификатор описания

Поддерживается только синхронный вызов.
Результат выполнения команды журналируется.

getIndexationDescription

Получение описания индексации по идентификатору (по сути по типу объекта)

На входе идентификатор описания

"Document"

В результате описание индексации

{
  "id": "NewEntityType",
  "steps": [
    {
      "children": [],
      "payload": {
        "fields": [
          "files"
        ],
        "type": "Erika"
      },
      "extensionFilter": {
        "type": "WhiteList",
        "allowed": [
          "docx"
        ],
        "default": false
      }
    }
  ],
  "version": 1
}

Поддерживается только синхронный вызов.
Результат выполнения команды не журналируется.

deleteIndexationDescription

Удаление описания индексации и истории запусков данной индексации.

На входе идентификатор описания

"Document"

В результате количество удаленных записей

Поддерживается только синхронный вызов.
Результат выполнения команды журналируется.

updateIndexationDescription

Обновление описания индексации

На входе описание индексации

{
  "id": "NewEntityType",
  "steps": [
    {
      "children": [],
      "payload": {
        "fields": [
          "files"
        ],
        "type": "Erika"
      }
    },
    {
      "children": [],
      "payload": {
        "filesRoutes": [
          {
            "field": "files",
            "actions": [
              {
                "lampRoute": "Plagiarism"
              }
            ]
          }
        ],
        "type": "Lamp"
      }
    }
  ],
  "version": 1
}

В результате количество обновленных записей

Поддерживается только синхронный вызов.
Результат выполнения команды журналируется.

listIndexationDescription

Получение списка описаний индексаций

Входных данных нет

В результате список описаний индексаций

[
  {
    "id": "Document",
    "steps": [
      {
        "children": [
          {
            "step": {
              "fields": [
                "documentFileContent"
              ],
              "type": "FullTextSearch"
            },
            "oneLevel": false
          }
        ],
        "payload": {
          "filesRoutes": [
            {
              "field": "documentFile",
              "saveContentTo": "documentFileContent",
              "actions": [
                {
                  "lampRoute": "Extraction"
                }
              ]
            }
          ],
          "type": "Lamp"
        },
        "extensionFilter": null
      },
      {
        "children": [],
        "payload": {
          "fields": [
            "documentFile"
          ],
          "type": "Erika"
        },
        "extensionFilter": null
      }
    ],
    "version": 1
  },
  {
    "id": "agreement",
    "steps": [
      {
        "children": [],
        "payload": {
          "filesRoutes": {
            "field": "files",
            "actions": [
              {
                "lampRoute": "Plagiarism"
              }
            ]
          },
          "type": "Lamp"
        },
        "extensionFilter": null
      }
    ],
    "version": 1
  }
]

Поддерживается только синхронный вызов.
Результат выполнения команды не журналируется.

listIndexationDescriptionPages

Получение списка описаний индексаций с поддержкой пагинации.

Имя вызова команды: listIndexationDescriptionPages.
Поддерживается только синхронный вызов.
Результат выполнения команды не журналируется.

На входе Search запрос (пока поддерживается только Paging)

{
  "query": "",
  "paging": {
    "page": 2,
    "count": 2
  },
  "context": {}
}

На выходе список описаний индексаций обернутый в Page

{
  "items": [
    {
      "id": "NewEntityType",
      "steps": [
        {
          "children": [],
          "payload": {
            "fields": [
              "files"
            ],
            "type": "Erika"
          }
        }
      ],
      "whiteList": [
        "docx"
      ],
      "version": 1
    },
    {
      "id": "NewEntityType1",
      "steps": [
        {
          "children": [],
          "payload": {
            "fields": [
              "files"
            ],
            "type": "Erika"
          }
        }
      ],
      "whiteList": [
        "docx"
      ],
      "version": 1
    }
  ],
  "total": 5
}

indexationRowsList

Получение списка результатов выполнения шагов.

Имя вызова команды: indexationRowsList.
Поддерживается только синхронный вызов.
Результат выполнения команды не журналируется.

По умолчанию сортировка производится по полю created.

На входе поисковый запрос

{
  "query": "entityId",
  "context": {
    "entityId": "d81eed64-3449-4bf1-a668-13f69cbaefc4"
  },
  "paging": {
    "page": 1,
    "count": 2
  },
  "sorting": {
    "fieldName": "created",
    "order": "asc"
  }
}

Запрос принимает параметры сортировки, фильтров и пейджинга в параметре Search.

Применяется к полям модели IndexationRow.

Доступные поля для фильтрации и виды фильтров по ним:

Поле Виды фильтров Комментарии
entityId InSetQuery Фильтрация по объекту. UUID-ы, разделенные запятыми
status InSetQuery Фильтрация по статусу шага.
entityType InSetQuery Фильтрация по типу объекта. Строки, разделенные запятыми
correlationId InSetQuery Фильтрация по тэгу. Например чтобы получить все шаги определенной индексации.
stepType InSetQuery Фильтрация по типу шага. Строки, разделенные запятыми

Команда вне зависимости от входных данных никогда не возвращает результаты выполнения шагов со статусом Ignored.

Доступные поля для сортировки:

Поле
created

По умолчанию сортировка производится по полю created.

В результате список статусов шагов с пагинацией

{
  "items": [
    {
      "id": "be54b09d-c655-41f6-a87e-1c5b1ed021cd",
      "entityId": "d81eed64-3449-4bf1-a668-13f69cbaefc4",
      "entityType": "Document",
      "status": "Success",
      "eventType": "Create",
      "created": "1629964032194",
      "step": {
        "children": [],
        "payload": {
          "fields": [
            "files"
          ],
          "type": "Erika"
        },
        "extensionFilter": {
          "type": "WhiteList",
          "allowed": [
            "docx",
            "doc"
          ],
          "default": true
        }
      },
      "message": null,
      "stackTrace": null,
      "additional": {
        "skipped": {
          "fileId": "be54b09d-c655-41f6-a87e-1c5b1ed021cd",
          "additional": null,
          "name": "file.txt",
          "url": "temp/be54b09d-c655-41f6-a87e-1c5b1ed021cd"
        }
      }
    },
    {
      "id": "a4be56be-b5f0-4ff7-8a8e-a514a68b546e",
      "entityId": "d81eed64-3449-4bf1-a668-13f69cbaefc4",
      "entityType": "Document",
      "status": "Error",
      "eventType": "Create",
      "created": "1629964032194",
      "step": {
        "children": [],
        "payload": {
          "fields": [
            "files"
          ],
          "type": "Erika"
        },
        "extensionFilter": null
      },
      "message": "CommandService timeout",
      "stackTrace": null,
      "additional": null
    }
  ],
  "total": 3
}

indexationRestartStep

Перезапуск шага

На входе идентификатор статуса шага

"be54b09d-c655-41f6-a87e-1c5b1ed021cd"

В результате признак успешного перезапуска

Поддерживается только синхронный вызов.
Результат выполнения команды не журналируется.

startIndexation

Запуск индексации всех сущностей определенного типа

На вход тип сущности

"RfbrDocument"

В результате идентификатор индексации

"be54b09d-c655-41f6-a87e-1c5b1ed021cd"

Поддерживает только синхронный вызов.
Результат выполнения команды журналируется.

fixIndexation

Перезапуск индексации. Будут заново проиндексированы объекты, у которых имеется хотя-бы 1 провалившийся шаг по данной индексации, а так же будут проиндексированы новые, не индексировавшиеся до этого объекты

На вход идентификатор завершившейся индексации

"be54b09d-c655-41f6-a87e-1c5b1ed021cd"

Поддерживает только синхронный вызов.
Результат выполнения команды журналируется.

interruptIndexation

Прерывание индексации. Индексация будет прервана только после завершения индексации текущей страницы данных (см. параметр INDEXATION_DATA_BATCH)

На вход идентификатор индексации

"be54b09d-c655-41f6-a87e-1c5b1ed021cd"

Поддерживает только асинхронный вызов.
Результат выполнения команды журналируется.

indexationStatistics command

Получение статистики по индексации

На вход идентификатор индексации

"be54b09d-c655-41f6-a87e-1c5b1ed021cd"

В результате полная статистика о прохождении индексации

{
  "completed": [
    "be54b09d-c655-41f6-a87e-1c5b1ed021cd",
    "d81eed64-3449-4bf1-a668-13f69cbaefc4"
  ],
  "typesErrors": {
    "Erika": 3
  },
  "entitiesErrors": {
    "372c7c3d-21dd-4568-8cf7-6c31b36b771d": [
      "Erika"
    ]
  },
  "status": "Done"
}

Поддерживает только синхронный вызов.
Результат выполнения команды не журналируется.

getIndexation

Получение индексации

На вход идентификатор индексации

"282484ae-3c53-4176-af0b-dba62e50e606"

В результате модель индексации

{
  "id": "282484ae-3c53-4176-af0b-dba62e50e606",
  "entityType": "RfbrDocument",
  "status": "InProgress",
  "created": "2022-02-04T12:37:28.997818",
  "updated": "2022-02-04T12:37:28.997818",
  "description": {
    "id": "RfbrDocument",
    "steps": [
      {
        "children": [],
        "payload": {
          "filesRoutes": [
            {
              "field": "file",
              "saveContentTo": "fileContent",
              "actions": []
            }
          ],
          "type": "Lamp"
        },
        "extensionFilter": null
      }
    ],
    "version": 1
  }
}

Поддерживает только синхронный вызов.
Результат выполнения команды не журналируется.

getIndexations

Получение списка индексаций

Входных данных нет

В результате список индексаций

[
  {
    "id": "245d6b04-40aa-4139-8c4d-a25ae2f57a55",
    "entityType": "RfbrDocument",
    "status": "InProgress",
    "created": "2022-01-31T14:49:06.834771",
    "updated": "2022-01-31T14:49:06.834771",
    "description": {
      "id": "RfbrDocument",
      "steps": [
        {
          "children": [],
          "payload": {
            "filesRoutes": [
              {
                "field": "file",
                "saveContentTo": "fileContent",
                "actions": []
              }
            ],
            "type": "Lamp"
          },
          "extensionFilter": null
        }
      ],
      "version": 1
    }
  },
  {
    "id": "5436a8e7-1ba2-40ca-93cd-96e318d76b3d",
    "entityType": "RfbrDocument",
    "status": "Interrupted",
    "created": "2022-01-31T14:52:12.495104",
    "updated": "2022-01-31T14:53:08.142893",
    "description": {
      "id": "RfbrDocument",
      "steps": [
        {
          "children": [],
          "payload": {
            "filesRoutes": [
              {
                "field": "file",
                "saveContentTo": "fileContent",
                "actions": []
              }
            ],
            "type": "Lamp"
          },
          "extensionFilter": null
        }
      ],
      "version": 1
    }
  }
]

Поддерживает только синхронный вызов.
Результат выполнения команды не журналируется.

Модели сервиса индексаций

IndexationDescription

Описание индексации определенного типа объекта

Название поля Тип Описание
id String Идентификатор описания, соответствует типу объекта
steps Seq[Step] Шаги индексации
version Int Версия описания. Используется для optimistic lock

IndexationDescriptionDTO

Создание описания индексации определенного типа объекта

Название поля Тип Описание
id String Идентификатор описания, соответствует типу объекта
steps Seq[Step] Шаги индексации

Шаги индексации

Отдельный элемент индексации, описывающий взаимодействие с сервисами интеллектуализации, конвертации или полнотекстового поиска

ExtensionFilter

Фильтр файлов по расширениям для шагов

AllowedAll

Разрешены любые расширения

WhiteList

Название поля Тип Описание
allowed Seq[String] Допустимые расширения
default boolean Флаг для дефолтных настроек

StepChild

Описание дочернего шага

Название поля Тип Описание
step Step Описание шага
oneLevel boolean Располагается ли дочерний шаг на одном уровне с родительским шагом

Step

Описание шага. Шаг после своего выполнения может вернуть результаты в виде ключ:ссылканафайлсрезультатами. Эти результаты можно использовать в дочерних шагах. Шаг может фиксировать свои результаты в дополнительных полях файлов через сервис модели данных

Название поля Тип Описание
children Seq[StepChild] Зависящие шаги
payload StepPayload Описание самого шага
extensionFilter Option[ExtensionFilter] Опциональный фильтр файлов по расширениям
label String Опциональный лейбл шага, может быть полезен при отладке

StepPayload

Тип-сумма для описания шагов индексации. При десериализации нужно дополнительное поле type, где указывается имя типа-произведения. Аналогичное поле будет при сериализации.

Lamp (indexation)

Индексация в сервисах LAMP всех объектов индексируемой сущности. Часть типов-произведений StepPayload. Может иметь дочернии шаги. Может фиксировать отдельные результаты в сервисе модели данных.

Этот шаг для каждого объекта индексируемой сущности и каждого i-го элемента массива fileRoutes извлекает из поля filesRoutes[i].field информацию о файле, с помощью этой информации достает файл из s3, и отправляет запросы с содержимым этого файла к рутам Lamp, которые соответствуют переданным fileRoutes.actions.lampRoute в маппинге APP_ROUTE_MAPPING.

Если эти запросы будут обращаться к сервисам Lamp из LAMP_CACHEABLE_SERVICES, то результаты обработки файлов этими сервисами будут добавлены в кэш Lamp-а по id Имя_Сущности_DM;Id_объекта_DM;Имя_поля_с_файлом;ID_файла. Для сервиса extraction таким результатом будет само содержимое файла. Для каждого внутреннего сервиса Lamp поддерживается свой отдельный кэш.

Краткая справка про Lamp:

Lamp состоит внутри себя из нескольких сервисов, которые по-разному обрабатывают входящие файлы. К каким конкретно сервисам внутри себя обратится Lamp при вызове определенного рута можно посмотреть в переменной ROUTER_ROUTES сервиса router20.

Название поля Тип Описание
filesRoutes Seq[FileRoutes] Индексация отдельных файловых полей сущности

FullTextSearch

Индексация в сервисе полнотекстового поиска. Часть типов-произведений StepPayload

Название поля Тип Описание
fields Seq[String] Поля, значение которых нужно сохранить в поисковом индексе

FullTextCompletion

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

Название поля Тип Описание
fields Seq[String] Поля, значение которых нужно сохранить в индексе для автодополнений
saveKeywordsToDM Option[String] Поле в модели данных, внутри additionalData, в которое нужно сохранить ключевые слова, выделенные из файлов

Erika

Индексация, конвертирующая файлы объекта в pdf-представление. Обновляет состояние в сервисе МД. Часть типов-произведений StepPayload. Может иметь дочернии шаги. Сохраняет результаты в сервисе модели данных в дополнительных полях файлов под ключем pdf

Название поля Тип Описание
fields Seq[String] Список полей для конвертации.

Plugin

Пример описания действия Plagiarism в шаге Lamp

{
  "lampRoute": "Plagiarism",
  "routeResult": null
}

Пример описания действия Similarity в шаге Lamp

{
  "lampRoute": "Similarity",
  "routeResult": null
}

Индексация в плагинах интеллектуализации. Часть типов-произведений StepPayload. В поле topic указывается кафка-топик, по которому произойдет связь с конкретным плагином.

Является единственным типом шагов, которые не игнорируются в индексациях, вызванных событиями удаления entityObject. Подробнее это поведение описано здесь.

Доступные на данный момент плагины:

Для plagiarismPlugin и similarityPlugin шаг должен быть запущен после обработки всех передаваемых fields с помощью шага Lamp (в шаге Lamp обрабатываемое поле указывается в filesRoutes.field). В шаге Lamp в filesRoutes.actions должны присутствовать действия Plagiarism и Similarity соответственно.

Название поля Тип Описание
topic String Кафка топик целевого плагина
fields Seq[String] Список файловых полей для индексации
needBacklinks Boolean Определяет, нужно ли запускать переиндексацию связанных объектов, если файлы этих объектов не найдены в кэше lamp (используется только для lamp2)
parameters Json Произвольные параметры, определяющие специфичные настройки индексации для обработки плагином. Плагины plagiarism, similarity и tagging не учитывют данные параметры.

PDFView

Индексация для предварительного рендеринга pdf. Часть типов-произведений StepPayload. Сохраняет результаты в сервисе модели данных в дополнительных полях файлов под ключом из настройки PDF_VIEW_ADDITIONAL_FIELD_NAME

Название поля Тип Описание
fields Seq[String] Список файловых полей для индексации

Keyword

Пример описания действия Keyword в шаге Lamp

{
  "lampRoute": "Keyword",
  "routeResult": {
    "resultName": "fileKeywords",
    "saveToDM": false
  }
}

Пример описания шага индексации Keyword

{
  "children": [],
  "payload": {
    "fields": [
      "fileKeywords"
    ],
    "type": "Keyword"
  },
  "extensionFilter": null,
  "label": ""
}

Шаг индексации, осуществляющий заполнение реестра ключевых слов и установку связей ключей и объектов на основе ключевых слов, полученных в шаге Lamp. Часть типов-произведений StepPayload.

  1. Считывает из entityObject-ов, обрабатываемых индексацией, содержимое полей, идентификаторы которых указаны в fields.
  2. Конвертирует полученное содержимое во входные данные команды updateKeywords.
  3. Асинхронно вызывает команду updateKeywords и успешно завершает свое выполнение, если асинхронный вызов updateKeywords возвращает commandId. Иначе падает с ошибкой.

Шаг должен быть запущен после обработки нужных файловых полей сущности с помощью шага Lamp. В шаге Lamp в filesRoutes.actions должно присутствовать действие Keyword с указанным routeResult.resultName. Указанный в шаге Lamp routeResult.resultName затем должен быть передан в шаге Keywords в fields.

Название поля Тип Обязательное Значение по умолчанию Описание Ограничения
fields Seq[FieldId] Да Нет Поля, из которых происходит выгрузка ключей, полученных Lamp, для формирования входного потока команды UpdateKeywords Все поля, указанные в fields должны быть полями, сгенерированными на предыдущих шагах индексации.

FileRoutes

Индексация в сервисах LAMP отдельно взятого файлового поля сущности. Модель формирует ключи для сохранения результатов работы шага Lamp из saveContentTo и actions.

Поле Тип Описание
field String Имя поля, где хранится файл, для которого будет запущена индексация
saveContentTo Option[String] Опциональный ключ для сохранения результата работы extraction в data-model в поле data.[значение field].additional.[значение saveContentTo]
actions Seq[FileRoute] Список конкретных индексаций в LAMP
fieldSearch Search Фильтр связанной сущности, подробнее в подразделе про Lamp и длинные пути

FileRoute

Конкретная индексация в LAMP

Название поля Тип Описание
lampRoute LampRoute Lamp роут
routeResult Option[RouteResult] Опциональная обработка результатов от LAMP

RouteResult

Обработка результатов от LAMP

Название поля Тип Описание
resultName String Ключ для результата, по которому следующие шаги могу получить этот результат
saveToDM Boolean Флаг, указывающий нужно ли сохранить результат в сервис модели данных. По умолчанию false

LampRoute (indexation)

Имена сервисных LAMP роутов. Доступные на данный момент роуты: Extraction, Keyword, Plagiarism, Similarity, ExtractionPdfium

EventType

Типы событий объектов, которые принимает сервис индексаций: Create, Delete, Update, Reindex, IndexPlagiarismPluginBacklinks, IndexSimilarityPluginBacklinks

IndexationRow

Статус шага индексации

Название поля Тип Описание
id UUID Идентификатор шага
entityId UUID Идентификатор объекта, который индексируется этим шагом
entityType String Тип объекта, который индексируется этим шагом
status IndexationRowStatus Статус шага
created LocalDateTime Дата создания статуса шага
step Step Шаг индексации
correlation_id String Тэг. Используется, в частности, для объединения статусов по одной индексации
level Int Уровень обработки индексации, который вызвал этот шаг
message Option[String] Опциональный текст ошибки выполнения шага
stackTrace Option[String] Опциональное подробное описание ошибки выполнения шага
additional Option[Json] Опицональная дополнительная информация о шаге
initial_event Option[EventType] Тип события, который вызвал индексацию, содержащую этот шаг

IndexationRowStatus

Типы статусов шагов индексации: Success(успешная обработка шага), Error(ошибка обработки шага), Ignored(проигнорирован).

Подробнее это поведение описано здесь.

Page

Страница списка элементов (часть списка с примененным пейджингом) типа T

Название поля Тип Описание
items Seq[T] Список элементов на запрошенной странице
total Long Общее количество объектов

IndexationStatistics

Статистика результатов индексации

Название поля Тип Описание
completed Seq[UUID] Список сущностей, по которым все шаги были успешно выполнены
typesErrors Map[String, Int] Сводная информация об ошибках, в формате "Тип шага:кол-во провалившихся шагов"
entitiesErrors Map[UUID, Seq[String]] Сводная информация об ошибках, в формате "идентификатор сущности:типы провалившихся шагов"
status IndexationStatus Статус индексации

IndexationStatus

Типы статусов индексации: InProgress, Done, Interrupted

Indexation

Индексация определенного типа сущностей

Название поля Тип Описание
id UUID Идентификатор, по которому можно получить модель, статистику, и сделаные шаги
entityType String Тип сущности
status IndexationStatus Статус индексации
created LocalDateTime Дата создания
updated LocalDateTime Дата обновления
description IndexationDescription Зафиксированное на момент запуска описание индексации

Особенности журналирования сервиса индексации

При журналировании окончания и прерывания индексаций, которые содержат шаги с типом Plugin, шаги с типом Plugin не учитываются при подсчете количества успешно или неуспешно обработанных объектов. Успешными при этом считаются шаги со статусом IndexationRowStatus Success и Ignored.

Delete entityObject indexations

Если индексация была начата из-за события с eventType равным delete, то она осуществляется по особым правилам.

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

Если индексация дойдет до шагов-плагинов, то они будут запущены и выполнены исходя из своей логики и после этого могут иметь статусы Ignored, Error и Success.

Шаги со статусом Ignored не возвращаются в команде indexationRowsList даже если запросить их в search.

Lamp и длинный путь к relation полям (indexation)

Пример использования длинного пути до поля с файлом с использованием фильтра

{
  "filesRoutes": [
    {
      "field": "children/file",
      "saveContentTo": "fileContent",
      "actions": [],
      "fieldSearch": {
        "query": "name",
        "context": {
          "name": "fileName.txt"
        }
      }
    }
  ],
  "type": "Lamp"
}

В индексации Lamp в поле field есть возможность указывать длинный путь до поля с файлами через relation.
В качестве разделителя полей в пути должен использоваться символ /.

Пример:

Создана сущность Folder(name: String) с Relation-полем children
Она связана с другой сущностью File(name: String, file: StoredFile), которое имеет поле с файлом.
В этом случае, путь до файла можно указать следующим образом: children/file.

Глубина пути не ограничена. Если отношение имеет тип one-to-many или many-to-many, то будут включены все связанные файлы.

Также можно указать фильтр связанной сущности в поле fieldSearch.
Этот фильтр будет применен к конечной сущности в цепочке, а не к исходной.

Для иллюстрации предположим, что в предыдущем примере relation между "Folder" и "File" имеет тип one-to-many и
мы хотим отфильтровать файлы по полю "name". В таком случае, указанный фильтр будет применен к массиву из объектов сущности "File".

{
  "query": "name",
  "context": {
    "name": "file.txt"
  }
}

Integration-external-api: внешний интерфейс сервиса интеграций

Внешний API сервиса интеграций позволяет импортировать данные в систему на основе Verdi (далее просто Verdi), получать описание и пример данных для импорта.
Доступен по HTTP.

Сервис оперирует понятием сущности (entity). Он позволяет загрузить любые объекты с любым набором полей. Для отделения таких объектов с разным набором атрибутов друг от друга вводится понятие сущности. Сущность - это описание группы объектов, имеющих общий набор полей (например: договор, сотрудник или патент). Каждая сущность идентифицируется определенным типом entityType. Все операции с ней должны сопровождаться передачей соответствующего entityType в строке запроса.

Между двумя объектами могут устанавливаться отношения (relation).
Понятием "Вид отношения" называется комбинация двух сущностей и "виртуального" поля первой сущности. Например: отношение авторства может быть представлено комбинацией сущностей Book и Person, и полем author. Виртуальные поля отношений фактически не являются частью объекта и не могут быть напрямую указаны при создании или обновлении объекта; но при этом возвращаются при получении объекта из Verdi. Например: если у книги указан автор, его id вернется в поле author при получении данных этой книги.
Отношение между двумя объектами может быть установлено только в рамках какого-либо вида отношений сущностей этих объектов. Между двумя сущностями может быть установлено несколько видов отношений; кроме того может быть установлено отношение сущности с самой собой (например: отношение родительства или отношение связи элементов графа). Вид отношений считается доступным для текущего клиента, если ему доступны обе входящие в него сущности
(см. Список сущностей, доступных для текущего клиента).

Для работы с файлами нужно использовать отдельный вызов UploadFile. По нему в систему можно загрузить некоторый файл. На выходе метода - id файла. Этот id необходимо передать при сохранении или обновлении объекта в соответствующем поле типа file. Тип поля можно узнать с помощью вызова GetEntityTypeSchema.

Каждый запрос требует указать заголовок X-Client-Token: [token], где [token] - это токен зарегистрированного, незаблокированного клиента.
Если запрос связан с какой-либо сущностью, данный клиент также должен иметь доступ к ней.

Во внешнем API реализовано получение документации по доступным для клиента типам данных:

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

Получение документации внешнего интерфейса сервиса интеграций

ListEntityTypesForCurrent

На входе ничего

На выходе список доступных типов данных для текущего клиента

[
  {
    "id": "paper",
    "title": "Научная статья",
    "description": "Документ, представляющий научную статью"
  }
]

Возвращает перечень доступных для клиента типов данных

Путь: HTTP GET /external/v1/help/entityType

GetEntityTypeSchema

На входе ничего

На выходе JSON-Schema сущности

{
  "$schema": "https://json-schema.org/draft/2019-09/schema",
  "definitions": {
    "date": {
      "type": "integer"
    },
    "relation": {
      "type": "string"
    },
    "catalog": {
      "type": "string"
    },
    "multi-catalog": {
      "type": "array",
      "items": {
        "type": "string",
        "format": "uuid"
      }
    },
    "file": {
      "type": "object",
      "properties": {
        "fileId": {
          "type": "string",
          "format": "uuid"
        },
        "name": {
          "type": "string"
        },
        "size": {
          "type": "integer",
          "minimum": 0
        },
        "url": {
          "type": "string"
        },
        "additional": {
          "type": "object"
        },
        "created": {
          "type": "integer",
          "minimum": 0
        },
        "modified": {
          "type": "integer",
          "minimum": 0
        },
        "md5": {
          "type": "string",
          "pattern": "^[0-9a-fA-F]{32}$"
        }
      },
      "required": [
        "fileId"
      ]
    }
  },
  "type": "object",
  "properties": {
    "modified": {
      "$ref": "#/definitions/date",
      "title": "Дата обновления файла",
      "additional": false,
      "rawType": "dateTime",
      "description": "Дата обновления файла",
      "example": 1582966800,
      "exampleType": "number"
    },
    "created": {
      "$ref": "#/definitions/date",
      "title": "Дата создания файла",
      "additional": false,
      "rawType": "dateTime",
      "description": "Дата создания файла",
      "example": 1582966800,
      "exampleType": "number"
    },
    "path": {
      "type": "string",
      "maxLength": 5000,
      "title": "Путь в папке до файла",
      "additional": false,
      "rawType": "string",
      "settings": {
        "maxLength": 5000
      },
      "example": "/docs/dogovor.docx",
      "exampleType": "string"
    },
    "name": {
      "type": "string",
      "maxLength": 1000,
      "title": "Название файла",
      "additional": false,
      "rawType": "string",
      "settings": {
        "maxLength": 1000
      },
      "example": "Договор",
      "exampleType": "string"
    },
    "file": {
      "type": "array",
      "items": {
        "$ref": "#/definitions/file"
      },
      "multiple": false,
      "maxItems": 1,
      "title": "ID файла",
      "additional": false,
      "rawType": "file"
    },
    "author": {
      "title": "Автор документа",
      "$ref": "#/definitions/relation",
      "multiple": false,
      "additional": false,
      "readOnly": true,
      "nullable": true,
      "to": "Author",
      "settings": {
        "to": "Author"
      }
    }
  },
  "required": [
    "created",
    "path",
    "name",
    "file"
  ],
  "relations": [
    {
      "name": "Document_To_Author",
      "entity1": "Document",
      "entity2": "Author",
      "entity1Field": "author",
      "entity2Field": "documents",
      "relationType": "many-to-one"
    }
  ]
}

Получение описания модели данных для конкретной сущности в виде JSON-Schema.

Путь: HTTP GET /external/v1/help/entityType/:entityTypeId/schema

GetObjectExample

На входе ничего

На выходе пример данных объекта

{
  "id": "64f1e728-7fe7-4886-9d5c-e72452dbc3ce",
  "internalId": "933d8db6-fddc-475e-8366-652c8d0a0f32",
  "entityType": "FolderFile",
  "source": "example",
  "created": 1644839076580,
  "modified": 1644839076580,
  "data": {
    "created": 1582966800,
    "file": [
      {
        "fileId": "00000000-0000-0000-0000-000000000000",
        "name": "Пример_файла.txt",
        "extension": "txt",
        "size": 1,
        "url": "datamodel/00000000-0000-0000-0000-000000000000",
        "additional": {},
        "created": 0,
        "modified": 0,
        "md5": "D41D8CD98F00B204E9800998ECF8427E"
      }
    ],
    "modified": 1582966800,
    "name": "Договор",
    "path": "/docs/dogovor.docx",
    "author": "author1Id"
  },
  "additionalData": {},
  "version": 1
}

Получение примера объекта указанной сущности

Путь: HTTP GET /external/v1/help/entityType/:entityTypeId/example

GetOpenAPI

Генерирует описание внешнего API для указанной сущности (в формате OpenAPI v3.1.0)

Путь: HTTP GET /external/v1/help/entityType/:entityTypeId/openAPI

Работа с файлами (внешний интерфейс сервиса интеграций)

UploadFile

На входе POST-запрос с Content-Type: multipart/form-data и файлом в бинарном виде в поле file

На выходе ID загруженного файла

{
  "fileId": "1c689788-9617-4c93-bcee-6eae8909a0ba"
}

Загрузить файл в систему.

Путь: HTTP POST /external/v1/file/upload

Работа со справочниками (внешний интерфейс сервиса интеграций)

ListCatalogItems

На входе номер и размер страницы, и, опционально, фильтр по названию элемента

{
  "paging": {
    "page": 1,
    "count": 10
  },
  "titleLike": "%файл%"
}

На выходе искомый список элементов запрашиваемого справочника и их общее количество на всех страницах

{
  "items": [
    {
      "id": "2247fbe6-1f78-47d3-af28-e71f75535a84",
      "catalogId": "fbf859d2-30db-4789-9fdd-71add0832772",
      "code": "FileTags-3",
      "title": "Файл кода",
      "archived": false,
      "metadata": {},
      "created": 1642749153188,
      "modified": 1664290811956,
      "version": 10
    },
    {
      "id": "a4f1b0e5-0c47-4d82-bbd7-2c1f2164765a",
      "catalogId": "fbf859d2-30db-4789-9fdd-71add0832772",
      "code": "FileTags-5",
      "title": "Музыкальный файл",
      "archived": false,
      "metadata": {},
      "created": 1642749350176,
      "modified": 1642758418413,
      "version": 3
    },
    {
      "id": "6d2aa5c7-b0b8-455f-82c2-da90ff074a95",
      "catalogId": "fbf859d2-30db-4789-9fdd-71add0832772",
      "code": "FileTags-6",
      "title": "Видеофайл",
      "archived": false,
      "metadata": {},
      "created": 1642757894740,
      "modified": 1643197192686,
      "version": 2
    }
  ],
  "total": 3
}

Получение данных справочника в системе.

Путь: HTTP POST /external/v1/catalog/:catalogCode/listItems

Работа с объектами (внешний интерфейс сервиса интеграций)

CreateEntity (Integration)

На входе список создаваемых объектов

{
  "items": [
    {
      "id": "first",
      "data": {
        "number": 1,
        "file": [
          {
            "fileId": "dfca1cac-0df2-454a-b57a-4a2c360b09db"
          }
        ]
      }
    },
    {
      "id": "second",
      "data": {
        "number": 2,
        "file": [
          {
            "fileId": "724d8b05-6992-4d3c-ac0b-501ef02cb74e"
          }
        ]
      }
    }
  ]
}

На выходе данные по статусу создания каждого объекта и дополнительные данные о загрузке

{
  "items": [
    {
      "id": "first",
      "statusCode": 201,
      "payload": null
    },
    {
      "id": "second",
      "statusCode": 409,
      "payload": null
    }
  ]
}

Создание объектов в системе (импорт).

Для каждого объекта передается id и его атрибуты в виде произвольного json. Набор атрибутов должен соответствовать json-схеме сущности, которую можно получить с помощью вызова GetEntityTypeSchema

Путь: HTTP POST /external/v1/entity/:entityTypeId

UpdateEntity (Integration)

На входе список обновляемых объектов

{
  "items": [
    {
      "id": "first",
      "data": {
        "number": 101,
        "file": [
          {
            "fileId": "0cae7ea7-a6eb-4492-b72f-7a3d8187a17c"
          }
        ]
      }
    },
    {
      "id": "second",
      "data": {
        "number": 102,
        "file": [
          {
            "fileId": "22b9e63e-c0b6-43a6-9ce3-6540d5731c2b"
          }
        ]
      }
    }
  ]
}

На выходе данные по статусу обновления каждого объекта и дополнительные данные об обновлении

{
  "items": [
    {
      "id": "first",
      "statusCode": 200,
      "payload": null
    },
    {
      "id": "second",
      "statusCode": 404,
      "payload": {
        "message": "Processing error: ERROR: Entity object not found",
        "data": null
      }
    }
  ]
}

Обновление данных объектов в системе. Обновление данных происходит путем поиска подходящих объектов по переданному id. Переданные данные по объекту перезаписывают имеющиеся.

Для каждого объекта передается id и его атрибуты в виде произвольного json. Набор атрибутов должен соответствовать json-схеме сущности, которую можно получить с помощью вызова GetEntityTypeSchema

Путь: HTTP PUT /external/v1/entity/:entityTypeId

DeleteEntity (Integration)

На входе перечень ID удаляемых объектов

{
  "items": [
    {
      "id": "second"
    }
  ]
}

На выходе данные по статусу удаления каждого объекта и дополнительные данные об удалении

{
  "items": [
    {
      "id": "second",
      "statusCode": 200,
      "payload": null
    }
  ]
}

Удаление объектов в системе.

Путь: HTTP POST /external/v1/entity/:entityTypeId/deleteByIds

GetEntity (Integration)

На входе перечень ID объектов

{
  "items": [
    {
      "id": "first"
    }
  ]
}

На выходе данные по каждому запрошенному объекту

{
  "items": [
    {
      "id": "first", 
      "statusCode": 200,
      "payload": {
        "id": "first",
        "internalId": "21c30f14-6671-4c3d-b238-d7bb7f738ee5",
        "entityType": "document",
        "source": "IntegrationClient",
        "created": 1651821345542,
        "modified": 1651821345542,
        "data": {
          "number": 101,
          "file": [
            {
              "fileId": "0cae7ea7-a6eb-4492-b72f-7a3d8187a17c",
              "name": "Договор.pdf",
              "extension": "pdf",
              "size": 254873,
              "url": "datamodel/document/0cae7ea7-a6eb-4492-b72f-7a3d8187a17c",
              "additional": {},
              "created": 1651821345718,
              "modified": 1651821345718,
              "md5": "C4BA149A18155BF6E74AA55AA79776D6"
            }
          ]
        },
        "additionalData": {}, 
        "version": 2
      }
    }
  ]
}

Получение данных объектов.

Путь: HTTP POST /external/v1/entity/:entityTypeId/getByIds

UpdateEntityRelations (Integration)

На входе перечень связываемых отношениями объектов с указанием виртуальных полей отношений

{
  "items": [
    {
      "id": "firstArticle",
      "relations": {
        "fromBook": ["myFirstBook"],
        "authors": ["me"]
      }
    },
    {
      "id": "secondArticle",
      "relations": {
        "fromBook": ["mySecondBook"],
        "authors": ["me", "anotherGuy"]
      }
    }
  ]
}

На выходе статус сохранения каждого отношения

{
  "items": [
    {
      "id": "firstArticle",
      "relation": "fromBook",
      "relatedId": "myFirstBook",
      "error": null
    },
    {
      "id": "firstArticle",
      "relation": "authors",
      "relatedId": "me",
      "error": null
    },
    {
      "id": "secondArticle",
      "relation": "fromBook",
      "relatedId": "mySecondBook",
      "error": null
    },
    {
      "id": "secondArticle",
      "relation": "authors",
      "relatedId": "me",
      "error": null
    },
    {
      "id": "secondArticle",
      "relation": "authors",
      "relatedId": "anotherGuy",
      "error": null
    }
  ]
}

Обновление списка отношений для объектов сущности entityTypeId.
Команда полностью обновляет список отношений каждого из объектов сущности; таким образом, указанные в теле команды отношения будут созданы, а не указанные — удалены. Например: если у объекта first были ранее созданы отношения с объектами A и B по полю field, а при вызове команды в теле был указан элемент {"id": "first", "relations": {"field": ["A", "C"]}}, то отношение с объектом B удалится, а с объектом C — создастся.

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

Путь: HTTP POST /external/v1/entity/:entityTypeId/updateRelations

ListEntityMeta (Integration)

На входе данные для получения определенной страницы

{
  "paging": {
    "page": 2,
    "count": 10
  }
}

На выходе страница со списком объектов

{
  "items": [
    {
      "id": "first",
      "internalId": "21c30f14-6671-4c3d-b238-d7bb7f738ee5",
      "entityType": "document",
      "source": "IntegrationClient",
      "created": 1651821345542,
      "modified": 1651821345542,
      "version": 2
    }
  ],
  "total": 11
}

Получение метаданных объектов в системе: идентификаторов и прочих служебных аттрибутов.

Путь: HTTP POST /external/v1/entity/:entityTypeId/listMeta

Объекты документации внешнего интерфейса сервиса интеграций

AvailableEntityType

Описание доступной текущему клиенту сущности

Поле Тип Обязательное Описание
id string Да Код сущности
title string Да Название сущности
description string Да Описание сущности

EntityObject (Integration)

Данные объекта сущности

Поле Тип Обязательное Описание
id string Нет Идентификатор объекта, с которым он был загружен. Будет пустым, если объект создан внутри системы
internalId uuid Да Внутренний идентификатор объекта в формате UUID
entityType string Да Тип сущности объекта
source string Да Источник, откуда был получен объект (импорт, интерфейс, итп)
created timestamp Да Дата и время создания объекта в виде timestamp
modified timestamp Да Дата и время последнего изменения объекта в виде timestamp
data json object Да Исходные данные объекта. Могут быть изменены пользователем
additionalData json object Да Дополнительные данные по объекту, полученные системой из сервисов интеллектуализации
version integer Да Версия изменений

ListEntityMetaDTO (Integration)

Запрос списка метаданных объектов

Поле Тип Обязательное Описание
paging Paging Да Данные для получения определенной страницы

EntityMeta (Integration)

Метаданные объекта сущности

Поле Тип Обязательное Описание
id string Нет Идентификатор объекта, с которым он был загружен. Будет пустым, если объект создан внутри системы
internalId uuid Да Внутренний идентификатор объекта в формате UUID
entityType string Да Тип сущности объекта
source string Да Источник, откуда был получен объект (импорт, интерфейс, итп)
created timestamp Да Дата и время создания объекта в виде timestamp
modified timestamp Да Дата и время последнего изменения объекта в виде timestamp
version integer Да Версия изменений

FileUploadResult

Результат загрузки файла

Поле Тип Обязательное Описание
fileId string Да Идентификатор загруженного файла в формате UUID

ListCatalogItemsDTO

Запрос элементов справочника

Поле Тип Обязательное Описание
paging Paging Да Данные для получения определенной страницы
titleLike string Нет Поиск по названию элемента справочника. Если поле пустое, тогда возвращаются все элементы

CatalogItem

Данные элемента справочника

Поле Тип Обязательное Описание
id uuid Да Идентификатор элемента справочника в формате UUID
catalogId uuid Да Идентификатор справочника в формате UUID
code string Да Код элемента справочника
title string Да Название элемента справочника
archived boolean Да Признак архивности элемента
metadata json object Да Произвольные дополнительные данные в виде json-объекта
created timestamp Да Дата и время создания элемента в виде timestamp
modified timestamp Да Дата и время последнего изменения элемента в виде timestamp
version integer Да Версия изменений

ObjectCrudDTO

Список объектов для выполнения CRUD-операции с ними

Поле Тип Обязательное Описание
items List[ObjectCrudDTOItem] Да Список объектов для выполнения операции с ними

ObjectCrudDTOItem

Данные объекта для выполнения CRUD-команды с ним

Поле Тип Обязательное Описание
id string Да Идентификатор объекта в исходной системе
data json object Нет Опциональные данные объекта в произвольном json-формате ключ-значение. Актуально в командах Create и Update.

ObjectCrudResponse

Ответ на CRUD-операцию (команду) со списком объектов

Поле Тип Обязательное Описание
items List[ObjectCrudResponseItem] Да Список результатов выполнения команд над объектами

ObjectCrudResponseItem

Результат выполнения CRUD-команды над объектом

Поле Тип Обязательное Описание
id string Да Идентификатор объекта в исходной системе
statusCode integer Да Код результата операции с объектом в формате кода HTTP-ответа
payload json object Нет Данные ответа в произвольном json-формате

UpdateRelationsDTO

Запрос на обновление списка отношений объектов

Поле Тип Обязательное Описание
items List[UpdateRelationsDTOItem] Да Список объектов для выполнения операции с ними

UpdateRelationsDTOItem

Данные объектов для установления отношений между ними

Поле Тип Обязательное Описание
id string Да ID объекта, для которого обновляется список отношений
relations json object Да Объект, где ключ - это название поля отношения, а значение — ID объектов, которые должны быть связаны отношением с объектом id

UpdateRelationsResponse

Ответ на операцию (команду) обновления перечня отношений

Поле Тип Обязательное Описание
items List[UpdateRelationsResponseItem] Да Список результатов сохранения указанных отношений

UpdateRelationsResponseItem

Результат сохранения отношения между объектами

Поле Тип Обязательное Описание
id string Да ID объекта, для которого обновлялся список отношений
relatedId string Да ID объекта, связываемого отношением с объектом id
relation string Да Название поля, по которому устанавливается отношение
error string Нет Ошибка сохранения отношения, если сохранение прошло неуспешно; иначе null

Integration: сервис интеграций

Сервис интеграций, он же сервис импорта, включает в себя внутренний и внешний API:

В данной документации описан внутренний API. Во внутреннем API сервиса реализованы следующие команды:

Локальный запуск сервиса интеграций

При запуске сервиса ожидается, что уже развернута необходимая инфраструктура:

Кроме того, конфигурация стенда должна подразумевать доступ к внешней части API (т.е. той части, путь которой начинается с /external) по HTTP, минуя apigateway.
Например, на сервере может быть настроено перенаправление с http://verdi-host.org/integration/api/external/path на /external/path.

Запуск из консоли с помощью SBT

INTEGRATION_DB_HOST=localhost INTEGRATION_DB_PORT=5432 INTEGRATION_DB_NAME=integration_db INTEGRATION_DB_USER=postgres INTEGRATION_DB_PASSWORD=12345 sbt boot/run

Список переменных окружения для сервиса Integration

Переменная Тип Обязательная Значение по умолчанию Описание
INTEGRATION_HTTP_HOST string нет "0.0.0.0" Хост для HttpListener.
INTEGRATION_HTTP_PORT int нет 8192 Порт для HttpListener.
INTEGRATION_KAFKA_SERVERS string нет "localhost:9092" Адрес Kafka.
INTEGRATION_KAFKA_TOPIC string нет "integration_commands" Название топика для команд.
INTEGRATION_KAFKA_CONSUMER_GROUP string нет "integration_consumer_group" Название consumer-группы для чтения команд.
INTEGRATION_KAFKA_COMMANDEVENT_TOPIC string нет "commandevents" Название топика для отправки сообщений со статусом команд.
INTEGRATION_KAFKA_PARTITIONS int нет 10 Количество партиций в топике команд.
INTEGRATION_KAFKA_CONSUMER_RESTART_MIN_BACKOFF duration string нет 1 second Минимальная задержка перед перезапуском.
INTEGRATION_KAFKA_CONSUMER_RESTART_MAX_BACKOFF duration string нет 30 seconds Максимально возможная задержка перед перезапуском.
INTEGRATION_KAFKA_CONSUMER_RESTART_RANDOM_FACTOR float нет 0.2 Коэффициент величины дополнительной случайной задержки(jitter) относительно основной задержки: 0.0 - без случайной задержки, 1.0 - до 100% задержки. Если после умножения задержки на INTEGRATION_KAFKA_CONSUMER_RESTART_RANDOM_FACTOR получится меньше 1 миллисекунды, то jitter будет приравнен к нулю.
INTEGRATION_KAFKA_CONSUMER_RESTART_MAX_RESTARTS int нет 5 Максимальное количество перезапусков в заданный период времени. После превышения этого числа сервис будет объявлен больным. Все рестарты для каждого отдельного сообщения увеличивают и общий счетчик рестартов консьюмера, поэтому при использовании INTEGRATION_KAFKA_CONSUMER_PER_MESSAGE_RESTART_MAX_RESTARTS нужно указывать INTEGRATION_KAFKA_CONSUMER_RESTART_MAX_RESTARTS > INTEGRATION_KAFKA_CONSUMER_PER_MESSAGE_RESTART_MAX_RESTARTS или не указывать INTEGRATION_KAFKA_CONSUMER_PER_MESSAGE_RESTART_MAX_RESTARTS совсем.
INTEGRATION_KAFKA_CONSUMER_PER_MESSAGE_RESTART_MAX_RESTARTS int нет 2 Максимальное количество раз, которое консьюмер перезапустится с неизменной очередью сообщений(в пределах DATA_MODEL_KAFKA_CONSUMER_RESTART_MAX_RESTARTS_WITHIN), прежде чем проигнорировать сообщение, на котором происходит ошибка (Указано количество рестартов, а не прочтений. Если INTEGRATION_KAFKA_CONSUMER_RESTART_MAX_RESTARTS = 2, то ошибочное сообщение будет обработано 3 раза, после чего произойдет 3ий рестарт и оно будет проигнорировано). Если указать 0, то перезапуск произойдет, но сообщение будет обработано только в первый раз, когда произошла ошибка. Если указать значение меньше 0, то перезапуски все равно будут происходить, но игнорирование сообщений, вызывающих ошибку, будет отключено.
INTEGRATION_KAFKA_CONSUMER_PER_MESSAGE_RESTART_CACHE_SIZE int нет 100 Для каждого сообщения счетчик перепрочтений хранится в кэше. Максимальное количество значений в этом кэше.
INTEGRATION_KAFKA_CONSUMER_PER_MESSAGE_RESTART_CACHE_TTL duration string нет 5 minutes Для каждого сообщения счетчик перепрочтений хранится в кэше.Максимальное время жизни элемента в этом кэше. В случае отсутствия значения время жизни элемента не будет ограничено.
INTEGRATION_KAFKA_CONSUMER_RESTART_MAX_RESTARTS_WITHIN duration string нет 5 minutes Период времени для ограничения перезапусков.
INTEGRATION_KAFKA_CONSUMER_POLL_TIMEOUT duration string нет 10 milliseconds timeout запроса poll для kafka consumer
INTEGRATION_KAFKA_CONSUMER_POLL_INTERVAL duration string нет 100 milliseconds интервал между запросами poll для kafka consumer
INTEGRATION_KAFKA_CONSUMER_PROPS string нет "max.poll.records=500;max.partition.fetch.bytes=524288" дополнительные параметры для kafka consumer в формате "key1=value1;key2=value2"
INTEGRATION_KAFKA_PRODUCER_PROPS string нет "batch.size=524288;linger.ms=10;max.request.size=1048576" дополнительные параметры для kafka producer в формате "key1=value1;key2=value2"
INTEGRATION_KAFKA_AUTH_USER string нет "" Название учетной записи Kafka. Если название не указано, то настройки авторизации не будут применены.
INTEGRATION_KAFKA_AUTH_PASSWORD string нет "" Пароль учетной записи Kafka.
INTEGRATION_KAFKA_AUTH_PRINCIPAL string нет "" Principal учетной записи Kafka в Kerberos(в случае соединения с kafka через Kerberos).
INTEGRATION_KAFKA_AUTH_KEYTAB_PATH string нет "" Путь до keytab-файла(в случае соединения с kafka через Kerberos).
INTEGRATION_KAFKA_AUTH_TRUSTSTORE_LOCATION string нет "" Путь до хранилища сертификатов (Java key store). Если путь не указан, то сертификат применяться не будет.
INTEGRATION_KAFKA_AUTH_TRUSTSTORE_PASSWORD string нет "" Пароль к хранилищу сертификатов.
INTEGRATION_KAFKA_AUTH_MODE string нет "static" Режим аутентификации: static - одна учетная запись на все запросы, mapping - учетная запись зависит от запроса
INTEGRATION_KAFKA_AUTH_CONFIG string нет "" Настройки для аутентификации: если AuthMode = mapping, то необходим JSON с List[KafkaAuthConfig]. Переменная соответствует полю authConfig из KafkaAuthSettings.
INTEGRATION_KAFKA_AUTH_CACHE_SIZE int нет Максимальный размер кеша для Kafka producer (количество активных соединений).
INTEGRATION_KAFKA_AUTH_CACHE_TTL duration string нет Время жизни Kafka producer в кеше.
INTEGRATION_KAFKA_CONNECTION_CHECK_TEST_MESSAGES_INTERVAL duration string нет 4 minutes Применяется только для producer-ов со способом аутентификации kerberos. Интервал отправки тестовых сообщений кафки в топик connectionCheck.testMessagesTopicName. Тестовые сообщения (null, service producer test) отправляются регулярно с этим интервалом.
INTEGRATION_KAFKA_CONNECTION_CHECK_INTERVAL duration string нет 60 seconds Применяется только для producer-ов со способом аутентификации kerberos. Интервал проверки того, сколько тестовых сообщений было отправлено за данный период. Если количество сообщений за этот период равно количеству сообщений за прошлый период, то начинается отсчет периода без сообщений.
INTEGRATION_KAFKA_CONNECTION_CHECK_FAILED_AFTER_INTERVAL duration string нет 5 minutes Применяется только для producer-ов со способом аутентификации kerberos. Максимальная продолжительность периода без успешно отправленных тестовых сообщений. По ее достижении сервис будет объявлен больным.
INTEGRATION_CONSUL_ADDR string нет "http://localhost:8500" Адрес Сonsul.
INTEGRATION_CONSUL_AUTH_USER string нет "" Название учетной записи Сonsul. Если название не указано, то настройки авторизации не будут применены.
INTEGRATION_CONSUL_AUTH_PASSWORD string нет "" Пароль учетной записи Сonsul.
INTEGRATION_TRACE_DURATION bool нет false Признак необходимости трассировки выполнения команд.
INTEGRATION_DISCOVERABLE_ID string нет "another_integration_instance" Id сервиса в ServiceDiscovery.
INTEGRATION_DISCOVERABLE_NAME string нет "integration" Имя сервиса в ServiceDiscovery.
INTEGRATION_DISCOVERABLE_HOST string нет "localhost" Хост, публикуемый в ServiceDiscovery.
INTEGRATION_DISCOVERABLE_PORT int нет 8192 Порт, публикуемый в ServiceDiscovery.
INTEGRATION_DISCOVERABLE_LIVETIME duration string нет 2 minutes Период после отправки health check, в течение которого ServiceDiscovery считает сервис живым.
INTEGRATION_DISCOVERABLE_HEALTHPASS duration string нет 1 minute Периодичность отправки health check в ServiceDiscovery.
INTEGRATION_AKKA_HTTP_CLIENT_MAXCON int нет 512 Максимальное число одновременных исходящих HTTP-соединений.
INTEGRATION_AKKA_HTTP_CLIENT_MAXREQ int нет 1024 Максимальное число одновременных исходящих HTTP-запросов.
INTEGRATION_AKKA_HTTP_SERVER_MAXCON int нет 1024 Максимальное число одновременных входящих HTTP-соединений.
INTEGRATION_AKKA_HTTP_PARSING_MAX_BYTES size string нет 50m Максимальный размер данных из http-запроса, который может быть принят и распаршен
INTEGRATION_AKKA_HTTP_PARSING_MAX_CHUNK_SIZE size string нет 10m Максимальный размер одной части http-запроса, который может быть принят и распаршен
INTEGRATION_AKKA_HTTP_SERVER_REQUEST_TIMEOUT duration string нет 2 minutes Таймаут запросов к сервису по умолчанию.
INTEGRATION_AKKA_HTTP_SERVER_IDLE_TIMEOUT duration string нет 3 minutes Таймаут, по истечению которого бездействующее соединение закрывается.
INTEGRATION_INTERNALCMD_ALLOW bool нет true Можно ли сервису отправлять внутрисистемные команды.
INTEGRATION_SENDERLIB_CONSIDER_ALL_COMMANDS_AS_INTERNAL boolean Нет false Флаг, определяющий будут ли все обращения в другие сервисы являться внутренними (т.е. не требовать авторизацию). Детальное описание механизма: Внутренние команды.
INTEGRATION_SENDERLIB_COMMANDS_CACHE_UPDATEPERIOD duration string нет 10 minutes Время кэширования данных по командам из CommandDiscovery.
INTEGRATION_SENDERLIB_SERVICES_CACHE_UPDATEPERIOD duration string нет 30 seconds Время кэширования данных по сервисам из ServiceDiscovery.
INTEGRATION_DB_URL string да Адрес базы данных. Можно использовать вместо DB_HOST, DB_PORT и DB_NAME.
INTEGRATION_DB_HOST string да Хост сервера базы данных.
INTEGRATION_DB_PORT int да Порт сервера базы данных.
INTEGRATION_DB_NAME string да Название базы данных.
INTEGRATION_DB_USER string да Пользователь базы данных.
INTEGRATION_DB_PASSWORD string да Пароль для пользователя базы данных.
INTEGRATION_DB_THREADS int нет 10 Количество потоков в пуле потоков для соединения с БД
INTEGRATION_DB_QUEUE_SIZE int нет 300 Размер очереди для действий базы данных, которые не могут быть выполнены немедленно, когда все потоки заняты. За пределами этого значения новые действия немедленно завершаются неудачей
INTEGRATION_DB_CONN_MAX int нет 10 Максимальное количество одновременных подключений к БД
INTEGRATION_DB_CONN_TIMEOUT duration string нет 20 second Максимальное время ожидания ответа для соединения к БД. Если это время превышено, а соединение не становится доступным, будет брошено исключение SQLException. 1000 мс — минимальное значение.
INTEGRATION_DB_ISOLATION string нет "READ_COMMITTED" Уровень изоляции транзакций для новых подключений. Допустимые значения: NONE, READ_COMMITTED, READ_UNCOMMITTED, REPEATABLE_READ, SERIALIZABLE.
INTEGRATION_DB_READONLY boolean нет false Read-only SQL транзакция может изменять только временные таблицы. Этот параметр управляет статусом «только для чтения» по умолчанию для каждой новой транзакции.
INTEGRATION_DB_CONN_MIN int нет = DB_THREADS Минимальное количество одновременных подключений к БД
INTEGRATION_DB_VALIDATION_TIMEOUT duration string нет 1 seconds Максимальное время, в течение которого соединение будет проверяться на работоспособность. 1000 мс — минимальное значение.
INTEGRATION_DB_IDLE_TIMEOUT duration string нет 10 minutes Максимальное время, в течение которого соединению разрешено простаивать в пуле. Значение 0 означает, что простаивающие соединения никогда не удаляются из пула.
INTEGRATION_DB_MAX_LIFETIME duration string нет 30 minutes Максимальное время жизни соединения в пуле. Когда простаивающее соединение достигает этого времени ожидания, даже если оно недавно использовалось, оно будет удалено из пула. Значение 0 указывает на отсутствие максимального срока службы.
INTEGRATION_DB_INITIALIZATION_FAIL_FAST string нет false Deprecated, начиная с версии Slick 3.3.0. Определяет, будет ли пул «быстро выходить из строя», если пул не может быть успешно заполнен начальными соединениями. Если соединения не могут быть созданы во время запуска пула, будет выдано исключение RuntimeException. Это свойство не имеет никакого эффекта, если minConnections равно 0.
INTEGRATION_DB_LEAK_DETECTION_THRESHOLD int нет 0 Время, в течение которого соединение может находиться вне пула, прежде чем будет зарегистрировано сообщение, указывающее на возможную утечку соединения. Значение 0 означает, что обнаружение утечек отключено. Наименьшее приемлемое значение для включения обнаружения утечек составляет 10 с.
INTEGRATION_DB_CONNECTION_TEST_QUERY string нет "SELECT 1" Выражение, которое будет выполнено непосредственно перед получением соединения из пула для проверки того, что соединение с базой данных все еще активно. Оно зависит от базы данных и должно представлять собой запрос, требующий минимальной обработки базой данных (например, «VALUES 1»). Если этот параметр не установлен, вместо него используется метод JDBC4 Connection.isValid().
INTEGRATION_DB_AUTO_COMMIT boolean нет true Это свойство определяет то, как будут вести себя по умолчанию возвращаемые соединения относительно autocommit-а.
INTEGRATION_DB_SCHEMA string нет "public" Устанавливает schema по умолчанию
INTEGRATION_DB_ISOLATE_INTERNAL_QUERIES boolean нет false Определяет то, изолируются ли с помощью транзакций внутренние запросы пула(например запрос connection alive test). Свойство применяется только если autoCommit выключен.
INTEGRATION_DB_INITIALIZATION_FAIL_TIMEOUT int нет 1 Работает, начиная с версии Slick 3.3.0. Определяет, будет ли пул «быстро выходить из строя», если пул не может быть успешно заполнен начальными соединениями. Любое положительное число считается числом миллисекунд для попытки получить начальное соединение;поток приложения будет заблокирован в течение этого периода. Если соединение не может быть получено до истечения этого времени,будет брошено исключение. Данный таймаут применяется после периода connectionTimeout. Если значение равно нулю (0),HikariCP попытается получить и проверить подключение. Если соединение получено,но проверка не пройдена, будет брошено исключение, и пул не будет запущен. Однако,если соединение не может быть получено, пул запустится,но последующие попытки получить соединение могут потерпеть неудачу.Значение меньше нуля пройдет любую первоначальную попытку подключения, и пул немедленно запустится,пытаясь получить соединения в фоновом режиме.Следовательно, последующие попытки получить соединение могут потерпеть неудачу.
INTEGRATION_DB_REGISTER_MBEANS boolean нет false Зарегистрированы ли JMX Management Beans («MBeans»)
INTEGRATION_PROCESSING_MULTIPLE_COMMAND_TIMEOUT duration string нет 1 minute Таймаут батч-команд (команд над несколькими объектами).
INTEGRATION_PROCESSING_MAX_TOTAL_ENTITIES_IN_PROCESS int нет 1000 Максимальный размер очереди выполняемых единичных команд (среди всех клиентов).
INTEGRATION_PROCESSING_COMMAND_PROCESSING_PARALLELISM int нет 32 Максимальное число одновременно выполняемых команд (среди всех клиентов).
INTEGRATION_FS_URI string нет http://localhost:9000 Адрес для подключения к Minio.
INTEGRATION_FS_ACCESS_KEY_ID string нет "minioadmin" Ключ доступа к хранилищу файлов Minio (aka пользователь).
INTEGRATION_FS_SECRET_ACCESS_KEY string нет "minioadmin" Секретный код доступа к хранилищу файлов Minio (aka пароль).
INTEGRATION_FS_UPLOAD_PARALLELISM int нет 4 Максимально возможный параллелизм при загрузке файлов в хранилище.
INTEGRATION_FS_AUTH_MODE string нет static Режим аутентификации: static - одна учетная запись на все запросы, mapping - учетная запись зависит от запроса
INTEGRATION_FS_AUTH_CONFIG string нет "" Настройки для аутентификации: если AuthMode = mapping, то необходим JSON с List[FSBucketConfig] соответствует полю authConfig FSConfigRep
INTEGRATION_FS_CACHE_SIZE int нет 1 Максимальный размер кеша клиентов для хранилища файлов (количество активных соединений).
INTEGRATION_FS_CACHE_TTL duration string нет Время жизни клиента в кеше
INTEGRATION_FS_RETRY_ATTEMPTS int нет 5 Количество ретраев, которое будет произведено в случае Exception-а в операции FSClient-а и при вычитывании стрима в get операциях FSClient-а.
INTEGRATION_FS_RETRY_DELAY duration string нет 10 millis Задержка между ретраями операций FSClient-а.
INTEGRATION_FS_SIZE_LIMIT_KB int нет 102400 Максимальный размер загружаемого файла в килобайтах.
INTEGRATION_FS_BUCKETS_TEMP string нет temp Временный бакет, куда сохраняются файлы для дальнейшей отправки в составе полей объекта.
INTEGRATION_FS_ZIO_SHORT_MESSAGE_MODE boolean нет false Флаг включения режима сохранения ошибок работы с файловым хранилищем в сервисе журналирования nestor. При включении режима ошибки в логах будут отображаться в сокращенном формате: Short zio message mode. ExceptionType: ТИП ОШИБКИ, Exception id: 'СГЕНЕРИРОВАННЫЙ UUID' added to journal. Указанный id будет фиксироваться в event записи nestor'а в поле data.id
INTEGRATION_ENTITY_TYPES_REFRESH_RATE duration string нет 5 minutes Периодичность обновления перечня доступных типов данных из модели данных.
INTEGRATION_SENDERLIB_COMMANDS_HTTP_RETRY_ATTEMPTS int нет 5 Поле attempts из RetrySettings
INTEGRATION_SENDERLIB_COMMANDS_HTTP_RETRY_DELAY duration string нет "5 seconds" Поле delay из RetrySettings
INTEGRATION_SENDERLIB_COMMANDS_HTTP_RETRY_KIND string нет "OnSomeExceptions(ConnectException)" CommandResultRetryConditionKind
INTEGRATION_SENDERLIB_CONSUL_CONNECTION_RETRY_MAX int нет 5 Количество попыток переподключения к Consul
INTEGRATION_SENDERLIB_CONSUL_CONNECTION_RETRY_DELAY duration string нет "1 second" Задержка при попытках переподключения к Consul
INTEGRATION_JOURNAL_MODE string нет WriteToJournal Режим журналирования Nestor. Допустимые значения: WriteToJournal (Отправка в сервис журналирования), WriteToTopic (Отправка события в очередь)
INTEGRATION_JOURNAL_TOPIC string да, если переменная INTEGRATION_JOURNAL_MODE = WriteToTopic "" Название очереди журналирования. Для режима WriteToJournal значение игнорируется.

Команды сервиса Integration

CreateClient (Integration)

На входе свойства регистрируемого клиента

{
  "id": "network-folder-papers",
  "title": "Сетевая папка - научные статьи",
  "allowFiles": true,
  "data": null
}

На выходе Boolean (признак успешности исполнения)

true

Регистрирует новый клиент.

Поддерживается асинхронный и синхронный вызов.
Результат выполнения команды не журналируется.

Команда Путь
integration_CreateClient Kafka Topic "integration_commands"

ListClients (Integration)

Входные данные отсутствуют

На выходе перечень зарегистрированных клиентов

[
  {
    "id": "network-folder-papers",
    "title": "Сетевая папка - научные статьи",
    "token": "mK8XoAb3GwICWZ4inj00Ax?lO_ZFRzshyTKQyH8j?COulcQFLnzcj6RczsSvBUYn",
    "allowFiles": true,
    "data": null,
    "blocked": false
  }
]

Возвращает полный перечень зарегистрированных клиентов.

Поддерживается только синхронный вызов.
Результат выполнения команды не журналируется.

Команда Путь
integration_ListClients HTTP POST /v1/client/list

UpdateClient (Integration)

На входе ID обновляемого клиента и новые свойства

{
  "id": "network-folder-papers",
  "title": "Сетевая папка (научные статьи)",
  "allowFiles": true,
  "data": null,
  "blocked": false
}

На выходе Boolean (признак успешности исполнения)

true

Обновляет данные клиента.

Поддерживается асинхронный и синхронный вызов.
Результат выполнения команды не журналируется.

Команда Путь
integration_UpdateClient Kafka Topic "integration_commands"

RefreshClientToken (Integration)

На входе ID клиента, для которого требуется перегенерировать токен

"network-folder-papers"

На выходе Boolean (признак успешности исполнения)

true

Повторно генерирует токен клиента.

Поддерживается асинхронный и синхронный вызов.
Результат выполнения команды не журналируется.

Команда Путь
integration_RefreshClientToken Kafka Topic "integration_commands"

AllowEntityType (Integration)

На входе ID клиента и ID типа данных, которые требуется связать

{
  "clientId": "network-folder-papers",
  "entityTypeId": "paper"
}

На выходе Boolean (признак успешности исполнения)

true

Дает указанному клиенту право создавать, редактировать и удалять данные указанного типа.

Поддерживается асинхронный и синхронный вызов.
Результат выполнения команды не журналируется.

Команда Путь
integration_AllowEntityType Kafka Topic "integration_commands"

DisallowEntityType (Integration)

На входе ID клиента и ID типа данных, для которых требуется удалить связь

{
  "clientId": "network-folder-papers",
  "entityTypeId": "paper"
}

На выходе Boolean (признак успешности исполнения)

true

Запрещает указанному клиенту создавать, редактировать и удалять данные указанного типа.

Поддерживается асинхронный и синхронный вызов.
Результат выполнения команды не журналируется.

Команда Путь
integration_DisallowEntityType Kafka Topic "integration_commands"

ListEntityTypes (Integration)

Входные данные отсутствуют

На выходе список доступных типов данных

[
  {
    "id": "paper",
    "title": "Бумага",
    "description": ""
  },
  {
    "id": "document",
    "title": "Документ",
    "description": ""
  }
]

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

Поддерживается только синхронный вызов.
Результат выполнения команды не журналируется.

Команда Путь
integration_ListEntityTypes HTTP POST /v1/entityType/list

RefreshEntityTypes (Integration)

Входные данные отсутствуют

На выходе Boolean (признак успешности исполнения)

true

Вызывает принудительное обновление списка доступных типов данных (обычно список обновляется по расписанию в указанные в INTEGRATION_ENTITY_TYPES_REFRESH_RATE промежутки времени).

Поддерживается асинхронный и синхронный вызов.
Результат выполнения команды не журналируется.

Команда Путь
integration_RefreshEntityTypes Kafka Topic "integration_commands"

ListEntityTypesForClient (Integration)

На входе ID клиента

"MarkerExternalClient"

На выходе список доступных типов данных для указанного клиента

[
  {
    "id": "DocForOwTkexzNTZeyY995aWgmAg",
    "title": "Документ для проекта с ID 3b04e47b-1ccd-4d97-b263-df7969682602",
    "description": ""
  },
  {
    "id": "DocForv0xczPbGTPiWaP_U8P1uBg",
    "title": "Документ для проекта с ID bf4c5ccc-f6c6-4cf8-9668-ffd4f0fd6e06",
    "description": ""
  }
]

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

Поддерживается только синхронный вызов.
Результат выполнения команды не журналируется.

Команда Путь
integration_ListEntityTypesForClient HTTP POST /v1/entityType/listForClient

Модели сервиса (Integration)

Client (Integration)

Описание зарегистрированного клиента

Поле Тип Обязательное Описание
id string Да Код клиента
title string Да Наименование клиента
token string Да Токен доступа для внешнего апи
allowFiles boolean Да Разрешено ли клиенту загружать файлы
data json Нет Дополнительные данные в свободном формате
blocked boolean Да Признак полной блокировки клиента

CreateClientDTO (Integration)

Поле Тип Обязательное Описание
id string Да Код клиента
title string Да Наименование клиента
allowFiles boolean Да Разрешено ли клиенту загружать файлы
data json Нет Дополнительные данные в свободном формате

UpdateClientDTO (Integration)

Поле Тип Обязательное Описание
id string Да Код клиента
title string Да Наименование клиента
allowFiles boolean Да Разрешено ли клиенту загружать файлы
data json Нет Дополнительные данные в свободном формате
blocked boolean Да Признак блокировки клиента

EntityType (Integration)

Описание известного типа данных

Поле Тип Обязательное Описание
id string Да Код типа данных
title string Да Название типа данных
description string Да Описание типа данных

ClientToEntityTypeIds (Integration)

Описание связи клиентов и типов данных для использования в командах

Поле Тип Обязательное Описание
clientId string Да Код клиента
entityTypeId string Да Код типа данных

Intelligent-plugin-core: хранилище общей логики плагинов

Intelligent Plugin Core это отдельный sbt-project, в который были вынесены логика и сущности, переиспользуемые отдельными плагинами.

Модели IntelligentPluginCore (models)

PluginConstantRegistrar (plugin)

Плагины регистрируются в сервисе TechConstants не как отдельные сервисы, а как константы, относящиеся к сервису Indexation. PluginConstantRegistrar содержит в себе логику, осуществляющую этот процесс регистрации плагинов в сервисе TechConstants.

BaseFlow (plugin)

Трейт, содержащий в себе API запуска обработки kafka-сообщений, поступающих плагину.

Трейт имеет две реализации: Flow и FlowLamp2, которые в процессе обработки обращаются к Lamp1 и Lamp2 соответственно.

Обе эти реализации выполняют следующие шаги обработки:

1. Плагин ожидает получать из топика consumerConfig.topic сообщения, содержащие json-представления модели StepProgress. Происходит конвертация этого json-а в инстанс StepProgress.

2. После этого для каждого идентификатора файла(progress.files), генерируется EntityFileSemanticId, включающий в себя привязку к конкретной сущности(progress.entityObject).

3. Затем плагин отправляет в Lamp запрос, содержащий сгенерированный EntityFileSemanticId, чтобы найти файлы, которые имеют пересечение с текущим.

4. LampResponseProcessor, определяемый в каждом плагине отдельно, преобразует ответ Lamp в список пар из EntityFileSemanticId и некоторой меры схожести файлов(measure). Мера определяет то, насколько файл, соответствующий полученному id, похож на файл соответствующий id, переданному в запросе. По полученному списку производится фильтрация - остаются идентификаторы только тех файлов, мера которых превышает linkConfig.measureThreshold. Так мы получаем все forwardLinks, которые нужно создать.

5. Если индексация, вызвавшая обращение к плагину, была порождена событием в data-model, то для каждого EntityFileSemanticId, возвращенного Lamp-ом на предыдущем шаге, выполняются действия шагов 3 и 4. Пересечения, найденные таким образом, называются backlinks.

6. Если при обращении к Lamp во время поиска backlinks на шаге 5, происходит ошибка, то после того, как количество ретраев превысит максимально возможное, то:

7. Множество (forwardLinks ++ backLinks) делится на батчи, которые отправляются в data-model во входных данных команды createObjectsLinks для создания соответствующей связи между объектами. В поле additional при этом сохраняется json-object {linkConfig.measureName -> measure}.

8. В топик consumerConfig.progressTopic отправляется либо StepProgress (тот же, что и поступил на вход), либо FailedStepProgress в качестве маркера об окончании обработки шага plugin для данного stepProgress.

  1. Происходит обращение к data-model, чтобы по EntityFileSemanticId файла сущности получить саму сущность для переиндексации.
  2. В топик consumerConfig.indexationEntityEventObjectTopic отправляется сообщение, содержащее TypedEvent[EntityObjectEvent] с PluginBackLinksAdditionalData, которое порождает искусственную индексацию файла сущности с шагами Lamp и Plugin. При этом обработка искусственного шага Plugin для такого файла исключает поиск собственных backlinks (чтобы не попасть в цикл).

TypedEvent[EntityObjectEvent] (plugin)

DTO для стандартных событий

Поле Тип Обязательное Описание Ограничения
eventType String Да Тип события (информация для более удобной фильтрации)
payloadType String Да Тип объекта, который передается
payloadId String Да Id объекта, который передается. Может содержать идентификатор объекта из сервиса, который отправляет события
payload EntityObjectEvent Да Передаваемый объект

LampResponseProcessor (plugin)

Содержит в себе один метод processResponse, который принимает на вход сообщение из Lamp и возвращает Option[Seq[LinkItem]]

LinkItem (plugin)

Поле Тип Обязательное Значение по умолчанию Описание Ограничения
id EntityFileSemanticId Да Нет Семантический идентификатор файла сущности
measure Float Да Нет Мера

ConsumerConfig (plugin)

Поле Тип Обязательное Значение по умолчанию Описание Ограничения
topic String Да Нет Топик, в который поступает StepProgress на обработку
group String Да Нет Группа консьюмера
progressTopic String Да Нет Топик, в который плагин пишет об окончании обработки

LinkConfig (plugin)

Поле Тип Обязательное Значение по умолчанию Описание Ограничения
lampParametersOperation String Да Нет Название операции, которое в качестве параметра передается в Lamp
lampRoute String Да Нет Рут Lamp, к которому обращается плагин с запросом поиска пересекающихся файлов
linkType String Да Нет Тип ссылки, создаваемой плагином в data-model
linkOwner String Да Нет Link owner ссылки, создаваемой плагином в data-model
measureName String Да Нет measureName, которое будет использовано в объекте, лежащем в поле additionalData при создании ссылки в data-model
measureThreshold Float Да Нет Пороговое значение measure. Ссылки создаются только между документами, мера схожести между которыми больше или равна этому значению
linkItemsPerKafkaMessage Int Да Нет Размер батча для запроса к data-model c командой createObjectsLinks

EntityFileSemanticId (plugin)

Поле Тип Обязательное Значение по умолчанию Описание Ограничения
entityType EntityTypeId Да Нет Тип сущности, к которой относится файл
entityId String Да Нет Идентификатор сущности, к которой относится файл
fieldId String Да Нет Идентификатор поля сущности, в котором хранится файл
fileId String Да Нет Идентификатор файла

FailedStepProgress (plugin)

Поле Тип Обязательное Значение по умолчанию Описание Ограничения
indexationProgress StepProgress Да Нет StepProgress, который завершился ошибкой
message String Да Нет Message ошибки, произошедшей во время обработки StepProgress
stackTrace String Нет Нет StackTrace ошибки, произошедшей во время обработки StepProgress

StepProgress (plugin)

В плагинах поле stepProgress.step всегда будет содержать Step c payload Plugin, то есть шаг сервиса индексации, который описывает обращение к плагину (тип stepPayload = Plugin). В остальном аналогично любому другому StepProgress.

JWT: библиотека для работы с JWT

Библиотека предоставляет вспомогательные методы для создания и работы с JWT.

TODO: описать JwtAuthenticatorPac4j, JwtPac4j, JwtClaim и как их использовать

Structs (jwt)

JwtInvalidationId (jwt)

Идентификатор для правила инвалидации JwtInvalidation. Может быть либо "global" - для всех пользователей, либо UserId - для конкретного пользователя.
Соответствует типу String.

JwtInvalidation (jwt)

Параметры для хранилища сертификатов (Java key store)

Поле Тип Обязательное Описание Ограничения
id JwtInvalidationId Да Идентификатор правила инвалидации JWT Либо "global" - для всех пользователей, либо UserId - для конкретного пользователя
condition string Да Правило инвалидации JWT Формат должен совпадать с JwtInvalidationCondition

JwtInvalidationCondition (jwt)

Формат правила для инвалидации

Lamp-client: cервис интеграции с LAMP

В сервисе реализованы следующие команды

Общее описание архитектуры сервиса клиента LAMP

Сервис позволяет общаться с LAMP через Verdi команду, ответы LAMP упаковываются в файлы, и в качестве результата выполнения команды создается ссылка на файл с ответом LAMP

Конфигурирование сервиса клиента LAMP

Требования к запуску сервиса клиента LAMP

Запуск сервиса осуществляется локально через sbt, на стенде в docker на jvm. Для корректной минимальной работы сервиса требуется обязательное подключение к Kafka, Consul, MinIO и Remote Lamp Client Для нормальной работы сервису дополнительно требуется окружение Verdi: CommandStatus и ApiGateway.

Список переменных окружения сервиса клиента LAMP

Переменная Тип Обязательная Значение по умолчанию Описание
CONSUMER_TOPIC string нет lampClient Название кафка-топика для запросов в LAMP
CONSUMER_GROUP string нет lampClient Имя группы-консьюмеров сервиса клиента LAMP
VERDI_CONSUL url string да http://localhost:8500 Адрес Consul
VERDI_CONSUL_AUTH_USER string нет "" Название учетной записи Сonsul. Если название не указано, то настройки авторизации не будут применены.
VERDI_CONSUL_AUTH_PASSWORD string нет "" Пароль учетной записи Сonsul.
VERDI_KAFKA_AUTH_PRINCIPAL string нет "" Principal учетной записи Kafka в Kerberos(в случае соединения с kafka через Kerberos).
VERDI_KAFKA_AUTH_KEYTAB_PATH string нет "" Путь до keytab-файла(в случае соединения с kafka через Kerberos).
VERDI_KAFKA_ADDRESS string да localhost:9092 Адрес брокера Kafka.
VERDI_KAFKA_TOPIC string нет commandevents Название кафка-топика для отправки сообщений со статусами выполняемых команд. ОБЯЗАТЕЛЬНО должно соответствовать названию этого топика в сервисе статуса команд.
VERDI_KAFKA_AUTH_USER string нет "" Название учетной записи Kafka. Если название не указано, то настройки авторизации не будут применены.
VERDI_KAFKA_AUTH_PASSWORD string нет "" Пароль учетной записи Kafka.
VERDI_KAFKA_AUTH_TRUSTSTORE_LOCATION string нет "" Путь до хранилища сертификатов (Java key store). Если путь не указан, то сертификат применяться не будет.
VERDI_KAFKA_AUTH_TRUSTSTORE_PASSWORD string нет "" Пароль к хранилищу сертификатов.
VERDI_KAFKA_AUTH_MODE string нет "" Режим аутентификации: static - одна учетная запись на все запросы, mapping - учетная запись зависит от запроса
VERDI_KAFKA_AUTH_CONFIG string нет "" Настройки для аутентификации: если AuthMode = mapping, то необходим JSON с List[KafkaAuthConfig]. Переменная соответствует полю authConfig из KafkaAuthSettings.
VERDI_KAFKA_AUTH_CACHE_SIZE int нет Максимальный размер кеша для Kafka producer (количество активных соединений).
VERDI_KAFKA_AUTH_CACHE_TTL duration string нет Время жизни Kafka producer в кеше.
VERDI_KAFKA_CONNECTION_CHECK_TEST_MESSAGES_INTERVAL duration string нет 4 minutes Применяется только для producer-ов со способом аутентификации kerberos. Интервал отправки тестовых сообщений кафки в топик connectionCheck.testMessagesTopicName. Тестовые сообщения (null, service producer test) отправляются регулярно с этим интервалом.
VERDI_KAFKA_CONNECTION_CHECK_INTERVAL duration string нет 60 seconds Применяется только для producer-ов со способом аутентификации kerberos. Интервал проверки того, сколько тестовых сообщений было отправлено за данный период. Если количество сообщений за этот период равно количеству сообщений за прошлый период, то начинается отсчет периода без сообщений.
VERDI_KAFKA_CONNECTION_CHECK_FAILED_AFTER_INTERVAL duration string нет 5 minutes Применяется только для producer-ов со способом аутентификации kerberos. Максимальная продолжительность периода без успешно отправленных тестовых сообщений. По ее достижении сервис будет объявлен больным.
VERDI_HOST string да localhost Хост, публикуемый в ServiceDiscovery. По нему на данный сервис будут обращаться другие через HTTP. Указанный адрес должен быть виден другим сервисам. Пример: имя kubernetes/docker_swarm service
VERDI_TTL duration string нет 30 seconds Период после последней отправки health check, в течение которого ServiceDiscovery считает данный сервис живым.
VERDI_HEALTH_CHECK duration string нет 10 seconds Периодичность отправки health check в ServiceDiscovery
VERDI_COMMAND_STORAGE_UPDATE_PERIOD duration string нет 1 minutes Время кэширования данных по командам из CommandDiscovery
VERDI_SERVICE_DISCOVERY_UPDATE_PERIOD duration string нет 30 seconds Время кэширования данных по сервисам из ServiceDiscovery
VERDI_ALLOW_INTERNAL_COMMANDS bool нет true Можно ли сервису отправлять внутрисистемные команды
VERDI_CONSUL_CONNECTION_MAX_RETRY int нет 5 Максимальное количество попыток подключений к Consul
VERDI_CONSUL_CONNECTION_RETRY_DELAY duration string нет 1 seconds Таймаут между неудачными попытками подключения к Consul
FS_URI url string да http://localhost:9002 Адрес S3 файлового хранилища minio
FS_ACCESS_KEY_ID string да admin Идентификатор доступа к minio
FS_SECRET_ACCESS_KEY string да admin Секретный ключ доступа к minio
FS_UPLOAD_PARALLELISM int нет 10 Параллелизм загрузки файлов в minio
FS_AUTH_MODE string нет static Режим аутентификации: static - одна учетная запись на все запросы, mapping - учетная запись зависит от запроса
FS_AUTH_CONFIG string нет "" Настройки для аутентификации: если AuthMode = mapping, то необходим JSON с List[FSBucketConfig] соответствует полю authConfig FSConfigRep
FS_CACHE_SIZE int нет 1 Максимальный размер кеша клиентов для хранилища файлов (количество активных соединений).
FS_CACHE_TTL duration string нет Время жизни клиента в кеше
FS_RETRY_ATTEMPTS int нет 5 Количество ретраев, которое будет произведено в случае Exception-а в операции FSClient-а и при вычитывании стрима в get операциях FSClient-а.
FS_RETRY_DELAY duration string нет 10 millis Задержка между ретраями операций FSClient-а.
FS_ZIO_SHORT_MESSAGE_MODE boolean нет false Флаг включения режима сохранения ошибок работы с файловым хранилищем в сервисе журналирования nestor. При включении режима ошибки в логах будут отображаться в сокращенном формате: Short zio message mode. ExceptionType: ТИП ОШИБКИ, Exception id: 'СГЕНЕРИРОВАННЫЙ UUID' added to journal. Указанный id будет фиксироваться в event записи nestor'а в поле data.id
LAMP_USE_VERSION_2 bool нет false Использовать ли LAMP2 (true) или LAMP1 (false)
LAMP_BUFFER_SIZE int нет 10 Буфер на отправку сообщений в клиент LAMP
LAMP_RECONNECT_SCHEDULE schedule string нет I(2 seconds) Стратегия переподключения клиента LAMP (формат см. lamp.transport.model.Schedule)
LAMP_HOST url string да lamp-dev.dev.embedika.ru Адрес клиента LAMP
LAMP_PORT int да 443 Порт клиента LAMP
LAMP_TLS bool да true Признак защищенного подключения к LAMP
LAMP_TLS_CERTIFICATE string нет "" Путь файла с сертификатом для подключения к LAMP
LAMP_TLS_PRIVATE_KEY string нет "" Путь файла с приватным ключем для подключения к LAMP
LAMP_TLS_ROOT_TRUSTED_CERTS string нет "" Путь файла с центром сертификации (Certification Authority, CA) для подключения к LAMP
LAMP_TIMEOUT duration string нет 150 second Таймаут отправки сообщения и получения результатов через клиент LAMP
APP_RESULT_BUCKET string нет processing S3 bucket в который сохраняются ответы LAMP
APP_ROUTE_MAPPING string нет Plagiarism:plagiarism_route;Similarity:faiss_route Маппинг сервисных имен LAMP роутов с реальными LAMP роутами. Формат indexation1:route1;indexation2:route2. Список роутов см. LampRoute
VERDI_COMMANDS_HTTP_RETRY_ATTEMPTS int нет 5 Поле attempts из RetrySettings
VERDI_COMMANDS_HTTP_RETRY_DELAY duration string нет "5 seconds" Поле delay из RetrySettings
VERDI_COMMANDS_HTTP_RETRY_KIND string нет "OnSomeExceptions(ConnectException)" CommandResultRetryConditionKind
SERVER_PORT int да 8080 Порт для HttpListener
JOURNAL_MODE string нет WriteToJournal Режим журналирования Nestor. Допустимые значения: WriteToJournal (Отправка в сервис журналирования), WriteToTopic (Отправка события в очередь)
JOURNAL_TOPIC string да, если переменная JOURNAL_MODE = WriteToTopic "" Название очереди журналирования. Для режима WriteToJournal значение игнорируется.

Модели сервиса клиента LAMP

LampQuery

Описание запроса к LAMP с файлами

Название поля Тип Описание
data Either[String, StoredFile] Данные запроса - это либо ссылка на файл, либо строка
route String LAMP роут
parameters Option[JsonObject] Опциональные параметры для запроса

LampQueryJson

Описание запроса к LAMP с json

Название поля Тип Описание
data String Строковые данные запроса
route String LAMP роут
parameters Option[JsonObject] Опциональные параметры для запроса

Имена сервисных LAMP роутов

Доступные на данный момент роуты: Plagiarism, Similarity, Extend

Команды сервиса клиента LAMP

lampQuery-command

Запрос в LAMP для больших данных

На входе ссылка на файл с данными и роут

{
  "data": "temp/8df98571-bb81-4ca6-8fef-0776ea18da50",
  "route": "Plagiarism"
}

В результате ссылка на файл с ответом от LAMP

"processing/8df98571-bb81-4ca6-8fef-0776ea18da50"

Поддерживается асинхронный и синхронный вызов.
Результат выполнения команды не журналируется.

lampQueryJson-command

Запрос в LAMP

На входе строковые данные, роут и параметры запроса в Lamp

{
  "data":"nacl",
  "route":"Extend",
  "parameters": {
    "k_nearest": "100",
    "pos_accept": "noun,adj,verb"
  }
}

В результате json с ответом от Lamp

{"synonyms":[{"lemma":"толуол","pos":"NOUN","weight":0.6470648050308228},{"lemma":"mgcl","pos":"NOUN","weight":0.6426058411598206}]}

Поддерживается асинхронный и синхронный вызов.
Результат выполнения команды не журналируется.

License-models: модели данных для работы с лицензией

Библиотека предоставляет вспомогательные методы для чтения файла лицензии и структуру с данными лицензии.

Модели данных (license-model)

LicenseDTO (license-model)

Пример лицензии, предоставляющей доступ к разделу "Лицензии".

kind=Prod
expiredAt:LONG=8050167349000
globalSessionsLimit:INT=-1
sessionsLimitPerUser:INT=-1
sessionWatchSec:INT=300
allowedActions=UIStorage_ViewList,ViewLicense
activeUserLimit:INT=-1
description=Лицензия для доступа к разделу "Лицензии" 

Данные выданной лицензии.

Поле Тип Обязательное Описание Значение по умолчанию
kind LicenseKind Нет Вид лицензии "Prod"
expiredAt TimeStamp Нет Время, когда лицензия истекает, в миллисекундах 0
globalSessionsLimit Int Нет Глобальное ограничение на количество сессий: меньше 0 = "без ограничений" -1
sessionsLimitPerUser Int Нет Ограничение на количество сессий для одного пользователя: меньше 0 = "без ограничений" -1
sessionWatchSec Int Нет Время в секундах, в течении которого сессия учитывается в подсчете доступного лимита: должно быть >= 0, ноль будет обрабатываться также как и любое другое значение 300
allowedActions String Нет Строка в формате: список действий (List[String]), которые разрешены для выполнения под лицензией (другие - автоматически запрещены) []
privilegedEmails String Нет Строка в формате: список email-ов привилегированных пользователей через запятую (List[UserEmail]) []
activeUserLimit Int Нет Глобальное ограничение на количество активированных пользователей: меньше 0 - "без ограничений" -1
jwtLifeTime Option[Int] Нет Время действия токена JWT в секундах (если есть, то перекрывает значение переменной MON_JWT_LIFETIME): должно быть >= 0, ноль будет обрабатываться также как и любое другое значение None
description Option[String] Нет Описание лицензии в свободном формате None

Примеры формата:

LicenseKind (license-model)

Вид лицензии. Соответствует типу String. Возможные значения: Prod, Dev.

Расширения liquibase plugin

PidLockDatabaseChangeLogGenerator

Расширение LockDatabaseChangeLogGenerator записывает допольнительные данные о pid сервиса в стоблец LOCKEDBY таблицы с liquibase lock.

Работает только с PostgreSQL, используется таблицу pg_stat_activity, и функцию pg_backend_pid().

ReleasingLockService

Расширение StandardLockService проверяет есть ли активное подключение к базе по pid из столбца LOCKEDBY, если нет, то снимает lock. Требует PidLockDatabaseChangeLogGenerator. Работает только с PostgreSQL, используется таблицу pg_stat_activity, и функцию pg_backend_pid().

Marsu: cервис для тестирования

Marsu, в переводе с финского, означает "морская свинка".

Сервис предназначен для тестирования работоспособности команд.
Команды могут приходить как по HTTP, так и через Kafka в топик marsu_commands.

Конфигурирование Marsu

Список переменных окружения для сервиса Marsu

Переменная Тип Обязательная Значение по умолчанию Описание
MARSU_HTTP_HOST string Нет 0.0.0.0 Хост для HttpListener.
MARSU_HTTP_PORT int Нет 8192 Порт для HttpListener.
MARSU_KAFKA_SERVERS string Нет localhost:9092 Адрес Kafka.
MARSU_KAFKA_TOPIC string Нет marsu_commands Название топика для команд.
MARSU_KAFKA_CONSUMER_GROUP string Нет marsu_consumer_group Название consumer-группы для чтения команд.
MARSU_KAFKA_COMMANDEVENT_TOPIC string Нет commandevents Название топика для отправки сообщений со статусом команд.
MARSU_KAFKA_PARTITIONS int Нет 10 Количество партиций в топике команд.
MARSU_KAFKA_CONSUMER_RESTART_MIN_BACKOFF duration string Нет 1 second Минимальная задержка перед перезапуском.
MARSU_KAFKA_CONSUMER_RESTART_MAX_BACKOFF duration string Нет 30 seconds Максимально возможная задержка перед перезапуском.
MARSU_KAFKA_CONSUMER_RESTART_RANDOM_FACTOR float Нет 0.2 Коэффициент величины дополнительной случайной задержки (jitter) относительно основной задержки: 0.0 - без случайной задержки, 1.0 - до 100% задержки. Если после умножения задержки на MARSU_KAFKA_CONSUMER_RESTART_RANDOM_FACTOR получится меньше 1 миллисекунды, то jitter будет приравнен к нулю.
MARSU_KAFKA_CONSUMER_RESTART_MAX_RESTARTS int Нет 5 Максимальное количество перезапусков в заданный период времени. После превышения этого числа сервис будет объявлен больным. Все рестарты для каждого отдельного сообщения увеличивают и общий счетчик рестартов консьюмера, поэтому при использовании MARSU_KAFKA_CONSUMER_PER_MESSAGE_RESTART_MAX_RESTARTS нужно указывать MARSU_KAFKA_CONSUMER_RESTART_MAX_RESTARTS > MARSU_KAFKA_CONSUMER_PER_MESSAGE_RESTART_MAX_RESTARTS или не указывать MARSU_KAFKA_CONSUMER_PER_MESSAGE_RESTART_MAX_RESTARTS совсем.
MARSU_KAFKA_CONSUMER_PER_MESSAGE_RESTART_MAX_RESTARTS int Нет 2 Максимальное количество раз, которое консьюмер перезапустится с неизменной очередью сообщений (в пределах MARSU_KAFKA_CONSUMER_RESTART_MAX_RESTARTS_WITHIN), прежде чем проигнорировать сообщение, на котором происходит ошибка (Указано количество рестартов, а не прочтений. Если MARSU_KAFKA_CONSUMER_RESTART_MAX_RESTARTS = 2, то ошибочное сообщение будет обработано 3 раза, после чего произойдет 3ий рестарт и оно будет проигнорировано). Если указать 0, то перезапуск произойдет, но сообщение будет обработано только в первый раз, когда произошла ошибка. Если указать значение меньше 0, то перезапуски все равно будут происходить, но игнорирование сообщений, вызывающих ошибку, будет отключено.
MARSU_KAFKA_CONSUMER_PER_MESSAGE_RESTART_CACHE_SIZE int Нет 100 Для каждого сообщения счетчик перепрочтений хранится в кэше. Максимальное количество значений в этом кэше.
MARSU_KAFKA_CONSUMER_PER_MESSAGE_RESTART_CACHE_TTL duration string Нет 5 minutes Для каждого сообщения счетчик перепрочтений хранится в кэше. Максимальное время жизни элемента в этом кэше. В случае отсутствия значения время жизни элемента не будет ограничено.
MARSU_KAFKA_CONSUMER_RESTART_MAX_RESTARTS_WITHIN duration string Нет 5 minutes Период времени для ограничения перезапусков.
MARSU_KAFKA_CONSUMER_POLL_TIMEOUT duration string нет 10 milliseconds timeout запроса poll для kafka consumer
MARSU_KAFKA_CONSUMER_POLL_INTERVAL duration string нет 50 milliseconds интервал между запросами poll для kafka consumer
MARSU_KAFKA_CONSUMER_PROPS string нет "max.poll.records=2500;max.partition.fetch.bytes=3145728" дополнительные параметры для kafka consumer в формате "key1=value1;key2=value2"
MARSU_KAFKA_PRODUCER_PROPS string нет "batch.size=3145728;linger.ms=5;max.request.size=3145728" дополнительные параметры для kafka producer в формате "key1=value1;key2=value2"
MARSU_KAFKA_CONSUMER_PARALLELISM int нет 10 параллелизм обработки сообщений в одной партиции
MARSU_KAFKA_AUTH_USER string Нет "" Название учетной записи Kafka. Если название не указано, то настройки авторизации не будут применены.
MARSU_KAFKA_AUTH_PASSWORD string Нет "" Пароль учетной записи Kafka.
MARSU_KAFKA_AUTH_PRINCIPAL string Нет "" Principal учетной записи Kafka в Kerberos(в случае соединения с kafka через Kerberos).
MARSU_KAFKA_AUTH_KEYTAB_PATH string Нет "" Путь до keytab-файла(в случае соединения с kafka через Kerberos).
MARSU_KAFKA_AUTH_TRUSTSTORE_LOCATION string Нет "" Путь до хранилища сертификатов (Java key store). Если путь не указан, то сертификат применяться не будет.
MARSU_KAFKA_AUTH_TRUSTSTORE_PASSWORD string Нет "" Пароль к хранилищу сертификатов.
MARSU_KAFKA_AUTH_MODE string Нет static Режим аутентификации: static - одна учетная запись на все запросы, mapping - учетная запись зависит от запроса.
MARSU_KAFKA_AUTH_CONFIG string Нет "" Настройки для аутентификации: если AuthMode = mapping, то необходим JSON с List[KafkaAuthConfig]. Переменная соответствует полю authConfig из KafkaAuthSettings.
MARSU_KAFKA_AUTH_CACHE_SIZE int Нет Максимальный размер кеша для Kafka producer (количество активных соединений).
MARSU_KAFKA_AUTH_CACHE_TTL duration string Нет Время жизни Kafka producer в кеше.
MARSU_KAFKA_CONNECTION_CHECK_TEST_MESSAGES_INTERVAL duration string Нет 4 minutes Применяется только для producer-ов со способом аутентификации kerberos. Интервал отправки тестовых сообщений кафки в топик connectionCheck.testMessagesTopicName. Тестовые сообщения (null, service producer test) отправляются регулярно с этим интервалом.
MARSU_KAFKA_CONNECTION_CHECK_INTERVAL duration string Нет 60 seconds Применяется только для producer-ов со способом аутентификации kerberos. Интервал проверки того, сколько тестовых сообщений было отправлено за данный период. Если количество сообщений за этот период равно количеству сообщений за прошлый период, то начинается отсчет периода без сообщений.
MARSU_KAFKA_CONNECTION_CHECK_FAILED_AFTER_INTERVAL duration string Нет 5 minutes Применяется только для producer-ов со способом аутентификации kerberos. Максимальная продолжительность периода без успешно отправленных тестовых сообщений. По ее достижении сервис будет объявлен больным.
MARSU_CONSUL_ADDR string Нет http://localhost:8500 Адрес Consul.
MARSU_DISCOVERABLE_ID string Нет marsu_instance Id сервиса в ServiceDiscovery.
MARSU_DISCOVERABLE_NAME string Нет Marsu Имя сервиса в ServiceDiscovery.
MARSU_DISCOVERABLE_HOST string Нет localhost Хост, публикуемый в ServiceDiscovery.
MARSU_DISCOVERABLE_PORT int Нет Порт, публикуемый в ServiceDiscovery.
MARSU_DISCOVERABLE_LIVETIME duration string Нет 2 minutes Период после отправки health check, в течение которого ServiceDiscovery считает сервис живым.
MARSU_DISCOVERABLE_HEALTHPASS duration string Нет 1 minute Периодичность отправки health check в ServiceDiscovery.
MARSU_AKKA_HTTP_CLIENT_MAXCON int Нет 512 Максимальное число одновременных исходящих HTTP-соединений.
MARSU_AKKA_HTTP_CLIENT_MAXREQ int Нет 1024 Максимальное число одновременных исходящих HTTP-запросов.
MARSU_AKKA_HTTP_SERVER_MAXCON int Нет 1024 Максимальное число одновременных входящих HTTP-соединений.
MARSU_INTERNALCMD_ALLOW bool Нет false Можно ли сервису отправлять внутрисистемные команды.
MARSU_SENDERLIB_COMMANDS_CACHE_UPDATEPERIOD duration string Нет 10 minutes Время кэширования данных по командам из CommandDiscovery.
MARSU_SENDERLIB_SERVICES_CACHE_UPDATEPERIOD duration string Нет 30 seconds Время кэширования данных по сервисам из ServiceDiscovery.
MARSU_SENDERLIB_COMMANDS_HTTP_RETRY_ATTEMPTS int Нет 5 Поле attempts из RetrySettings.
MARSU_SENDERLIB_COMMANDS_HTTP_RETRY_DELAY duration string Нет 5 seconds Поле delay из RetrySettings.
MARSU_SENDERLIB_COMMANDS_HTTP_RETRY_KIND string Нет OnSomeExceptions(ConnectException) CommandResultRetryConditionKind.

Команды сервиса Marsu

Список реализованных в сервисе команд.

Назначение команды Имя вызова команды
Отправка тестовой команды по HTTP marsu_http_Delayable
Отправка тестовой команды по KAFKA marsu_kafka_Delayable

http_Delayble (Marsu)

Получаем запрос о длительности выполнения команды

{
  "delayMs": 1000
}

Возвращаем полученный запрос

{
  "delayMs": 1000
}

Команда для проверки длительности выполнения команд. Команда ничего не делает, только ожидает указанное временя в мс.

Имя команды для вызова: marsu_http_Delayable.
Поддерживается только синхронный вызов.
Результат выполнения команды не журналируется.

kafka_Delayble (Marsu)

Получаем запрос о длительности выполнения команды

{
  "delayMs": 1000
}

Возвращаем полученный запрос

{
  "delayMs": 1000
}

Команда для проверки длительности выполнения команд. Команда ничего не делает, только ожидает указанное временя в мс.

Имя команды для вызова: marsu_kafka_Delayable.
Поддерживается асинхронный и синхронный вызов.
Результат выполнения команды не журналируется.

Модели сервиса Marsu

DelayableCommand (Marsu)

Модель для настроек задержек команд

Поле Тип Обязательное Описание
delayMs long Да Длительность выполнения команды в мс

Mon-client: библиотека для работы с сервисом Mon

Библиотека предоставляет интерфейс и реализацию клиента для сервиса Mon.

Публикуется вместе с подпроектом mon-core/domain, так как использует сущности из этого подпроекта.

Подключение (mon-client)

Для того чтобы использовать библиотеку mon-client, нужно добавить зависимость "com.embedika.mon" %% "mon-client" % verdiVersion

Регистрация в distage

make[MonClient[IO]].from { (dispatcher: Dispatcher, ec: ExecutionContext @Id("ec-services")) =>
  implicit val executionContext: ExecutionContext = ec
  implicit val ff: FromFuture[IO] = FromFuture.make[IO](ec)
  MonClient.make[IO](dispatcher)
}

В distage клиент можно зарегистрировать следующим способом:

Предоставляемые методы

Mon-client предоставляет методы вызова соответствующих команд сервиса Mon. Формат входных и выходных данных методов Mon-client аналогичен формату входных и выходных данных команд сервиса Mon.

Метод mon-client Вызываемая команда mon
registerUser Регистрация нового пользователя
verifyUserRegistration Подтверждение регистрации пользователя
login Вход пользователя в систему (Логин-пароль)
kerberosLogin Вход пользователя в систему (Kerberos)
getKeycloakAuthUrl Генерация ссылки на форму входа Keycloak
keycloakLogin Вход пользователя в систему (Keycloak)
logout Выход пользователя из системы
changeStatus Изменение статуса пользователя
updateInfo Изменение данных пользователя
changePassword Изменение пароля пользователя
recoverPassword Запрос восстановления пароля пользователя
listUsers Список всех пользователей
listUsersInternal Список всех пользователей(внутренняя)
myData Данные текущего пользователя
requestContextDataJwt Данные пользователя для контекста команды по JWT
requestContextDataHandlerAccessToken Данные пользователя для контекста команды по OAuth access token
createGroup Создать группу пользователей
getGroup Получить группу пользователей по ID
updateGroup Отредактировать группу пользователей
deleteGroup Удалить группу пользователей
listGroups Список всех групп пользователей
listGroupsByUserId Список групп в которых состоит пользователь
listUsersByGroup Список пользователей которые состоят в группе
addUsersToGroup Добавить пользователей в группу
removeUsersFromGroup Удалить пользователей из группы
closeAllUserSessions Завершить все сессии (выданные JWT) для 1 пользователя
deleteJwtInvalidation Удалить правило инвалидации JWT
updateDeactivationTime Изменение срока действия аккаунта
getLicenseInfo Получение текущей лицензии
listUsersWithGroupsCount Список пользователей с количеством групп
listUsersWithGroups Список пользователей с информацией о группах
listUserIdsByGroupId Получить список пользователей по списку идентификаторов групп(внутренняя)
listGroupsByUserIds Получить список групп по списку идентификаторов пользователей
checkToken Проверить токен пользователя
recoverPasswordByToken Восстановить пароль по токену

Mon-core: базовая библиотека сервисов аутентификации

В библиотеку вынесен шаблон структуры и кода для сервисов аутентификации и реализации по умолчанию.

Сервис разбит на несколько модулей, в виде sbt проектов:

Публикуются эти проекты как одна библиотека mon-core.

Подключение (mon-core)

Для того чтобы использовать библиотеку mon-core, нужно добавить зависимость "com.embedika.mon" %% "mon-core" % verdiVersion

Liquibase (mon-core)

Реализация mon, поставляемая в данной библиотеке, предполагает наличие определенных таблиц в базе данных, которая указана в application.conf по пути database.db.url. Эти таблицы mon-core создает с помощью com.embedika.verdi.persistence.migration.LiquibasePlugin. Для корректной работы плагина в сервисе, созданном на основе mon-core, по пути boot/src/main/resources/liquibase должен лежать файл changelog.xml, иначе при запуске упадет исключение liquibase.exception.ChangeLogParseException: The file liquibase/changelog.xml was not found. Для корректной работы всех команд в сервисе, созданном на основе mon-core, предоставленный файл changelog.xml должен включать в себя все stages, находящиеся в mon-core по пути /testkit/src/main/resources/liquibase/stages. При необходимости после указанных stages можно добавить в changelog.xml свои кастомные stages.

Пример содержимого файла changelog.xml.

<?xml version="1.0" encoding="UTF-8"?>
<databaseChangeLog
        xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog
         http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.6.xsd">

    <include file="stages/init.xml" relativeToChangelogFile="true"/>
    <include file="stages/groups.xml" relativeToChangelogFile="true"/>
    <include file="stages/2023.xml" relativeToChangelogFile="true"/>
    <include file="stages/2024.xml" relativeToChangelogFile="true"/>

    <include file="stages/MyCustomStage.xml" relativeToChangelogFile="true"/>

</databaseChangeLog>

Модули (mon-core)

Для инициализации сервиса mon используются модули izumi-distage.

В каждом модуле описывается создание сущностей, необходимых для работы сервиса.

Модуль можно определить двумя способами

object MyModule extends ModuleDef {}

case class MyModule[F[_] : TagK] extends ModuleDef {}

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

make[MyTrait].from(MyImpl)

Если же класс используется напрямую, то указывать его соответствие трейту нет необходимости. Но указать необходимость его создания нужно и сделать это можно так.

make[MyImpl]

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

//создание named-соответствия
make[Config]
  .named("db-config")
  .from { rootConfig: RootConfig =>
    rootConfig.database
  }

//другое named-соответствие
make[Config]
  .named("senderlib-config")
  .from { rootConfig: RootConfig =>
    rootConfig.senderlib
  }

//использование named-соответствия
make[ProfileComponent].from { config: Config @Id("db-config") =>
  ProfileComponent.postgresProfileComponent(config)
}

Если при инициализации хочется создать Set значений, то можно воспользоваться директивой many.

например
many[TechConstant]
  .addSet(Set(myConstant1, myConstant2))
  .add(myConstant3)

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

object OldModule extends ModuleDef {
  many[TechConstant]
    .addSet(Set(myConstant1, myConstant2))
    .add(myConstant3)
}

object NewModule extends ModuleDef {
  include(OldModule)

  many[TechConstant]
    .add(myConstant4)
}

Однако, если вы хотите убрать значение из предопределенного Set, нужно использовать overriddenBy с новым соответствием many и с новым набором значений.

В boot/src/main/modules хранятся некоторые уже описанные заранее определения модулей izumi-distage для создания сервисов mon. Для того чтобы расширить существующий модуль, то есть добавить в него НОВОЕ соответствие реализации трейту или новый класс, который мы используем напрямую, нужно создать новый расширенный модуль и включить в него старый.

object MyOldModule extends ModuleDef {
  make[MyOldTrait].from(MyOldImpl)
}

object MyNewModule extends ModuleDef {
  inlude(MyOldModule)

  make[MyNewTrait].from(MyNewImpl)
}

Для того чтобы переопределить соответствие реализации трейту в модуле, но использовать все остальное, нужно переопределить модуль.

object MyOldModule extends ModuleDef {
  make[MyOldTrait].from(MyOldImpl)
}

object MyNewModule extends ModuleDef {
  make[MyOldTrait].from(MyNewImpl)
}

object OverriddenModule extends ModuleDef {
  include(MyOldModule overriddenBy MyNewModule)
}

MainAppModule (mon-core)

Точкой входа в программу является модуль MainAppModule, который содержит весь функционал сервиса mon и требует всех обязательных значений application.conf.

Запустить MainAppModule можно двумя способами:

object Main extends IOApp {
  override def run(args: List[String]): IO[ExitCode] =
    MainAppModule
      .resource[IO]
      .use(_.run())
      .as(ExitCode.Success)
}

object Main extends IOApp {
  override def run(args: List[String]): IO[ExitCode] =
    MainAppModule
      .resourceWithModule[IO](MainAppModule[IO]())
      .use(_.run())
      .as(ExitCode.Success)
}

Для тех, кому нет необходимости использовать полную версию Mon, существует модуль BaseMainAppModule, который реализует только базовую инициализацию сервиса Mon.

Запустить BaseMainAppModule можно так:

Этот модуль парсит урезанную версию конфига, не содержит в себе функционал связанный с

Кроме того, эта версия mon не публикует технические константы для команд и не отвечает ни на какие команды. Http-сервер этой версии mon принимает только GET запрос /health.

Для некоторых из этих функций в BaseMainApp совсем не определены модули, а для некоторых из них определены модули-заглушки (dummy-модули) и соответствия-заглушки (dummy-соответствия). Кроме того в BaseAppModule определен эффект LiquidBase-плагина, создающий Unit.

Модули, содержащиеся в BaseMainApp:

Соответствия, содержащиеся в BaseMainApp напрямую, без модулей:

Dummy-соответствия, содержащиеся в BaseMainApp напрямую, без модулей:

Классы без соответствий, содержащиеся в BaseMainApp напрямую, без модулей:

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

Замечание: Это пример, а не готовый вариант запуска, так как UserApiModule требует хэндлеры команд.

case class UserHttpApiModule[F[_] : TagK]() extends ModuleDef {
  include(BaseHttpApiModule[F])
  include(UserApiModule[F]())
}

case class MainAppModule[F[_] : TagK : Timer]()(implicit ce: ConcurrentEffect[F], cs: ContextShift[F]) extends ModuleDef {
  include(
    BaseMainAppModule[F]()
      overriddenBy UserHttpApiModule[F]()
  )
}

Замечание: При наличии соответствия (даже dummy-соответствия) одновременно в BaseMainAppModule и
нельзя сделать просто:

include(BaseMainAppModule[F]())
make[MyTrait].from(MyImpl)

Нужно делать

object NyModule extends ModuleDef {
  make[MyTrait].from(MyImpl)
}

include(BaseMainAppModule[F]() overriddenBy MyModule)

Базовые модули (mon-core)

Существуют также базовые модули

Скорее всего их также нужно будет переопределить и расширить в соответствии со своими нуждами во время использования библиотеки.

Ознакомиться с тем, какие модули и соответствия они содержат внутри себя можно в файлах scala

Пример минимального конфига, необходимого для запуска BaseMainAppModule (mon-core)

app {
  http {
    host = "0.0.0.0"
    host = ${?MON_HTTP_HOST}
    port = 8192
    port = ${?MON_HTTP_PORT}
  }

  kafka {
    servers = "localhost:9092"
    servers = ${?MON_KAFKA_SERVERS}

    commandEvent {
      topic = "commandevents"
      topic = ${?MON_KAFKA_COMMANDEVENT_TOPIC}
    }

    connectionCheck {
      testMessagesTopicName = ${app.kafka.commandEvent.topic}
      testMessagesSendInterval = 4 minutes
      testMessagesSendInterval = ${?MON_KAFKA_CONNECTION_CHECK_TEST_MESSAGES_INTERVAL}
      checkInterval = 60 seconds
      checkInterval = ${?MON_KAFKA_CONNECTION_CHECK_INTERVAL}
      checkFailedAfterInterval = 5 minutes
      checkFailedAfterInterval = ${?MON_KAFKA_CONNECTION_CHECK_FAILED_AFTER_INTERVAL}
    }

    userEvent {
      topic = "userEvents"
      topic = ${?MON_KAFKA_USEREVENT_TOPIC}
    }

    auth {
      staticAuth {
        passwordBased {
          user = ""
          user = ${?MON_KAFKA_AUTH_USER}

          password = ""
          password = ${?MON_KAFKA_AUTH_PASSWORD}
        }

        kerberosBased {
          principal = ""
          principal = ${?MON_KAFKA_AUTH_PRINCIPAL}

          keytabPath = ""
          keytabPath = ${?MON_KAFKA_AUTH_KEYTAB_PATH}
        }

        truststore {
          location = ""
          location = ${?MON_KAFKA_AUTH_TRUSTSTORE_LOCATION}

          password = ""
          password = ${?MON_KAFKA_AUTH_TRUSTSTORE_PASSWORD}
        }
      }

      authMode = "static"
      authMode = ${?MON_KAFKA_AUTH_MODE}

      authConfig = ""
      authConfig = ${?MON_KAFKA_AUTH_CONFIG}

      clientsCache {
        maxSize = ${?MON_KAFKA_AUTH_CACHE_SIZE}
        elementTTL = ${?MON_KAFKA_AUTH_CACHE_TTL}
      }
    }
  }

  consul {
    address = "http://localhost:8500"
    address = ${?MON_CONSUL_ADDR}

    auth {
      user = ""
      user = ${?MON_CONSUL_AUTH_USER}

      password = ""
      password = ${?MON_CONSUL_AUTH_PASSWORD}
    }
  }

  defaultUserGroups = ""
  defaultUserGroups = ${?MON_USERGROUP_DEFAULT}

  authentication {
    jwt {
      signatureSecret = ""
      signatureSecret = ${?MON_JWT_SIGNATURE}
      lifetime = 12 hours
      lifetime = ${?MON_JWT_LIFETIME}
      cookieExpireOffset = 24 hours
      cookieExpireOffset = ${?MON_JWT_COOKIE_EXPIRE_OFFSET}
    }
  }
}

discoverableService {
  id = "another_mon_instance"
  id = ${?MON_DISCOVERABLE_ID}
  name = "mon"
  name = ${?MON_DISCOVERABLE_NAME}
  host = "localhost"
  host = ${?MON_DISCOVERABLE_HOST}
  port = ${app.http.port}
  port = ${?MON_DISCOVERABLE_PORT}
  livetime = 2 minutes
  livetime = ${?MON_DISCOVERABLE_LIVETIME}
  healthPassPeriod = 1 minute
  healthPassPeriod = ${?MON_DISCOVERABLE_HEALTHPASS}
}

serviceInfo {
  name = ${discoverableService.name}
  readableName = "Сервис пользователей"
  readableName = ${?MON_READABLE_NAME}
  description = "Предназначен для определения схемы и хранения объектов"
  description = ${?MON_DESCRIPTION}
}

akka {
  http {
    host-connection-pool {
      max-connections = 512
      max-connections = ${?MON_AKKA_HTTP_CLIENT_MAXCON}
      max-open-requests = 1024
      max-open-requests = ${?MON_AKKA_HTTP_CLIENT_MAXREQ}
    }

    server {
      max-connections = 1024
      max-connections = ${?MON_AKKA_HTTP_SERVER_MAXCON}
    }
  }
}

senderlib {
  allowInternalCommands = true
  allowInternalCommands = ${?MON_INTERNALCMD_ALLOW}

  cache {
    commandStorage {
      updatePeriod = 10 minutes
      updatePeriod = ${?MON_SENDERLIB_COMMANDS_CACHE_UPDATEPERIOD}
    }

    serviceDiscovery {
      updatePeriod = 30 seconds
      updatePeriod = ${?MON_SENDERLIB_SERVICES_CACHE_UPDATEPERIOD}
    }
  }

  commands {
    http {
      retry {
        attempts = 5
        attempts = ${?MON_SENDERLIB_COMMANDS_HTTP_RETRY_ATTEMPTS}
        delay = 5 seconds
        delay = ${?MON_SENDERLIB_COMMANDS_HTTP_RETRY_DELAY}
        kind = "OnSomeExceptions(ConnectException)"
        kind = ${?MON_SENDERLIB_COMMANDS_HTTP_RETRY_KIND}
      }
    }
  }
}

database {
  profile = "com.embedika.verdi.persistence.profile.VerdiPostgresProfile$"
  db {
    driver = "org.postgresql.Driver"
    url = "jdbc:postgresql://"${?MON_DB_HOST}":"${?MON_DB_PORT}"/"${?MON_DB_NAME}
    url = ${?MON_DB_URL}
    user = ${?MON_DB_USER}
    password = ${?MON_DB_PASSWORD}
    numThreads = 10
    numThreads = ${?MON_DB_THREADS}
    queueSize = 300
    queueSize = ${?MON_DB_QUEUE_SIZE}
    maxConnections = 10
    maxConnections = ${?MON_DB_CONN_MAX}
    connectionTimeout = 20 second
    connectionTimeout = ${?MON_DB_CONN_TIMEOUT}
    isolation = "READ_COMMITTED"
    isolation = ${?MON_DB_ISOLATION}
    readOnly = false
    readOnly = ${?MON_DB_READONLY}
    minConnections = ${database.db.numThreads}
    minConnections = ${?MON_DB_CONN_MIN}
    validationTimeout = 1 seconds
    validationTimeout = ${?MON_DB_VALIDATION_TIMEOUT}
    idleTimeout = 10 minutes
    idleTimeout = ${?MON_DB_IDLE_TIMEOUT}
    maxLifetime = 30 minutes
    maxLifetime = ${?MON_DB_MAX_LIFETIME}
    #Deprecated in slick 3.3.0
    initializationFailFast = false
    initializationFailFast = ${?MON_DB_INITIALIZATION_FAIL_FAST}
    leakDetectionThreshold = 0
    leakDetectionThreshold = ${?MON_DB_LEAK_DETECTION_THRESHOLD}
    connectionTestQuery = "SELECT 1"
    connectionTestQuery = ${?MON_DB_CONNECTION_TEST_QUERY}
    registerMbeans = false
    registerMbeans = ${?MON_DB_REGISTER_MBEANS}
    autoCommit = true
    autoCommit = ${?MON_DB_AUTO_COMMIT}
    schema = "public"
    schema = ${?MON_DB_SCHEMA}
    isolateInternalQueries = false
    isolateInternalQueries = ${?MON_DB_ISOLATE_INTERNAL_QUERIES}
    initializationFailTimeout = 1
    initializationFailTimeout = ${?MON_DB_INITIALIZATION_FAIL_TIMEOUT}
  }
}

liquibase = ${database.db}
# Default changelog file name in the root of classpath
liquibase.changelog = "liquibase/changelog.xml"
# Allows disabling liquibase migration
liquibase.enable = true

include "custom.conf"

Особенности Kerberos authentication (mon-core)

После добавления Kerberos authentication, сервис стал зависеть от пакета com.sun.security.auth.module, которого нет, например, в IBM JRE. Поэтому рекомендуется использовать OpenJDK или Oracle.

Дополнительно: "the browser URL must match the fully-qualified-domain-name as specified in ServicePrincipal".

Список команд библиотеки Mon-core (commands list)

Список реализованных в сервисе команд, моделей EntityType и действий Actions, которые можно использовать при настройке авторизации.
Не все поля EntityType доступны для использования в настройке авторизации.
Если указан прочерк "-", то данное значение не влияет на авторизацию:

Назначение команды Имя вызова команды EntityType Actions
Регистрация нового пользователя mon_http_RegisterUser - -
Подтверждение регистрации пользователя mon_http_VerifyUserRegistration - -
Вход пользователя в систему (Логин-пароль) mon_http_LoginByCredentials - -
Вход пользователя в систему (Kerberos) mon_http_LoginByKerberos - -
Генерация ссылки на форму входа Keycloak mon_http_GetKeycloakAuthUrl - -
Вход пользователя в систему (Keycloak) mon_http_LoginByKeycloak - -
Выход пользователя из системы mon_http_Logout - -
Изменение статуса пользователя mon_http_ChangeUserStatus User ChangeUserStatus
Изменение данных пользователя mon_http_UpdateUserInfo User UpdateUserInfo
Изменение пароля пользователя mon_http_ChangeUserPassword User ChangeUserPassword
Изменение срока действия аккаунта mon_http_UpdateDeactivationTime User UpdateDeactivationTime
Запрос восстановления пароля пользователя] mon_http_PasswordRecoverRequest - -
Проверить токен пользователя mon_http_CheckToken - -
Восстановить пароль по токену mon_http_RecoverPasswordByToken - -
Список всех пользователей mon_http_ListUsers User ReadUsers
Список всех пользователей(внутренняя) mon_http_ListUsersInternal - -
Список пользователей которые состоят в группе mon_http_ListUsersByGroupId User ReadUsers
Получение текущей лицензии mon_http_ListUsersWithGroupsCount User ReadUsers
Список пользователей с информацией о группах mon_http_ListUsersWithGroups User ListUsersWithGroups
Данные текущего пользователя mon_http_MyData - -
Данные пользователя для контекста команды по JWT mon_http_UserCommandContextData - -
Данные пользователя для контекста команды по OAuth access token mon_http_UserCommandContextData_OauthAccessToken - -
Завершить все сессии (выданные JWT) для 1 пользователя mon_http_CloseAllUserSessions User InvalidateSession
Удалить правило инвалидации JWT mon_http_DeleteJwtInvalidation User InvalidateSession
Создать группу пользователей mon_http_CreateGroup Group CreateGroup
Получить группу пользователей по ID mon_http_GetGroup Group ReadGroup
Отредактировать группу пользователей mon_http_UpdateGroup Group UpdateGroup
Удалить группу пользователей mon_http_DeleteGroup Group DeleteGroup
Список всех групп пользователей mon_http_ListGroups Group ReadGroups
Список групп в которых состоит пользователь mon_http_ListGroupsByUserId Group ReadGroups
Получить список групп по списку идентификаторов пользователей mon_http_ListGroupsByUserIds Group ReadGroups
Добавить пользователей в группу mon_http_AddUsersToGroup Group ManageUsers
Удалить пользователей из группы mon_http_RemoveUsersFromGroup Group ManageUsers
Получение текущей лицензии mon_http_GetLicenseInfo - ViewLicense
Получить список идентификаторов пользователей по списку идентификаторов групп(внутренняя) mon_http_ListUserIdsByGroupIds - -
Выгрузить список пользователей согласно шаблону mon_http_ExportUsers User ExportUsers

RegisterUser (mon-core)

Payload для команды

{
  "email": "emailname@mail.io",
  "password": "strongpassword",
  "info": {
    "firstName": "John",
    "lastName": "Week",
    "middleName": "Jovonovich",
    "data": {
      "myField": {
        "myInnerField": "value"
      }
    }
  },
  "notificationUrl": "http://localhost:8080/verify-user?token=[[token]]"
}

Результат выполнения команды

{
  "userId": "a133f0c8-a516-4537-8f3f-915acb335e2c",
  "verificationRequested": true
}

Добавляет нового пользователя. Статус зависит от настроек сервиса. Если включена проверка email, то отправляется письмо для проверки email, а статус пользователя назначается в Pending. Если проверка email выключена, то статус пользователя назначается в Activated. Уникальность пользователя определяется по полю Email. Отправляет событие о регистрации нового пользователя.

Имя вызова команды:mon_http_RegisterUser.
Поддерживается только синхронный вызов.
Результат выполнения команды журналируется.

VerifyUserRegistration (mon-core)

Payload для команды

"e5cdd1e3-84ef-4d85-98d4-b56bac91093d"

Результат выполнения команды

"user has been verified"

Подтверждает регистрацию нового пользователя и изменяет его статус "Pending" => "Activated". Отправляет событие о подтверждении нового пользователя.

Имя вызова команды:mon_http_VerifyUserRegistration.
Поддерживается только синхронный вызов.
Результат выполнения команды журналируется.

LoginByCredentials (mon-core)

Payload для команды

{
  "email": "emailname@mail.io",
  "password": "strongpassword"
}

Результат выполнения команды (Header ответа)

Set-Cookie: jwt_token=eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJTb21lKDRiZTgxOGFlLTUwNTMtNDM2Zi1hZTEzLWE3NDY5MDgwMDhkYykiLCJleHAiOjE2MjkzMDIyMzUsInVzZXJJZCI6IjRiZTgxOGFlLTUwNTMtNDM2Zi1hZTEzLWE3NDY5MDgwMDhkYyJ9.XxPMZUtIez9pG2zfwrIxBofQN5b2dQ2p3Q4XPPCLB-E; Expires=Wed, 18 Aug 2021 15:57:15 GMT; Path=/; HttpOnly

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

Имя вызова команды:mon_http_LoginByCredentials.
Поддерживается только синхронный вызов.
Результат выполнения команды журналируется.

LoginByKerberos (mon-core)

Payload для команды (Header запроса, base64)

Authorization: Negotiate YIIB1wYJKoZIhvcSAQICAQBuggHGMIIBwqADAgEFoQMCAQ6iBwMFAAAAAACjge5hgeswge

Результат выполнения команды (Header ответа, base64)

WWW-Authenticate: Negotiate ???, где ??? может быть или токен в base64 или пустая строка (т.е. значение Header будет просто "Negotiate")

Set-Cookie: jwt_token=eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJTb21lKDRiZTgxOGFlLTUwNTMtNDM2Zi1hZTEzLWE3NDY5MDgwMDhkYykiLCJleHAiOjE2MjkzMDIyMzUsInVzZXJJZCI6IjRiZTgxOGFlLTUwNTMtNDM2Zi1hZTEzLWE3NDY5MDgwMDhkYyJ9.XxPMZUtIez9pG2zfwrIxBofQN5b2dQ2p3Q4XPPCLB-E; Expires=Wed, 18 Aug 2021 15:57:15 GMT; Path=/; HttpOnly

Осуществляет вход пользователя в систему на основе профиля пользователя из Active Directory. Если пользователь с указанным профилем не зарегистрирован, то происходит процесс регистрации БЕЗ верификации (статус пользователя будет сразу Activated).

Имя вызова команды:mon_http_LoginByKerberos.
Поддерживается только синхронный вызов.
Результат выполнения команды журналируется.

GetKeycloakAuthUrl (mon-core)

Результат выполнения команды (тело ответа) (URL на форму входа)

"http://keycloak.url/realms/verdi/protocol/openid-connect/auth?scope=openid+profile+email&response_type=code&redirect_uri=http%3A%2F%2Fverdi.dev%2Fkeycloak-callback"

Результат выполнения команды (Header ответа)

Set-Cookie: external_session_id=802bf1d6-366c-420e-9196-5645ce9953bb; Max-Age=600; Path=/; HttpOnly

Генерирует и возвращает ссылку на форму входа в Keycloak, а также устанавливает коротко живущую Cookie, необходимую для последующей аутентификации в Keycloak.

Имя вызова команды:mon_http_GetKeycloakAuthUrl.
Поддерживается только синхронный вызов.
Результат выполнения команды не журналируется.

LoginByKeycloak (mon-core)

Payload для команды

{
  "queryParameters": {
    "client_name": "KeycloakOidcClient",
    "session_state": "914b01b8-19ca-42f4-af11-96fa49da0caa",
    "code": "b164638b-05a8-413d-aa86-1442a7f10252.35216f68-c210-447e-ade4-d0a7035254d6.0974025f-9aa6-4daf-b755-80ba35c64576",
    "state": "ce901f20522"
  }
}

Результат выполнения команды (Header ответа)

Set-Cookie: jwt_token=eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJTb21lKDRiZTgxOGFlLTUwNTMtNDM2Zi1hZTEzLWE3NDY5MDgwMDhkYykiLCJleHAiOjE2MjkzMDIyMzUsInVzZXJJZCI6IjRiZTgxOGFlLTUwNTMtNDM2Zi1hZTEzLWE3NDY5MDgwMDhkYyJ9.XxPMZUtIez9pG2zfwrIxBofQN5b2dQ2p3Q4XPPCLB-E; Expires=Wed, 18 Aug 2021 15:57:15 GMT; Path=/; HttpOnly

Осуществляет вход пользователя в систему на основе профиля в Keycloak. Если пользователь с указанным профилем не зарегистрирован, то происходит процесс регистрации БЕЗ верификации (статус пользователя будет сразу Activated).

Имя вызова команды:mon_http_LoginByKeycloak.
Поддерживается только синхронный вызов.
Результат выполнения команды журналируется.

Logout (mon-core)

Результат выполнения команды (Header ответа)

Set-Cookie:jwt_token=deleted; Expires=Thu, 01 Jan 1970 00:00:00 GMT; Path=/; HttpOnly

Осуществляет выход текущего пользователя из системы.

Имя вызова команды:mon_http_Logout.
Поддерживается только синхронный вызов.
Результат выполнения команды журналируется.

ChangeUserStatus (mon-core)

Payload для команды

{
  "userId": "a133f0c8-a516-4537-8f3f-915acb335e2c",
  "status": "Deactivated"
}

Результат выполнения команды

{
  "id": "a133f0c8-a516-4537-8f3f-915acb335e2c",
  "email": "emailname@mail.io",
  "status": "Deactivated",
  "info": {
    "firstName": "John",
    "lastName": "Week",
    "middleName": "Jovonovich",
    "data": {}
  },
  "modified": 1715940083060,
  "modifiedBy": "00000000-0000-0000-0000-000000000000",
  "reason": null,
  "deactivateAt": 1715940083770
}

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

Имя вызова команды:mon_http_ChangeUserStatus.
Поддерживается только синхронный вызов.
Результат выполнения команды журналируется.

UpdateUserInfo (mon-core)

Payload для команды

{
  "id": "9a67afa9-1a21-4a6d-9e97-334e9d95a7f2",
  "info": {
    "firstName": "newFirstName",
    "lastName": "newLastName",
    "middleName": "newMiddleName",
    "data": {
      "myField": {
        "myInnerField": "value"
      }
    }
  }
}

Результат выполнения команды

{
  "id": "9a67afa9-1a21-4a6d-9e97-334e9d95a7f2",
  "email": "email3name@mail.io",
  "status": "Pending",
  "info": {
    "firstName": "newFirstName",
    "lastName": "newLastName",
    "middleName": "newMiddleName",
    "data": {
      "myField": {
        "myInnerField": "value"
      },
      "myOldField": "oldValue"
    }
  },
  "modified": 1715940083060,
  "modifiedBy": "00000000-0000-0000-0000-000000000000",
  "reason": null,
  "deactivateAt": 1715940083770
}

Обновляет данные пользователя относительно тех, которые указаны во входных данных. При этом поля firstName, lastName, middleName перезаписываются на новые значения (если соответствующее поле присутствует во входных данных), а в поле data производится merge: при наличии поля в json оно перезаписывается на новое значение, а при отсутствии добавляется. Старые поля json внутри data, которых не было во входящем json, не меняются.

Имя вызова команды:mon_http_UpdateUserInfo.
Поддерживается только синхронный вызов.
Результат выполнения команды журналируется.

UpdateDeactivationTime (mon-core)

Payload для команды

{
  "userIds": [
    "9a67afa9-1a21-4a6d-9e97-334e9d95a7f2",
    "d81f3bb4-46bc-475f-af21-3277989e1371"
  ],
  "newDeactivateAt": 1715940083060,
  "reason": "Изменение срока деактивации"
}

Результат выполнения команды

{
  "updated": 2
}

Изменяет на переданное время деактивации(или удаляет при отсутствии поля newDeactivateAt) время деактивации аккаунта всех пользователей, id которых входит в переданный список. При выполнении этой команды также обновятся значения полей modified, modifiedBy и reason на текущий timestamp, id пользователя, который вызывал команду, и переданный в команду reason соответственно.

Имя вызова команды:mon_http_UpdateDeactivationTime.
Поддерживается только синхронный вызов.
Результат выполнения команды не журналируется.

ChangeUserPassword (mon-core)

Payload для команды

{
  "oldPassword": "pass123",
  "newPassword": "new_Pa$$w0rd"
}

Результат выполнения команды (признак успешности исполнения)

true

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

Имя вызова команды:mon_http_ChangeUserPassword.
Поддерживается только синхронный вызов.
Результат выполнения команды журналируется.

PasswordRecoverRequest (mon-core)

Payload для команды

{
  "email": "emailname@mail.io",
  "notificationUrl": "http://localhost:8080/change-password?token=[[token]]"
}

Сгенерировать для пользователя токен c типом "ChangePassword"

Шаблон формируемой ссылки находится в переменной MON_PASSWORD_RECOVERY_URL

Имя вызова команды:mon_http_PasswordRecoverRequest.
Поддерживается только синхронный вызов.
Результат выполнения команды не журналируется.

CheckToken (mon-core)

Payload для команды

{
  "actionTokenId": "b133f0c8-a516-4537-8f3f-915acb335e2b"
}

Результат выполнения команды

"token is valid"

Проверить статус токена восстановления пароля

Имя вызова команды:mon_http_CheckToken.
Поддерживается только синхронный вызов.
Результат выполнения команды не журналируется.

RecoverPasswordByToken (mon-core)

Payload для команды

{
  "token": "e5cdd1e3-84ef-4d85-98d4-b56bac91093d",
  "newPassword": "new_Pa$$w0rd"
}

Результат выполнения команды

"password has been changed"

Команда используется для установки нового пароля, который пользователь введет на форме восстановления

Имя вызова команды:mon_http_RecoverPasswordByToken.
Поддерживается только синхронный вызов.
Результат выполнения команды журналируется.

ListUsers (mon-core)

Payload для команды

{
  "sorting": {
    "fieldName": "lastname",
    "order": "asc"
  },
  "paging": {
    "page": 1,
    "count": 20
  },
  "query": "firstname",
  "context": {
    "firstname": "John"
  }
}

Результат выполнения команды

{
  "total": 1,
  "items": [
    {
      "id": "a133f0c8-a516-4537-8f3f-915acb335e2c",
      "email": "emailname@mail.io",
      "status": "Activated",
      "info": {
        "firstName": "John",
        "lastName": "Week",
        "middleName": "Jovonovich",
        "data": {}
      },
      "modified": 1715940083060,
      "modifiedBy": "00000000-0000-0000-0000-000000000000",
      "reason": null,
      "deactivateAt": 1715940083770
    }
  ]
}

Возвращает список всех существующих пользователей.

Имя вызова команды:mon_http_ListUsers.
Поддерживается только синхронный вызов.
Результат выполнения команды не журналируется.

По умолчанию сортировка производится по полю email модели User.

Запрос принимает параметры сортировки, фильтров и пейджинга в параметре Search.

Применяется к полям моделей User и UserInfo.

Доступные поля для фильтрации и виды фильтров по ним:

Поле Виды фильтров Комментарии
userId InSetQuery
status InSetQuery
email InSetQuery, LikeQuery
modified InSetQuery, RangeQuery
lastName InSetQuery, LikeQuery
firstName InSetQuery, LikeQuery
middleName InSetQuery, LikeQuery
fio TsQuery Поле содержит конкатенацию нескольких полей модели UserInfo: lastName + " " + firstName + " " + middleName.
data LikeQuery

Доступные поля для сортировки:

Поле
userId
status
email
lastName
firstName
middleName
modified

ListUsersInternal (mon-core)

Payload для команды

[
  "45682a6e-fb74-4ea9-b344-f24b2d3afd0a",
  "3c94e169-f9b3-4c50-b497-21ee544d6fae"
]

Результат выполнения команды

[
  {
    "userId": "45682a6e-fb74-4ea9-b344-f24b2d3afd0a",
    "email": "email5name@mail.io"
  },
  {
    "userId": "3c94e169-f9b3-4c50-b497-21ee544d6fae",
    "email": "email6name@mail.io"
  }
]

Возвращает список userId и соответствующих им email, где userId - это id пользователей, переданные во входящем списке.

Имя вызова команды:mon_http_ListUsersInternal.
Поддерживается только синхронный вызов.
Результат выполнения команды не журналируется.

Команда только внутренняя (нельзя вызвать через Api Gateway), не требует аутентификации.

ListUsersByGroupId (mon-core)

Payload для команды

{
  "groupId": "id_of_my_first_group",
  "options": {
    "sorting": {
      "fieldName": "name",
      "order": "asc"
    },
    "paging": {
      "page": 1,
      "count": 20
    },
    "query": "status",
    "context": {
      "status": "Activated"
    }
  }
}

Результат выполнения команды

{
  "total": 2,
  "items": [
    {
      "user": {
        "id": "a133f0c8-a516-4537-8f3f-915acb335e2c",
        "email": "emailname@mail.io",
        "status": "Activated",
        "info": {
          "firstName": "John",
          "lastName": "Week",
          "middleName": "Jovonovich",
          "data": {}
        },
        "modified": 1715940083060,
        "modifiedBy": "00000000-0000-0000-0000-000000000000",
        "reason": null,
        "deactivateAt": 1715940083770
      },
      "groupsCount": 1
    },
    {
      "user": {
        "id": "2595becc-e4a2-4507-88bf-e0114ab6d677",
        "email": "abc@gmail.ru",
        "status": "Activated",
        "info": {
          "firstName": "Ivan",
          "lastName": "Petrov",
          "middleName": "Vasilyevich",
          "data": {}
        },
        "modified": 1715940083060,
        "modifiedBy": "00000000-0000-0000-0000-000000000000",
        "reason": null,
        "deactivateAt": 1715940083770
      },
      "groupsCount": 10
    }
  ]
}

Возвращает список всех пользователей, которые состоят в указанной группе.

Имя вызова команды:mon_http_ListUsersByGroupId.
Поддерживается только синхронный вызов.
Результат выполнения команды не журналируется.

По умолчанию сортировка производится по полю email модели User.

Запрос принимает параметры сортировки, фильтров и пейджинга в параметре Search в поле options входных данных.

Применяется к полям моделей User и UserInfo, а также отдельно к полям:

Доступные поля для фильтрации и виды фильтров по ним:

Поле Виды фильтров Комментарии
userId InSetQuery
status InSetQuery
email InSetQuery, LikeQuery
modified InSetQuery, RangeQuery
lastName InSetQuery, LikeQuery
firstName InSetQuery, LikeQuery
middleName InSetQuery, LikeQuery
fio TsQuery Поле содержит конкатенацию нескольких полей модели UserInfo: lastName + " " + firstName + " " + middleName.
data LikeQuery
count InSetQuery, LikeQuery, RangeQuery
groupId InSetQuery, AllInSetQuery

Доступные поля для сортировки:

Поле
userId
status
email
lastName
firstName
middleName
count

ListUsersWithGroupsCount (mon-core)

Payload для команды

{
  "sorting": {
    "fieldName": "name",
    "order": "asc"
  },
  "paging": {
    "page": 1,
    "count": 20
  },
  "query": "status",
  "context": {
    "status": "Activated"
  }
}

Результат выполнения команды

{
  "total": 2,
  "items": [
    {
      "user": {
        "id": "a133f0c8-a516-4537-8f3f-915acb335e2c",
        "email": "emailname@mail.io",
        "status": "Activated",
        "info": {
          "firstName": "John",
          "lastName": "Week",
          "middleName": "Jovonovich",
          "data": {}
        },
        "modified": 1715940083060,
        "modifiedBy": "00000000-0000-0000-0000-000000000000",
        "reason": null,
        "deactivateAt": 1715940083770
      },
      "groupsCount": 1
    },
    {
      "user": {
        "id": "2595becc-e4a2-4507-88bf-e0114ab6d677",
        "email": "abc@gmail.ru",
        "status": "Activated",
        "info": {
          "firstName": "Ivan",
          "lastName": "Petrov",
          "middleName": "Vasilyevich",
          "data": {}
        },
        "modified": 1715940083060,
        "modifiedBy": "00000000-0000-0000-0000-000000000000",
        "reason": null,
        "deactivateAt": 1715940083770
      },
      "groupsCount": 10
    }
  ]
}

Возвращает список всех пользователей и кол-во групп, в которых они состоят.

Имя вызова команды:mon_http_ListUsersWithGroupsCount.
Поддерживается только синхронный вызов.
Результат выполнения команды не журналируется.

По умолчанию сортировка производится по полю email модели User.

Запрос принимает параметры сортировки, фильтров и пейджинга в параметре Search.

Применяется к полям моделей User и UserInfo, а также отдельно к полям:

Доступные поля для фильтрации и виды фильтров по ним:

Поле Виды фильтров Комментарии
userId InSetQuery
status InSetQuery
email InSetQuery, LikeQuery
modified InSetQuery, RangeQuery
lastName InSetQuery, LikeQuery
firstName InSetQuery, LikeQuery
middleName InSetQuery, LikeQuery
fio TsQuery Поле содержит конкатенацию нескольких полей модели UserInfo: lastName + " " + firstName + " " + middleName.
data LikeQuery
count InSetQuery, LikeQuery, RangeQuery
groupId InSetQuery, AllInSetQuery

Доступные поля для сортировки:

Поле
userId
status
email
lastName
firstName
middleName
count

ListUsersWithGroups (mon-core)

Payload для команды

{
  "sorting": {
    "fieldName": "name",
    "order": "asc"
  },
  "paging": {
    "page": 1,
    "count": 20
  },
  "query": "status",
  "context": {
    "status": "Activated"
  }
}

Результат выполнения команды

{
  "total": 2,
  "items": [
    {
      "user": {
        "id": "a133f0c8-a516-4537-8f3f-915acb335e2c",
        "email": "emailname@mail.io",
        "status": "Activated",
        "info": {
          "firstName": "John",
          "lastName": "Week",
          "middleName": "Jovonovich",
          "data": {}
        },
        "modified": 1715940083060,
        "modifiedBy": "00000000-0000-0000-0000-000000000000",
        "reason": null,
        "deactivateAt": 1715940083770
      },
      "groups": [
        {
          "groupId": "id_of_my_first_group",
          "title": "моя первая группа"
        }
      ]
    },
    {
      "user": {
        "id": "2595becc-e4a2-4507-88bf-e0114ab6d677",
        "email": "abc@gmail.ru",
        "status": "Activated",
        "info": {
          "firstName": "Ivan",
          "lastName": "Petrov",
          "middleName": "Vasilyevich",
          "data": {}
        },
        "modified": 1715940083060,
        "modifiedBy": "00000000-0000-0000-0000-000000000000",
        "reason": null,
        "deactivateAt": 1715940083770
      },
      "groups": [
        {
          "groupId": "id_of_my_first_group",
          "title": "моя первая группа"
        },
        {
          "groupId": "id_of_my_second_group",
          "title": "моя вторая группа"
        }
      ]
    }
  ]
}

Возвращает список всех пользователей и id и title групп, в которых они состоят.

Имя вызова команды:mon_http_ListUsersWithGroups.
Поддерживается только синхронный вызов.
Результат выполнения команды не журналируется.

По умолчанию сортировка производится по полю email модели User.

Запрос принимает параметры сортировки, фильтров и пейджинга в параметре Search.

Применяется к полям моделей User и UserInfo, а также отдельно к полям:

Доступные поля для фильтрации и виды фильтров по ним:

Поле Виды фильтров Комментарии
userId InSetQuery
status InSetQuery
email InSetQuery, LikeQuery
modified InSetQuery, RangeQuery
lastName InSetQuery, LikeQuery
firstName InSetQuery, LikeQuery
middleName InSetQuery, LikeQuery
fio TsQuery Поле содержит конкатенацию нескольких полей модели UserInfo: lastName + " " + firstName + " " + middleName.
data LikeQuery
count InSetQuery, LikeQuery, RangeQuery
groupId InSetQuery, AllInSetQuery

Доступные поля для сортировки:

Поле
userId
status
email
lastName
firstName
middleName
count

ExportUsers (mon-core)

Payload для команды

{
  "sorting": {
    "fieldName": "name",
    "order": "asc"
  },
  "query": "status",
  "context": {
    "status": "Activated"
  }
}

Результат выполнения команды

"temp/478eec63-4b8e-4cd2-9514-ae91b712b82a"

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

Имя вызова команды:mon_http_ExportUsers.
Поддерживается только синхронный вызов.
Результат выполнения команды не журналируется.

Доступные поля для фильтрации и сортировки совпадают с ListUsersWithGroups.

MyData (mon-core)

Результат выполнения команды

{
  "id": "a133f0c8-a516-4537-8f3f-915acb335e2c",
  "email": "emailname@mail.io",
  "status": "Activated",
  "info": {
    "firstName": "John",
    "lastName": "Week",
    "middleName": "Jovonovich",
    "data": {}
  },
  "modified": 1715940083060,
  "modifiedBy": "00000000-0000-0000-0000-000000000000",
  "reason": null,
  "deactivateAt": 1715940083770
}

Возвращает данные пользователя согласно указанному JWT.

Имя вызова команды:mon_http_MyData.
Поддерживается только синхронный вызов.
Результат выполнения команды не журналируется.

UserCommandContextData (mon-core)

Результат выполнения команды

{
  "userContext": {
    "id": "a133f0c8-a516-4537-8f3f-915acb335e2c",
    "emailOpt": "emailname@mail.io",
    "groupIds": [
      "first_group_id",
      "second_group_id",
      "third_group_id"
    ],
    "passwordExpirationDateOpt": 1715940083770
  },
  "userStatus": "Activated",
  "jwtInvalidation": [
    {
      "id": "d07c0cbc-93ee-4d5c-b9af-21b1aaf92a40",
      "condition": "1700545830"
    }
  ]
}

Возвращает основную информацию о пользователе, которая необходима при выполнении команд пользователем, согласно указанному JWT.
Данная команда используется в ApiGateway при создании контекста запроса входящих команд (context в CommandRequest).

Имя вызова команды:mon_http_UserCommandContextData.
Поддерживается только синхронный вызов.
Результат выполнения команды не журналируется.

UserCommandContextData_OauthAccessToken (mon-core)

Payload для команды

Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJ3ZnB4U3puQmw0UXRJNW83d2FZZFNWQzNRTm10NzEzUlB3bktMRzJDZk1nIn0.eyJleHAiOjE3MTkyOTMwOD...

Результат выполнения команды

{
  "userContext": {
    "id": "a133f0c8-a516-4537-8f3f-915acb335e2c",
    "emailOpt": "emailname@mail.io",
    "groupIds": [
      "first_group_id",
      "second_group_id",
      "third_group_id"
    ],
    "passwordExpirationDateOpt": null
  },
  "userStatus": "Activated",
  "jwtInvalidation": []
}

Возвращает информацию о пользователе по переданному AccessToken (из HTTP Header "Authorization") для контекста запроса команды CommandRequest.
В результате команды, поле "passwordExpirationDateOpt" из UserContext всегда будет пустым, т.к. исходные данные о пользователе хранятся во внешней системе.

Имя вызова команды:mon_http_UserCommandContextData_OauthAccessToken.
Поддерживается только синхронный вызов.
Результат выполнения команды не журналируется.

CloseAllUserSessions (mon-core)

Payload для команды

"a133f0c8-a516-4537-8f3f-915acb335e2c"

Результат выполнения команды (признак успешности исполнения)

true

Завершает все активные сессии выбранного пользователя. Завершение заключается в добавлении правила для инвалидации JWT с UserId.

Имя вызова команды:mon_http_CloseAllUserSessions.
Поддерживается только синхронный вызов.
Результат выполнения команды журналируется.

DeleteJwtInvalidation (mon-core)

Payload для команды

"a133f0c8-a516-4537-8f3f-915acb335e2c"

Результат выполнения команды (количество удаленных записей)

1

Удаляет из БД правило для инвалидации JWT с указанным идентификатором.

Имя вызова команды:mon_http_DeleteJwtInvalidation.
Поддерживается только синхронный вызов.
Результат выполнения команды журналируется.

CreateGroup (mon-core)

Payload для команды

{
  "id": "id_of_my_first_group",
  "name": "Название группы на руском языке",
  "description": "Описание группы"
}

Результат выполнения команды

{
  "id": "id_of_my_first_group",
  "name": "Название группы на руском языке",
  "modified": 1631707774,
  "description": "Описание группы"
}

Добавляет новую группу пользователей с заданными параметрами. Отправляет событие о создании группы.

Имя вызова команды:mon_http_CreateGroup.
Поддерживается только синхронный вызов.
Результат выполнения команды журналируется.

GetGroup (mon-core)

Payload для команды

"id_of_my_first_group"

Результат выполнения команды

{
  "id": "id_of_my_first_group",
  "name": "Название группы на руском языке",
  "modified": 1631707774,
  "description": "Описание группы"
}

Поиск группы пользователей с заданным идентифкатором.

Имя вызова команды:mon_http_GetGroup.
Поддерживается только синхронный вызов.
Результат выполнения команды не журналируется.

UpdateGroup (mon-core)

Payload для команды

{
  "id": "id_of_my_first_group",
  "name": "Новое название группы на каком-то языке",
  "description": "Измененное описание группы"
}

Результат выполнения команды

{
  "id": "id_of_my_first_group",
  "name": "Новое название группы на каком-то языке",
  "modified": 1631707774,
  "description": "Измененное описание группы"
}

Обновляет данные о группе пользователей. Отправляет событие об обновлении группы.

Имя вызова команды:mon_http_UpdateGroup.
Поддерживается только синхронный вызов.
Результат выполнения команды журналируется.

DeleteGroup (mon-core)

Payload для команды

"id_of_my_first_group"

Результат выполнения команды (признак успешности исполнения)

true

Удаляет группу пользователей с заданным идентифкатором. Отправляет событие об удалении группы.

Имя вызова команды:mon_http_DeleteGroup.
Поддерживается только синхронный вызов.
Результат выполнения команды журналируется.

ListGroups (mon-core)

Payload для команды

{
  "sorting": {
    "fieldName": "name",
    "order": "asc"
  },
  "paging": {
    "page": 1,
    "count": 20
  },
  "query": "modified",
  "context": {
    "modified": "1631707774"
  }
}

Результат выполнения команды

{
  "total": 2,
  "items": [
    {
      "group": {
        "id": "id_of_my_first_group",
        "name": "Новое название группы на каком-то языке",
        "modified": 1631707774,
        "description": "Измененное описание группы"
      },
      "usersCount": 2
    },
    {
      "group": {
        "id": "anotherGroup",
        "name": "Название группы",
        "modified": 1631707774,
        "description": null
      },
      "usersCount": 0
    }
  ]
}

Возвращает список всех групп пользователей.

Имя вызова команды:mon_http_ListGroups.
Поддерживается только синхронный вызов.
Результат выполнения команды не журналируется.

По умолчанию сортировка производится по полю modified модели GroupDTO.

Запрос принимает параметры сортировки, фильтров и пейджинга в параметре Search.

Применяется к полям модели GroupDTO.

Доступные поля для фильтрации и виды фильтров по ним:

Поле Виды фильтров
groupId InSetQuery, LikeQuery
name InSetQuery, LikeQuery
description InSetQuery, LikeQuery
modified InSetQuery, LikeQuery, RangeQuery

Применяется отдельно к полям:

Поле Виды фильтров
count InSetQuery, LikeQuery, RangeQuery

Доступные поля для сортировки:

Поле
groupId
name
description
modified
count

ListGroupsByUserId (mon-core)

Payload для команды

{
  "userId": "a133f0c8-a516-4537-8f3f-915acb335e2c",
  "options": {
    "sorting": {
      "fieldName": "name",
      "order": "asc"
    },
    "paging": {
      "page": 1,
      "count": 20
    },
    "query": "",
    "context": {}
  }
}

Результат выполнения команды

{
  "total": 1,
  "items": [
    {
      "group": {
        "id": "id_of_my_first_group",
        "name": "Новое название группы на каком-то языке",
        "modified": 1631707774,
        "description": "Измененное описание группы"
      },
      "usersCount": 2
    }
  ]
}

Возвращает список всех групп пользователей, в которых состоит указанный пользователь.

Имя вызова команды:mon_http_ListGroupsByUserId.
Поддерживается только синхронный вызов.
Результат выполнения команды не журналируется.

По умолчанию сортировка производится по полю modified модели GroupDTO.

Запрос принимает параметры сортировки, фильтров и пейджинга в параметре Search в поле options входных данных.

Применяется к полям модели GroupDTO.

Доступные поля для фильтрации и виды фильтров по ним:

Поле Виды фильтров
groupId InSetQuery, LikeQuery
name InSetQuery, LikeQuery
description InSetQuery, LikeQuery
modified InSetQuery, LikeQuery, RangeQuery

Применяется отдельно к полям:

Поле Виды фильтров
count InSetQuery, LikeQuery, RangeQuery

Доступные поля для сортировки:

Поле
groupId
name
description
modified
count

ListGroupsByUserIds (mon-core)

Payload для команды

[
  "9e04e443-9478-4f19-be0f-cac81aa17c7d",
  "7d21f4e6-1031-42f9-8610-d07d6b15f976",
  "7d21f4e6-1031-42f9-8610-d07d6b15f977"
]

Результат выполнения команды

[
  {
    "user": "9e04e443-9478-4f19-be0f-cac81aa17c7d",
    "groups": [
      {
        "id": "users",
        "name": "Пользователи",
        "modified": 1675845168767,
        "description": "Все пользователи системы"
      }
    ]
  },
  {
    "user": "7d21f4e6-1031-42f9-8610-d07d6b15f976",
    "groups": []
  },
  {
    "user": "7d21f4e6-1031-42f9-8610-d07d6b15f977",
    "groups": [
      {
        "id": "users",
        "name": "Пользователи",
        "modified": 1675845168767,
        "description": "Все пользователи системы"
      },
      {
        "id": "admins",
        "name": "Администраторы",
        "modified": 1674741697650,
        "description": null
      }
    ]
  }
]

Возвращает массив объектов, каждый из которых содержит id пользователя и массив всех групп, в которых состоит пользователь.

Команда не следит за существованием переданных id пользователей. Т.е. если передать во входных данных несуществующий id, то объект с таким id (с пустым списком групп) вернется в ответе

Имя вызова команды:mon_http_ListGroupsByUserIds.
Поддерживается только синхронный вызов.
Результат выполнения команды не журналируется.

ListUserIdsByGroupIds (mon-core)

Payload для команды

[
  "groupId1",
  "groupId2"
]

Результат выполнения команды

{
  "groupId1": [
    "userId1",
    "userId2"
  ],
  "groupId2": [
    "userId3"
  ]
}

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

Имя вызова команды:mon_http_ListUserIdsByGroupIds.
Поддерживается только синхронный вызов.
Результат выполнения команды не журналируется.

Команда только внутренняя (нельзя вызвать через Api Gateway), не требует аутентификации.

AddUsersToGroup (mon-core)

Payload для команды

{
  "groupIds": [
    "id_of_my_first_group"
  ],
  "users": [
    "a133f0c8-a516-4537-8f3f-915acb335e2c",
    "2595becc-e4a2-4507-88bf-e0114ab6d677"
  ]
}

Результат выполнения команды (признак успешности исполнения)

true

Добавляет новых пользователей в существующую группу. Отправляет событие о добавлении пользователей в группу.

Имя вызова команды:mon_http_AddUsersToGroup.
Поддерживается только синхронный вызов.
Результат выполнения команды журналируется.

RemoveUsersFromGroup (mon-core)

Payload для команды

{
  "groupIds": [
    "id_of_my_first_group"
  ],
  "users": [
    "a133f0c8-a516-4537-8f3f-915acb335e2c",
    "2595becc-e4a2-4507-88bf-e0114ab6d677"
  ]
}

Результат выполнения команды (признак успешности исполнения)

true

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

Имя вызова команды:mon_http_RemoveUsersFromGroup.
Поддерживается только синхронный вызов.
Результат выполнения команды журналируется.

GetLicenseInfo (mon-core)

Результат выполнения команды

[
  {
    "kind": "Dev",
    "expiredAt": 1906180561111,
    "properties": [
      {
        "key": "description",
        "value": "Лицензия по функционалу сервиса, использующего библиотеку Mon-core",
        "description": "Описание лицензии"
      },
      {
        "key": "globalSessionsLimit",
        "value": "-1",
        "description": "Глобальное ограничение на количество одновременных сессий за определенный промежуток времени (см. sessionWatchSec). Значение, которое меньше 0, означает \"без ограничений\"."
      },
      {
        "key": "sessionsLimitPerUser",
        "value": "-1",
        "description": "Ограничение на количество сессий для одного пользователя. Значение, которое меньше 0, означает \"без ограничений\"."
      },
      {
        "key": "sessionWatchSec",
        "value": "300",
        "description": "Время в секундах, в течении которого сессия учитывается при подсчете доступного лимита. Значение должно быть >= 0."
      },
      {
        "key": "privilegedEmails",
        "value": "mymega@email",
        "description": "Список email-ов привилегированных пользователей. На этих пользователей не распространяются лицензионные ограничения: globalSessionsLimit, sessionsLimitPerUser, activeUserLimit, allowedActions."
      },
      {
        "key": "allowedActions",
        "value": "anything,can,be,done",
        "description": "Действия, которые разрешены для выполнения под лицензией. Другие действия будут автоматически запрещены."
      },
      {
        "key": "activeUserLimit",
        "value": "-1",
        "description": "Глобальное ограничение на количество активированных пользователей в системе. Значение, которое меньше 0, означает \"без ограничений\"."
      },
      {
        "key": "jwtLifeTime",
        "value": null,
        "description": "Время действия токена JWT в секундах. Если установлено, то перекрывает значение переменной MON_JWT_LIFETIME. Значение должно быть >= 0."
      }
    ]
  }
]

Возвращает информацию об использующейся текущей лицензии сервиса Mon-core.

Имя вызова команды:mon_http_GetLicenseInfo.
Поддерживается только синхронный вызов.
Результат выполнения команды не журналируется.

Модели сервиса Mon-core (models)

User (mon-core)

Структура, описывающая сущность "пользователь"

Поле Тип Обязательное Описание
id UserId Да Идентификатор пользователя
email String Да Уникальный email пользователя
status UserStatus Да Статус пользователя в виде строки
info UserInfo Нет Опциональная информация о пользователе
modified TimeStamp Да Время в миллисекундах последнего изменения полей id, email или status
modifiedBy UserId Нет Пользователь, инициировавший последнее изменение полей id, email или status
reason String Нет Причина последнего изменения полей id, email или status
deactivateAt TimeStamp Нет Время в миллисекундах, после которого пользователь при попытке LoginByCredentials будет деактивирован

UserInfo (mon-core)

Дополнительная информация о пользователе.

Поле Тип Обязательное Описание
firstName String Нет Имя пользователя
lastName String Нет Фамилия пользователя
middleName String Нет Отчество пользователя
data Json Нет Дополнительные данные профиля пользователя

UserRegistrationInfo (mon-core)

Дополнительная информация о пользователе, которая используется только при регистрации.

Поле Тип Обязательное Описание
firstName String Да Имя пользователя
lastName String Да Фамилия пользователя
middleName String Нет Отчество пользователя
data Json Нет Дополнительные данные профиля пользователя

UserStatus (mon-core)

Список вариантов статуса пользователя в системе. Имеет тип String.

Название Описание
Pending Пользователь, ожидающий подтверждения регистрации
Activated Обычный пользователь системы (выполнивший все условия/требования после регистрации)
Deactivated Заблокированный пользователь системы

UserWithGroupCount (mon-core)

Информация о пользователе и количестве групп, в которых он состоит.

Поле Тип Обязательное Описание
user User Да Пользователь
groupsCount Int Да Количество групп, в которых состоит пользователь

LoginCredentials (mon-core)

Данные необходимые для выполнения входа пользователя в систему

Поле Тип Обязательное Описание
email String Да Email пользователя
password String Да Пароль пользователя

SuccessAuthentication (mon-core)

Результат, указывающий на успешный вход пользователя в систему. Содержит JWT.

Поле Тип Обязательное Описание
accessToken String Да JWT в виде строки
expiresIn Int Да Время жизни JWT в секундах

UserRegistrationDto (mon-core)

Данные, необходимые для регистрации пользователя в системе.

Поле Тип Обязательное Описание
email String Да Email пользователя
password String Да Пароль, который будет использован для аутентификации
info UserRegistrationInfo Да Дополнительная информация о пользователе
notificationUrl String Нет URL, который нужно отправить в письме пользователю

UserRegistrationResult (mon-core)

Результат, указывающий на успешный вход пользователя в систему. Содержит JWT.

Поле Тип Обязательное Описание
userId UserId Да Идентификатор группы пользователей
verificationRequested Boolean Да Признак того, что было отправлено письмо для подтверждения регистрации

ActionTokenId (mon-core)

Идентификатор токена (UUIDv4) для какого-либо действия.
В данный момент, доступно только 1 действие - подтверждение регистрации пользователя. Вид действия для которого был создан токен определяется с помощью типа ActionTokenKind ( название вида токена, представлен в виде строки).

GroupDTO (mon-core)

Структура для описания группы пользователей

Поле Тип Обязательное Описание
id GroupId Да Идентификатор группы пользователей
name String Да Название группы для отображения (любая строка)
modified TimeStamp Да Представляет время (UTC) в миллисекундах от 01.01.1970
description String Нет Описание группы

UpdateGroupDTO (mon-core)

Структура для передачи измененных атрибутов группы пользователей

Поле Тип Обязательное Описание Ограничения
id GroupId Да Идентификатор группы пользователей для CreateGroup:
- уникальное значение
для UpdateGroup:
- существующее значение
name String Да Название группы для отображения (любая строка)
description String Нет Описание группы

UpdateDeactivationTimeInput (mon-core)

Структура для передачи данных для обновления времени деактивации аккаунта

Поле Тип Обязательное Описание Ограничения
userIds List[UserId] Да Список идентификаторов пользователей
newDeactivateAt TimeStamp Нет Представляет время (UTC) в миллисекундах от 01.01.1970
reason String Нет Описание причины изменения

UpdateResponse (mon-core)

Поле Тип Обязательное Описание
updated Int Да Количество обновленных элементов

GroupInfo (mon-core)

Информация о группе пользователей и количестве ее участников

Поле Тип Обязательное Описание
group GroupDTO Да Информация о группе пользователей
usersCount Int Да Количество пользователей в группе

UsersInGroups (mon-core)

Структура для оперирования некоторыми пользователями из группы пользователей

Поле Тип Обязательное Описание Ограничения
groupId List[GroupId] Да Список идентификаторов групп пользователей
users List[UserId] Да Список идентификаторов пользователей

UserIdWithOptions (mon-core)

Поле Тип Обязательное Описание Ограничения
userId UserId Да Идентификатор пользователя
options Search Нет Опции для списка

UserIdWithStatus (mon-core)

Поле Тип Обязательное Описание Ограничения
userId UserId Да Идентификатор пользователя
status UserStatus Да Статус пользователя

UserIdWithInfo (mon-core)

Поле Тип Обязательное Описание Ограничения
id UserId Да Идентификатор пользователя
info UserInfo Да Информация о пользователе

UserIdWithEmail (mon-core)

Поле Тип Обязательное Описание
id UserId Да Идентификатор пользователя
email String Да Email пользователя

GroupIdWithOptions (mon-core)

Поле Тип Обязательное Описание Ограничения
groupId GroupId Да Идентификатор группы пользователей
options Search Нет Опции для списка

QueryParameters (mon-core)

Структура для передачи параметров, которые обычно должны быть переданы в качестве query string (например при входе по OpenID Connect провайдерам)

Поле Тип Обязательное Описание
queryParameters Json Да Json-объект со строковыми значениями, являющийся перечнем query string параметров

ChangePasswordDto (mon-core)

Поле Тип Обязательное Описание Ограничения
oldPassword String Да Текущий пароль пользователя
newPassword String Да Желаемый пароль пользователя

PasswordRecoverRequestDto (mon-core)

Поле Тип Обязательное Описание Ограничения
email String Да Логин пользователя
notificationUrl String Нет URL, который нужно отправить в письме пользователю

CheckTokenDto (mon-core)

Поле Тип Обязательное Описание Ограничения
actionTokenId uuid Да Идентификатор токена

RecoverPasswordByTokenDto (mon-core)

Поле Тип Обязательное Описание Ограничения
token uuid Да Идентификатор токена
newPassword String Да Желаемый пароль пользователя

UserAttributesMapping (mon-core)

Поле Тип Обязательное Описание
firstName String Да Настройка маппинга атрибутов для поля UserInfo.firstName. Строка в формате AttributeMapping.
lastName String Да Настройка маппинга атрибутов для поля UserInfo.lastName. Строка в формате AttributeMapping.
middleName String Да Настройка маппинга атрибутов для поля UserInfo.middleName. Строка в формате AttributeMapping.
email String Да Настройка маппинга атрибутов для поля User.email. Строка в формате AttributeMapping.

AttributeParsingSettings (mon-core)

Поле Тип Обязательное Описание
attribute String Да Название атрибута, из которого нужно использовать значение. Регистр не учитывается.
position Int Нет Индекс сегмента, который нужно использовать из значения атрибута, если значение атрибута было разделено. Если указано поле delimiter, то это поле становится обязательным.
delimiter String Нет Символ, по которому будет разделено значение атрибута. Если указано поле position, то это поле становится обязательным.
limit Int Нет Максимальное количество сегментов, на которое нужно разделить значение атрибута. Если не задано, то количество сегментов не ограничено.

UserIdWithGroups (mon-core)

Поле Тип Обязательное Описание
user UserId Да Идентификатор пользователя
groups List[GroupDTO] Да Массив групп пользователя

UserWithGroups (mon-core)

Поле Тип Обязательное Описание
user User Да Идентификатор пользователя
groups List[GroupIdTitle] Да Массив групп пользователя

GroupIdTitle (mon-core)

Поле Тип Обязательное Описание
groupId GroupId Да Идентификатор группы
name Title Да Имя группы

LicenseInfo (mon-core)

Поле Тип Обязательное Описание
kind String Да Вид лицензии
expiredAt Int Да Время, когда лицензия истекает
properties List[LicenseProperty] Да Список параметров модели LicenseDTO

LicenseProperty (mon-core)

Поле Тип Обязательное Описание
key String Да Название свойства лицензии
value String Нет Значение свойства лицензии
description String Нет Описание свойства. Значения для каждого свойства зафиксировано в таблице ниже

Таблица значений поля description

Значение поля description для каждого свойства лицензии зафиксировано в коде:

key description
description Описание лицензии.
globalSessionsLimit Глобальное ограничение на количество одновременных сессий за определенный промежуток времени (см. sessionWatchSec). Значение, которое меньше 0, означает "без ограничений".
sessionsLimitPerUser Ограничение на количество сессий для одного пользователя. Значение, которое меньше 0, означает "без ограничений".
sessionWatchSec Время в секундах, в течении которого сессия учитывается при подсчете доступного лимита. Значение должно быть >= 0.
privilegedEmails Список email-ов привилегированных пользователей. На этих пользователей не распространяются лицензионные ограничения: globalSessionsLimit, sessionsLimitPerUser, activeUserLimit, allowedActions.
allowedActions Действия, которые разрешены для выполнения под лицензией. Другие действия будут автоматически запрещены.
activeUserLimit Глобальное ограничение на количество активированных пользователей в системе. Значение, которое меньше 0, означает "без ограничений".
jwtLifeTime Время действия токена JWT в секундах. Если установлено, то перекрывает значение переменной MON_JWT_LIFETIME. Значение должно быть >= 0.

ActiveDirectory groups mapping (mon-core)

Для указания маппинга групп используются формат ADName=MonName, где
"ADName" может быть или GroupSID или Base64 строкой. "MonName" может быть только GroupId сервиса Mon.
Пример: S-1-5-21-4036403032-2978644966-1872548419-1100=TechAdmins;AQUAAAAAAAUVAAAAWJ+W8OaDirFD0pxvUgQAAA===Users.

Чтобы посмотреть информацию о группе, можно использовать команду
ldapsearch -H ldap://10.168.22.245 -x -W -D "tester@dev.embedika.ru" -b "dc=dev,dc=embedika,dc=ru" "(sAMAccountName=sso)", где
10.168.22.245 - адрес AD,
tester@dev.embedika.ru - пользователь AD, от которого делается запрос (должен иметь доступ к просмотру группы),
sso - название группы.

В ответе, нас интересует поле objectSid.

Пример ответа ldapsearch

# sso, Users, dev.embedika.ru
dn: CN=sso,CN=Users,DC=dev,DC=embedika,DC=ru
objectClass: top
objectClass: group
cn: sso
member:: Q0490KTRgNC+0L3RgtC10L3QtNC10YAsQ049VXNlcnMsREM9ZGV2LERDPWVtYmVkaWthLERDPXJ1
member:: Q0490KLQtdGB0YLQtdGALENOPVVzZXJzLERDPWRldixEQz1lbWJlZGlrYSxEQz1ydQ==
distinguishedName: CN=sso,CN=Users,DC=dev,DC=embedika,DC=ru
instanceType: 4
whenCreated: 20221129100547.0Z
whenChanged: 20221129100626.0Z
uSNCreated: 12851
uSNChanged: 12857
name: sso
objectGUID:: +4z7l0Mwe0qRQohm48uhCw==
objectSid:: AQUAAAAAAAUVAAAAWJ+W8OaDirFD0pxvUgQAAA==
sAMAccountName: sso
sAMAccountType: 268435456
groupType: -2147483646
objectCategory: CN=Group,CN=Schema,CN=Configuration,DC=dev,DC=embedika,DC=ru
dSCorePropagationData: 16010101000000.0Z

# search reference
ref: ldap://ForestDnsZones.dev.embedika.ru/DC=ForestDnsZones,DC=dev,DC=embedika,DC=ru

# search reference
ref: ldap://DomainDnsZones.dev.embedika.ru/DC=DomainDnsZones,DC=dev,DC=embedika,DC=ru

# search reference
ref: ldap://dev.embedika.ru/CN=Configuration,DC=dev,DC=embedika,DC=ru

# search result
search: 2
result: 0 Success

# numResponses: 5
# numEntries: 1
# numReferences: 3

External profile attributes mapping (mon-core)

Для указания атрибутов профиля из внешнего хранилища (ActiveDirectory, Keycloak и т.п.), из которых нужно получить значения для профиля пользователя (например, для полей User или UserInfo), используется JSON массив со списком настроек. Каждый элемент массива является строкой со структурой AttributeParsingSettings.

Формат строки со структурой AttributeParsingSettings:
"attributeName;position;delimiter;limit",
где ; является разделителем между полями структуры. Пробелы игнорируются для всех полей, кроме delimiter (данное поле может содержать пробелы).

Указание названия атрибута с разделителем может пригодиться, если нужно использовать только какой-то сегмент (по индексу из поля position), а не все значение. В качестве примера можно привести атрибут displayName, который содержит ФИО, и поле UserInfo.firstName, для которого требуется только Имя:
Атрибут: "displayName"
Значение атрибута: "Толстой Алексей Константинович"
Маппинг: "displayName; 1; ", где displayName - название атрибута, 1 - индекс сегмента (начиная с 0), ( пробел) - разделитель для сегментов. Limit сегментов не указан, т.к. опционален.
Выделение сегмента из значения атрибута реализовано через java-вый String.split(delimiter, limit).

Особенности:

Примеры строк с AttributeParsingSettings:

Примеры массива с настройками:

Требования к настройкам клиента Keycloak (mon-core)

Требования к настройке notification limit (mon-core)

Notification limit - это проверка того, что команды порождающие отправку email, не отправляют email одному пользователю дважды. Для того чтобы осуществить эту проверку, требуется идентифицировать пользователя.

Сейчас существует 2 команды порождающие отправку email: mon_http_RegisterUser и mon_http_PasswordRecoverRequest.

В команде mon_http_PasswordRecoverRequest идентификация пользователя производится с помощью email, который передается на вход команде. По email из базы данных извлекается userId и используется как идентификатор.

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

Замечание: при отсутствии у клиента заголовка User-Agent apigateway генерирует свой заголовок вида User-Agent: akka-http/10.2.10, поэтому клиент без User-Agent сможет первый раз выполнить команду.

IP-адрес пользователя поочередно ищется в заголовках X-Forwarded-For, X-Real-Ip и Forwarded и проверяется на то, является ли полученный заголовок валидным IP. Используется первый полученный таким образом IP.

Замечание: использование такого подхода подразумевает, что прокси, получающие запрос пользователя, должны убедиться, что заголовки X-Forwarded-For, X-Real-Ip и Forwarded генерируются прокси, а не пробрасываются из запроса пользователя.
При этом если прокси передает заголовок X-Forwarded-For, то достаточно убедиться, что был перезаписан именно он. Но если прокси не передает заголовки X-Forwarded-For и X-Real-Ip, а использует только Forwarded, ему кроме перезаписи Forwarded, нужно также отфильтровать возможные клиентские заголовки X-Forwarded-For и X-Real-Ip.

Замечание: http-заголовки регистронезависимы, поэтому нужно также запретить пробрасывание от пользователя любых вариаций разных регистров, например X-ForWARDed-For

Mon (門): сервис аутентификации

Сервис аутентификации отвечает за создание пользователей и вход пользователей в систему. Данные сервиса хранятся в PostgreSQL. Команды могут приходить только по HTTP.

Сервис разбит на несколько модулей, в виде sbt проектов:

Конфигурирование Mon

Требования к запуску Mon

Запуск локально из консоли с помощью SBT

MON_DB_HOST=localhost
MON_DB_PORT=5432
MON_DB_NAME=mon_db
MON_DB_USER=postgres
MON_DB_PASSWORD=postgres
MON_JWT_SIGNATURE=secretjwtstring
sbt boot/run

При запуске сервиса локально ожидается, что уже развернута необходимая инфраструктура:

Конфигурирование Mon через Consul

В Consul можно добавить следующие ключи:

Список всех переменных окружения для сервиса Mon

Переменная Тип Обязательная Значение по умолчанию Описание
MON_HTTP_HOST string Нет 0.0.0.0 Хост для HttpListener.
MON_HTTP_PORT int Нет 8192 Порт для HttpListener.
MON_KAFKA_SERVERS string Да localhost:9092 Адрес Kafka.
MON_KAFKA_TOPIC string Нет MON_commands Название топика для входящих команд.
MON_KAFKA_PARTITIONS int Нет 10 Количество партиций в топике команд.
MON_KAFKA_COMMANDEVENT_TOPIC string Нет commandevents Название топика для входящих/исходящих событий.
MON_KAFKA_USEREVENT_TOPIC string Нет userEvents Название топика для отправки событий о действиях с пользователями.
MON_KAFKA_CONSUMER_RESTART_MIN_BACKOFF duration string Нет 1 second Минимальная задержка перед перезапуском.
MON_KAFKA_CONSUMER_RESTART_MAX_BACKOFF duration string Нет 30 seconds Максимально возможная задержка перед перезапуском.
MON_KAFKA_CONSUMER_RESTART_RANDOM_FACTOR double Нет 0.2 Коэффициент величины дополнительной случайной задержки(jitter) относительно основной задержки (При значении 0.2 задержка может быть до 20% больше, чем при 0). Если после умножения задержки на MON_KAFKA_CONSUMER_RESTART_RANDOM_FACTOR получится меньше 1 миллисекунды, то jitter будет приравнен к нулю.
MON_KAFKA_CONSUMER_RESTART_MAX_RESTARTS int Нет 5 Максимальное количество перезапусков в заданный период времени. После превышения этого числа сервис будет объявлен больным. Все рестарты для каждого отдельного сообщения увеличивают и общий счетчик рестартов консьюмера, поэтому при использовании MON_KAFKA_CONSUMER_PER_MESSAGE_RESTART_MAX_RESTARTS нужно указывать MON_KAFKA_CONSUMER_RESTART_MAX_RESTARTS > MON_KAFKA_CONSUMER_PER_MESSAGE_RESTART_MAX_RESTARTS или не указывать MON_KAFKA_CONSUMER_PER_MESSAGE_RESTART_MAX_RESTARTS совсем.
MON_KAFKA_CONSUMER_RESTART_MAX_RESTARTS_WITHIN duration string Нет 5 minutes Период времени для ограничения перезапусков.
MON_KAFKA_CONSUMER_PER_MESSAGE_RESTART_MAX_RESTARTS int Нет 2 Максимальное количество раз, которое консьюмер перезапустится с неизменной очередью сообщений(в пределах DATA_MODEL_KAFKA_CONSUMER_RESTART_MAX_RESTARTS_WITHIN), прежде чем проигнорировать сообщение, на котором происходит ошибка (Указано количество рестартов, а не прочтений. Если MON_KAFKA_CONSUMER_RESTART_MAX_RESTARTS = 2, то ошибочное сообщение будет обработано 3 раза, после чего произойдет 3ий рестарт и оно будет проигнорировано). Если указать 0, то перезапуск произойдет, но сообщение будет обработано только в первый раз, когда произошла ошибка. Если указать значение меньше 0, то перезапуски все равно будут происходить, но игнорирование сообщений, вызывающих ошибку, будет отключено.
MON_KAFKA_CONSUMER_PER_MESSAGE_RESTART_CACHE_SIZE int Нет 100 Для каждого сообщения счетчик перепрочтений хранится в кэше. Максимальное количество значений в этом кэше.
MON_KAFKA_CONSUMER_PER_MESSAGE_RESTART_CACHE_TTL duration string Нет 5 minutes Для каждого сообщения счетчик перепрочтений хранится в кэше.Максимальное время жизни элемента в этом кэше. В случае отсутствия значения время жизни элемента не будет ограничено.
MON_KAFKA_CONSUMER_POLL_TIMEOUT duration string нет 10 milliseconds timeout запроса poll для kafka consumer
MON_KAFKA_CONSUMER_POLL_INTERVAL duration string нет 100 milliseconds интервал между запросами poll для kafka consumer
MON_KAFKA_CONSUMER_PROPS string нет "max.poll.records=500;max.partition.fetch.bytes=524288" дополнительные параметры для kafka consumer в формате "key1=value1;key2=value2"
MON_KAFKA_AUTH_USER string Нет "" Название учетной записи Kafka. Если название не указано, то настройки авторизации не будут применены.
MON_KAFKA_AUTH_PASSWORD string Нет "" Пароль учетной записи Kafka.
MON_KAFKA_AUTH_TRUSTSTORE_LOCATION string Нет "" Путь до хранилища сертификатов (Java key store). Если путь не указан, то сертификат применяться не будет.
MON_KAFKA_AUTH_TRUSTSTORE_PASSWORD string Нет "" Пароль к хранилищу сертификатов.
MON_KAFKA_AUTH_MODE string Нет static Режим аутентификации: static - одна учетная запись на все запросы, mapping - учетная запись зависит от запроса.
MON_KAFKA_AUTH_CONFIG string Нет "" Настройки для аутентификации: если AuthMode = mapping, то необходим JSON с List[KafkaAuthConfig]. Переменная соответствует полю authConfig из KafkaAuthSettings.
MON_KAFKA_AUTH_CACHE_SIZE int Нет Максимальный размер кеша для Kafka producer (количество активных соединений).
MON_KAFKA_CONNECTION_CHECK_TEST_MESSAGES_INTERVAL duration string Нет 4 minutes Применяется только для producer-ов со способом аутентификации kerberos. Интервал отправки тестовых сообщений кафки в топик connectionCheck.testMessagesTopicName. Тестовые сообщения (null, service producer test) отправляются регулярно с этим интервалом.
MON_KAFKA_CONNECTION_CHECK_INTERVAL duration string Нет 60 seconds Применяется только для producer-ов со способом аутентификации kerberos. Интервал проверки того, сколько тестовых сообщений было отправлено за данный период. Если количество сообщений за этот период равно количеству сообщений за прошлый период, то начинается отсчет периода без сообщений.
MON_KAFKA_CONNECTION_CHECK_FAILED_AFTER_INTERVAL duration string Нет 5 minutes Применяется только для producer-ов со способом аутентификации kerberos. Максимальная продолжительность периода без успешно отправленных тестовых сообщений. По ее достижении сервис будет объявлен больным.
MON_KAFKA_AUTH_CACHE_TTL duration string Нет Время жизни Kafka producer в кеше.
MON_CONSUL_ADDR string Да http://localhost:8500 Адрес Сonsul.
MON_CONSUL_AUTH_USER string Нет "" Название учетной записи Сonsul. Если название не указано, то настройки авторизации не будут применены.
MON_CONSUL_AUTH_PASSWORD string Нет "" Пароль учетной записи Сonsul.
MON_KAFKA_AUTH_PRINCIPAL string Нет "" Principal учетной записи Kafka в Kerberos(в случае соединения с kafka через Kerberos).
MON_KAFKA_AUTH_KEYTAB_PATH string Нет "" Путь до keytab-файла(в случае соединения с kafka через Kerberos).
MON_AUTHORIZER_KIND string Нет authzforce Вид авторизатора, который используется в сервисе. Допустимые значения: "authzforce", "oberto". При указании неизвестного значения будет использовано значение по-умолчанию.
MON_AUTHZFORCE_ADDR string Да http://localhost:8080/authzforce-ce Адрес AuthZforce server.
MON_AUTHZFORCE_DOMAIN string Нет Доступный DomainID в AuthZforce server.
MON_TRACE_DURATION boolean Нет false Нужно ли логировать длительность выполнения команд.
MON_USERGROUP_DEFAULT string Нет "" Список групп пользователей, в которые необходимо добавлять новых пользователей (группы по-умолчанию). Список групп задается в виде одной строки, в которой пары GroupId и названия записываются так "id1,name1;id2,name2". Пустая строка = "никакие группы добавлять не нужно".
MON_JWT_SIGNATURE string Да "" Сигнатура для подписи и расшифровки jwt-токенов, используемых для аутентификации.
MON_JWT_LIFETIME duration string Нет 12 hours Время действия токена JWT.
MON_JWT_COOKIE_EXPIRE_OFFSET duration string Нет 24 hours Cookie c jwt, которое выдается некоторыми командами mon, живет дольше, чем сам jwt, содержащийся внутри этой cookie. Переменная определяет то, на сколько срок жизни cookie превышает срок жизни jwt.
MON_PASSWORD_RECOVERY_URL url string Нет http://localhost:8080/change-password?token=[[token]] Префикс URL используемый при генерации ссылки восстановления пароля.
MON_VERIFICATION_TTL duration string Нет 1 day Время действия токена подтверждения регистрации.
MON_RECOVERY_TTL duration string Нет 1 day Время действия токена восстановления пароля.
MON_EXTERNAL_VERIFY_ENABLED boolean Нет false Проверять ли Email пользователя при регистрации.
MON_EXTERNAL_VERIFY_REASON string Нет Registration confirmed Текст сообщения о причине изменения пользователя, который будет фиксироваться в БД при подтверждении Email при верификации зарегистрированного пользователя командой VerifyUserRegistration.
MON_EXTERNAL_VERIFY_URL url string Нет http://localhost:8080/verify-user?token=[[token]] URL из письма для верификации.
MON_NOTIFICATION_URL_REGEXPS string Нет http://localhost:8080/verify-user\\?token=\\[\\[token\\]\\] Набор регулярных выражений, разделенных ";", для проверки переданного в запросе notificationUrl. Формат соответствует scala строке для regexp (потому и двойное экранирование слешей "\").
MON_DISCOVERABLE_ID string Нет another_mon_instance ID данного сервиса.
MON_DISCOVERABLE_NAME string Нет mon Название группы сервисов к которой принадлежит данный.
MON_DISCOVERABLE_HOST string Да localhost Адрес текущего инстанса сервиса, который будет виден через ServiceDiscovery.
MON_DISCOVERABLE_PORT int Нет ${MON_HTTP_PORT} Порт текущего инстанса сервиса, который будет виден через ServiceDiscovery.
MON_DISCOVERABLE_LIVETIME duration string Нет 2 minutes Время с последнего HealthCheck, в течении которого сервис считается "живым".
MON_DISCOVERABLE_HEALTHPASS duration string Нет 1 minute Периодичность отправки HealthCheck.
MON_INTERNALCMD_ALLOW boolean Нет false Возможно ли сервису отправлять "внутренние" команды.
MON_SENDERLIB_CONSIDER_ALL_COMMANDS_AS_INTERNAL boolean Нет false Флаг, определяющий будут ли все обращения в другие сервисы являться внутренними (т.е. не требовать авторизацию). Детальное описание механизма: Внутренние команды.
MON_SENDERLIB_COMMANDS_CACHE_UPDATEPERIOD duration string Нет 10 minutes Время на которое будут кешироваться данные о командах.
MON_SENDERLIB_SERVICES_CACHE_UPDATEPERIOD duration string Нет 30 seconds Время на которое будут кешироваться данные о сервисах.
MON_DB_HOST string Да Хост сервера базы данных.
MON_DB_PORT int Да Порт сервера базы данных.
MON_DB_NAME string Да Название базы.
MON_DB_USER string Да Пользователь для базы данных.
MON_DB_PASSWORD string Да Пароль для пользователь для базы данных.
MON_DB_THREADS int Нет 10 Количество потоков в пуле потоков для соединения с БД.
MON_DB_QUEUE_SIZE int Нет 300 Размер очереди для действий базы данных, которые не могут быть выполнены немедленно, когда все потоки заняты. За пределами этого значения новые действия немедленно завершаются неудачей.
MON_DB_CONN_MAX int Нет 10 Максимальное количество одновременных подключений к БД.
MON_DB_CONN_TIMEOUT duration string Нет 20 second Максимальное время ожидания ответа для соединения к БД. Если это время превышено, а соединение не становится доступным, будет брошено исключение SQLException. 1000 мс — минимальное значение.
MON_DB_ISOLATION string Нет READ_COMMITTED Уровень изоляции транзакций для новых подключений. Допустимые значения: NONE, READ_COMMITTED, READ_UNCOMMITTED, REPEATABLE_READ, SERIALIZABLE.
MON_DB_READONLY boolean Нет false Read-only SQL транзакция может изменять только временные таблицы. Этот параметр управляет статусом «только для чтения» по умолчанию для каждой новой транзакции.
MON_DB_CONN_MIN int Нет ${MON_DB_THREADS} Минимальное количество одновременных подключений к БД.
MON_DB_VALIDATION_TIMEOUT duration string Нет 1 seconds Максимальное время, в течение которого соединение будет проверяться на работоспособность. 1000 мс — минимальное значение.
MON_DB_IDLE_TIMEOUT duration string Нет 10 minutes Максимальное время, в течение которого соединению разрешено простаивать в пуле. Значение 0 означает, что простаивающие соединения никогда не удаляются из пула.
MON_DB_MAX_LIFETIME duration string Нет 30 minutes Максимальное время жизни соединения в пуле. Когда простаивающее соединение достигает этого времени ожидания, даже если оно недавно использовалось, оно будет удалено из пула. Значение 0 указывает на отсутствие максимального срока службы.
MON_DB_INITIALIZATION_FAIL_FAST boolean Нет false Deprecated, начиная с версии Slick 3.3.0. Определяет, будет ли пул «быстро выходить из строя», если пул не может быть успешно заполнен начальными соединениями. Если соединения не могут быть созданы во время запуска пула, будет выдано исключение RuntimeException. Это свойство не имеет никакого эффекта, если minConnections равно 0.
MON_DB_LEAK_DETECTION_THRESHOLD int Нет 0 Время, в течение которого соединение может находиться вне пула, прежде чем будет зарегистрировано сообщение, указывающее на возможную утечку соединения. Значение 0 означает, что обнаружение утечек отключено. Наименьшее приемлемое значение для включения обнаружения утечек составляет 10 с.
MON_DB_CONNECTION_TEST_QUERY string Нет SELECT 1 Выражение, которое будет выполнено непосредственно перед получением соединения из пула для проверки того, что соединение с базой данных все еще активно. Оно зависит от базы данных и должно представлять собой запрос, требующий минимальной обработки базой данных (например, «VALUES 1»). Если этот параметр не установлен, вместо него используется метод JDBC4 Connection.isValid().
MON_DB_REGISTER_MBEANS boolean Нет false Зарегистрированы ли JMX Management Beans («MBeans»).
MON_DB_AUTO_COMMIT boolean Нет true Это свойство определяет то, как будут вести себя по умолчанию возвращаемые соединения относительно autocommit-а.
MON_DB_SCHEMA string Нет public Устанавливает schema по умолчанию.
MON_DB_ISOLATE_INTERNAL_QUERIES boolean Нет false Определяет то, изолируются ли с помощью транзакций внутренние запросы пула(например запрос connection alive test). Свойство применяется только если autoCommit выключен.
MON_DB_INITIALIZATION_FAIL_TIMEOUT int Нет 1 Работает, начиная с версии Slick 3.3.0. Определяет, будет ли пул «быстро выходить из строя», если пул не может быть успешно заполнен начальными соединениями. Любое положительное число считается числом миллисекунд для попытки получить начальное соединение; поток приложения будет заблокирован в течение этого периода. Если соединение не может быть получено до истечения этого времени, будет брошено исключение. Данный таймаут применяется после периода connectionTimeout. Если значение равно нулю (0), HikariCP попытается получить и проверить подключение. Если соединение получено, но проверка не пройдена, будет брошено исключение, и пул не будет запущен. Однако, если соединение не может быть получено, пул запустится, но последующие попытки получить соединение могут потерпеть неудачу. Значение меньше нуля пройдет любую первоначальную попытку подключения, и пул немедленно запустится, пытаясь получить соединения в фоновом режиме. Следовательно, последующие попытки получить соединение могут потерпеть неудачу.
MON_READABLE_NAME string Нет Сервис пользователей Читаемое название этого сервиса.
MON_DESCRIPTION string Нет Предназначен для определения схемы и хранения объектов Читаемое описание этого сервиса.
MON_AUTHN_EXTERNAL_SESSION_LIFETIME duration string Нет 10 minutes Продолжительность внешней сессии (например, в случае сессии, хранящей данные о процессе OpenId Connect аутентификации - время, за которое пользователь должен завершить вход после получения ссылки на форму входа).
MON_KRB_SVC_PRINCIPAL string Нет "" ID сервера в ActiveDirectory (если значение отсутствует/пустое, то Kerberos authentication не будет работать).
MON_KRB_SVC_KEYTAB string Нет "" Путь к keytab файлу для MON_KRB_SVC_PRINCIPAL с настройками доступа к ActiveDirectory (если значение отсутствует/пустое, то Kerberos authentication не будет работать).
MON_KRB_CALLBACK_URL string Нет "" Callback URL для редиректа после Kerberos authentication (в версии <= 1.6 не используется?) (если значение отсутствует/пустое, то Kerberos authentication не будет работать).
MON_KRB_DEBUG boolean Нет false Debug логгирование Kerberos authentication в сторонней библиотеке.
MON_KRB_LDAP_HOST string Нет localhost Хост ActiveDirectory (LDAP протокол) (если значение отсутствует/пустое, то Kerberos authentication не будет работать). Пример: "cloud.dev.embedika.ru".
MON_KRB_LDAP_PORT int Нет 389 Порт ActiveDirectory (LDAP протокол) (если значение отсутствует/некорректное (port < 1), то Kerberos authentication не будет работать).
MON_KRB_LDAP_BIND_USER string Нет "" Имя пользователя для привязки всех запросов в ActiveDirectory (если значение отсутствует/пустое, то Kerberos authentication не будет работать). Пример: "cn=Verdi Dev,cn=Users,dc=dev,dc=embedika,dc=ru".
MON_KRB_LDAP_BIND_CREDS string Нет "" Пароль для MON_KRB_LDAP_BIND_USER (если значение отсутствует/пустое, то Kerberos authentication не будет работать).
MON_KRB_LDAP_SERVER_BASE_DN string Нет "" Базовый DN в ActiveDirectory для всех объектов (если значение отсутствует/пустое, то Kerberos authentication не будет работать). Пример: "dc=dev,dc=embedika,rc=ru".
MON_KRB_LDAP_CONNPOOL_SIZE_MIN int Нет 2 Минимальный размер пула подключений к ActiveDirectory.
MON_KRB_LDAP_CONNPOOL_SIZE_MAX int Нет 128 Максимальный размер пула подключений к ActiveDirectory.
MON_KRB_LDAP_CONNPOOL_TIMEOUT_WAIT duration string Нет 10 seconds Максимальное время ожидания свободного подключения в пуле.
MON_KRB_LDAP_CONNPOOL_TIMEOUT_CONN duration string Нет 500 millis Максимальное время ожидания подключения к ActiveDirectory.
MON_KRB_LDAP_CONNPOOL_TIMEOUT_RESP duration string Нет 1 seconds Максимальное время ожидания ответа от ActiveDirectory.
MON_KRB_LDAP_USER_FIRSTNAME string Нет ["givenName", "cn;1; ;3", "displayName;1; ;3"] Настройки получения атрибута из профиля в ActiveDirectory для UserInfo.firstName в формате AttributeMapping.
MON_KRB_LDAP_USER_LASTNAME string Нет ["sn", "cn;0; ;3", "displayName;0; ;3"] Настройки получения атрибута из профиля в ActiveDirectory для UserInfo.lastName в формате AttributeMapping.
MON_KRB_LDAP_USER_MIDDLENAME string Нет ["middleName", "cn;2; ;3", "displayName;2; ;3"] Настройки получения атрибута из профиля в ActiveDirectory для UserInfo.middleName в формате AttributeMapping.
MON_KRB_LDAP_USER_EMAIL string Нет ["mail", "emailaddress"] Настройки получения атрибута из профиля в ActiveDirectory для User.email в формате AttributeMapping.
MON_KRB_LDAP_USER_OBJECT_ID string Нет ["sid", "objectsid"] Настройки получения атрибута из профиля в ActiveDirectory для ProviderKey (уникального ключа пользователя в провайдере профиля пользователя) в формате AttributeMapping.
MON_KRB_GROUPS_MAPPING string Нет "" Конвертация групп из Active Directory в группы Mon. Формат "ADName1=MonName1;ADName2=MonName2". Подробнее в AD groups mapping.
MON_KRB_GROUPS_NOT_REMOVE string Нет "" Группы Mon, из которых не нужно удалять пользователя, если они больше не приходят из Active Directory. Формат "MonName1;MonName2".
MON_KEYCLOAK_CLIENT_ID string Нет "" ID клиента в Keycloak (если значение отсутствует, то Keycloak authentication не будет работать).
MON_KEYCLOAK_CLIENT_SECRET string Нет "" Secret клиента в Keycloak (если значение отсутствует, то Keycloak authentication не будет работать).
MON_KEYCLOAK_REALM string Нет "" Используемый Realm в Keycloak (если значение отсутствует, то Keycloak authentication не будет работать).
MON_KEYCLOAK_BASE_URI url string Нет "" URI Keycloak (если значение отсутствует, то Keycloak authentication не будет работать). Пример: "http://keycloak:8080".
MON_KEYCLOAK_DISCOVERY_URL url string Нет "" URI openid configuration в Keycloak (если значение отсутствует, то будет использован "$baseUri/realms/$realm/.well-known/openid-configuration"). Пример: "http://keycloak:8080/realms/test-realm/.well-known/openid-configuration".
MON_KEYCLOAK_CALLBACK_URL url string Нет "" Callback URL для редиректа после входа по Keycloak (если значение отсутствует, то Keycloak authentication не будет работать). Пример: "http://verdi.dev/keycloak-callback".
MON_KEYCLOAK_PKCE_METHOD string Нет S256 Используемый Challenge Method для PKCE (Proof Key for Code Exchange). Доступные варианты: "plain" и "S256". (если значение отсутствует, то Keycloak authentication не будет работать).
MON_KEYCLOAK_GROUPS_MAPPING string Нет "" Конвертация ролей из Keycloak в группы Mon. Формат "KCName1=MonName1;KCName2=MonName2".
MON_KEYCLOAK_GROUPS_NOT_REMOVE string Нет "" Группы Mon, из которых не нужно удалять пользователя, если соответствующие роли больше не приходят из Keycloak. Формат "MonName1;MonName2".
MON_KEYCLOAK_USER_FIRSTNAME string Нет ["givenName", "given_name;1; ;3"] Настройки получения атрибута из профиля в Keycloak для UserInfo.firstName в формате AttributeMapping.
MON_KEYCLOAK_USER_LASTNAME string Нет ["family_name"] Настройки получения атрибута из профиля в Keycloak для UserInfo.lastName в формате AttributeMapping.
MON_KEYCLOAK_USER_MIDDLENAME string Нет ["middleName", "middle_name", "given_name;2; ;3"] Настройки получения атрибута из профиля в Keycloak для UserInfo.middleName в формате AttributeMapping.
MON_KEYCLOAK_USER_EMAIL string Нет ["email", "mail", "emailaddress"] Настройки получения атрибута из профиля в Keycloak для User.email в формате AttributeMapping.
LOG_LEVEL_AUTH string Нет INFO Уровень логирования операций во время аутентификации.
LOG_LEVEL_AUTH_CONTEXT string Нет INFO Уровень логирования доступа к контексту аутентификации. Работает только в DEBUG.
MON_SENDERLIB_COMMANDS_HTTP_RETRY_ATTEMPTS int Нет 5 Поле attempts из RetrySettings.
MON_SENDERLIB_COMMANDS_HTTP_RETRY_DELAY duration string Нет 5 seconds Поле delay из RetrySettings.
MON_SENDERLIB_COMMANDS_HTTP_RETRY_KIND string Нет OnSomeExceptions(ConnectException) CommandResultRetryConditionKind.
MON_SENDERLIB_CONSUL_CONNECTION_RETRY_MAX int нет 5 Количество попыток переподключения к Consul
MON_SENDERLIB_CONSUL_CONNECTION_RETRY_DELAY duration string нет 1 second Задержка при попытках переподключения к Consul
MON_LICENSE_PATH string Да "" Путь до файла с лицензией (только binary format).
MON_LICENSE_KEY string Да "" Путь до файла с публичным ключом лицензией.
MON_LICENSE_PATH_PRIORITY string Нет "" Порядок использования лицензий. При пустом значении - порядок будет соответствовать порядку путей до файлов лицензий (MON_LICENSE_PATH). Строка должна содержать приоритет для каждой лицензии, приоритеты разделяются запятой (например, 1,5,2) - лицензии будут обрабатываться в порядке возрастания приоритета.
MON_ACCOUNT_LIFETIME duration string Нет Срок жизни аккаунта пользователя. Устанавливается в момент создания аккаунта, при превышении срока жизни аккаунт деактивируется во время LoginByCredentials.
MON_ACCOUNT_PRIVILEGED_EMAILS string Нет Строка с регулярным выражением. Аккаунты пользователей, у которых email-ы подходят под выражение, освобождаются от установки и проверки срока жизни аккаунта.
MON_EMAIL_NOTIFICATION_LIMIT_ENABLE boolean Нет false Включена ли проверка того, что команды порождающие отправку email, не отправляют email одному пользователю дважды в течении MON_EMAIL_NOTIFICATION_DELAY_PER_USER. Подробнее о настройке этой функции можно узнать здесь.
MON_EMAIL_NOTIFICATION_DELAY_PER_USER duration string Нет Период, в течении которого при MON_EMAIL_NOTIFICATION_LIMIT_ENABLE = true команды порождающие отправку email, не отправляют email одному пользователю дважды. Должен быть положительным и меньше 365 дней.
MON_EMAIL_NOTIFICATION_ADDITIONAL_IDENTITY_HEADERS string Нет "" Строка, содержащая перечисление через запятую дополнительных заголовков, которые учитываются при идентификации пользователя, чтобы запретить отправку email при MON_EMAIL_NOTIFICATION_LIMIT_ENABLE = true. Подробнее о работе с заголовками notification limit можно узнать здесь.
MON_PASSWORD_EXPIRE_MIGRATION_START_TIME string Нет "" Время, в которое нужно запустить обновление поля PasswordInfo.passwordExpirationDate для пользователей у которых PasswordInfo.salt != null. Значение должно быть позже времени запуска сервиса, иначе миграция будет считаться выполненой. Валидное значение должно быть не пустым и соответствовать формату "yyyy-MM-dd HH:mm" (UTC timezone).
MON_PASSWORD_EXPIRE_MIGRATION_VALUE string Нет "" Значение для поля PasswordInfo.passwordExpirationDate, которое будет установлено в процессе миграции. Значение должно быть не пустым и соответствовать формату "yyyy-MM-dd HH:mm" (UTC timezone).
MON_DB_URL jdbc url string Нет "jdbc:postgresql://"${?MON_DB_HOST}":"${?MON_DB_PORT}"/"${?MON_DB_NAME} Адрес базы данных. Можно использовать вместо MON_DB_HOST, MON_DB_PORT и MON_DB_NAME.
MON_KEYCLOAK_CLIENT_AUTHENTICATION_METHOD string Нет client_secret_basic Метод аутентификации keycloak-клиента.
MON_AKKA_HTTP_CLIENT_MAXCON int Нет 512 Максимальное количество http-соединений к одному хосту, которое используемый akka-http-клиент может одновременно поддерживать у себя в пуле.
MON_AKKA_HTTP_CLIENT_MAXREQ int Нет 1024 Максимальное количество http-запросов к одному хосту, которые в случае достижения количества одновременных запросов превышающих MON_AKKA_HTTP_CLIENT_MAXCON будут положены в очередь и обработаны akka-http-клиентом позже.
MON_AKKA_HTTP_SERVER_MAXCON int Нет 1024 Максимальное количество одновременно открытых http-соединений, которое поддерживает akka-http-сервер через метод Http.bind и другие методы аналогичные ему.
MON_EXPORT_FILE_NAME string Нет &quot;Список пользователей &lt;dd.MM.yyyy HH.mm&gt;.xlsx&quot; Название файла с экспортом. Внутри < > можно указать маску для даты.
MON_EXPORT_TIME_ZONE string Нет Europe/Moscow Временная зона, используемая при форматировании названия и дат в экспорте.
MON_EXPORT_DATE_FORMAT string Нет dd.MM.yyyy HH.mm Формат дат в файле экспорта.
MON_EXPORT_BUCKET string Нет temp Бакет S3, в котором сохраняются файлы экспорта.
MON_EXPORT_COLUMNS string Нет lastName,firstName,middleName,email,groups,status Колонки из БД, которые нужно поместить в файл экспорта, разделяются запятой. Поддерживаются все данные возвращаемые из ListUsersWithGroups включая строковые значения на произвольной глубине в data. Для каждого элемента в данной переменной должен быть элемент в MON_EXPORT_COLUMN_NAMES на соответствующей позиции, иначе сервис не запустится и в логе будет выведено сообщение с ошибкой.
MON_EXPORT_COLUMN_NAMES string Нет Фамилия,Имя,Отчество,Email,Группы,Состояние Названия для колонок в файле экспорта, разделенные запятой.
MON_EXPORT_PAGE_SIZE int Нет 256 Размер страниц, которыми извлекаются данные при экспорте.
MON_EXPORT_READ_BUFFER_SIZE int Нет 4096 Размер буфера в операциях с файлами во время экспорта.
MON_EXPORT_GROUPS_SEPARATOR string нет ; Разделитель для списка групп при выгрузке.
MON_FS_URI string Да http://localhost:9000 Адрес S3 хранилища.
MON_FS_ACCESS_KEY_ID string Да "" AccessKey S3 хранилища.
MON_FS_SECRET_ACCESS_KEY string Да "" Секретный ключ S3 хранилища.
MON_FS_UPLOAD_PARALLELISM int Нет 4 Параллельность при работе с S3.
MON_FS_RETRY_ATTEMPTS int Нет 5 Количество ретраев, которое будет произведено в случае Exception-а в операции FSClient-а и при вычитывании стрима в get операциях FSClient-а.
MON_FS_RETRY_DELAY duration string Нет 10 millis Задержка между ретраями операций FSClient-а.
MON_FS_ZIO_SHORT_MESSAGE_MODE boolean нет false Флаг включения режима сохранения ошибок работы с файловым хранилищем в сервисе журналирования nestor. При включении режима ошибки в логах будут отображаться в сокращенном формате: Short zio message mode. ExceptionType: ТИП ОШИБКИ, Exception id: 'СГЕНЕРИРОВАННЫЙ UUID' added to journal. Указанный id будет фиксироваться в event записи nestor'а в поле data.id
MON_JOURNAL_MODE string Нет WriteToJournal Режим журналирования Nestor. Допустимые значения: WriteToJournal (Отправка в сервис журналирования), WriteToTopic (Отправка события в очередь)
MON_JOURNAL_TOPIC string Да, если переменная MON_JOURNAL_MODE = WriteToTopic "" Название очереди журналирования. Для режима WriteToJournal значение игнорируется.
MON_AUTHN_HASH_ROUNDS int Нет 12 Количество раундов хэширования пароля при его сохранении в БД. Допустимые значения: от 4 до 30 включительно.
MON_AUTHN_SIPHASH_COMPRESSION_ROUNDS int Нет 2 Количество раундов сжатия исходной строки при генерации хэша идентификатора для отправки писем при регистрации и сбросе пароля. Подробнее о логике данных почтовых уведомлений можно узнать здесь. Указанное значение должно быть больше 0.
MON_AUTHN_SIPHASH_FINALIZATION_ROUNDS int Нет 4 Количество раундов финального преобразования при генерации хэша идентификатора для отправки писем при регистрации и сбросе пароля. Подробнее о логике данных почтовых уведомлений можно узнать здесь. Указанное значение должно быть больше 0.

Список команд сервиса Mon (commands-list)

Список команд сервиса Mon аналогичен списку команд в библиотеке mon-core.

Модели сервиса Mon

Набор моделей сервиса mon аналогичен набору моделей в библиотеке mon-core.

Особенности Kerberos authentication

Особенности Kerberos authentication для mon аналогичны особенностям Kerberos authentication для mon-core

ActiveDirectory groups mapping (mon)

ActiveDirectory groups mapping в mon аналогичен activeDirectory groups mapping в mon-core

External profile attributes mapping (mon)

Маппинг атрибутов профиля из внешнего хранилища (ActiveDirectory, Keycloak и т.п.) в mon, аналогичен маппингу в mon-core

Требования к настройкам клиента Keycloak (mon)

Требования к настройкам клиента Keycloak в mon аналогичны требованиям клиента Keycloak в mon-core

Требования к настройке notification limit (mon)

Требования к настройке notification limit в mon аналогичны требованиям к настройке notification limit в mon-core, за исключением того, что в mon настройка NotificationSettings.additionalIdentityHeaders равна переменной MON_EMAIL_NOTIFICATION_ADDITIONAL_IDENTITY_HEADERS.

Nestor-client: клиент для сервиса журнала

Примеры создания Nestor-client

Получение и валидация настроек NestorConfig

make[NestorConfig].from { appSettings: ApplicationSettings =>
  appSettings.nestor.validated.fold(throw _, identity)
}

Создание NestorClient

make[NestorClient].from {
  (
    dispatcher: Dispatcher,
    kafkaProducer: KafkaProducerApi[Either[ErrorResponse, Unit]],
    nestorConfig: NestorConfig,
    ec: ExecutionContext @Id("ec-services")
  ) => 
    new LiveNestorClient(dispatcher, kafkaProducer, nestorConfig)(ec)
}

Создание NestorClientTF[F]

// F[_]: Async: ContextShift
make[NestorClientTF[F]].from {
  (
    verdi: VerdiTF[F],
    factory: VerdiFactory,
    nestorConfig: NestorConfig,
    ec: ExecutionContext @Id("ec-services")
  ) =>
    NestorClientTF.make[F](verdi, factory.kafkaProducer, nestorConfig)(Async[F], ContextShift[F], ec)
}

Создание NestorClientTF[F] на ZIO

import zio.interop.catz._

val nestorConfigLayer: RLayer[Has[AppConfig], Has[NestorConfig]] = ZLayer.fromServiceM { config =>
  ZIO.fromEither(config.nestor.validated)
}

val nestorClientLayer
  : URLayer[Has[VerdiTF[Task]] with Has[VerdiFactory] with Has[NestorConfig] with Has[ExecutionContext], Has[NestorClientTF[Task]]] =
  ZLayer.fromServices[VerdiTF[Task], VerdiFactory, NestorConfig, ExecutionContext, NestorClientTF[Task]] { (verdi, factory, config, ec) =>
    NestorClientTF.make[Task](verdi, factory.kafkaProducer, config)(Async[Task], ContextShift[Task], ec)
  }

Для того чтобы использовать библиотеку nestor-client, нужно добавить зависимость "com.embedika.verdi" %% "nestor-client" % verdiVersion.

KafkaProducerApi можно получить из VerdiFactory.kafkaProducer или использовать свой

Предоставляемый функционал NestorClient

Nestor: сервис журналирования

Общее описание архитектуры сервиса журналирования

Для работы с журналом необходимы действия: добавить одно событие, запросить событие по идентификатору, отфильтровать события. Для каждого из этих действий Nestor предоставляет verdi-команду. Добавление это асинхронная команда, все события поступаю в очередь кафки и сохраняются пачками, поэтому будет существовать временной лаг между созданием события и возможностью его просмотра через Nestor. Сохранение пачками сделано для снижения нагрузки на хранилище. Размер пачки событий ограничен максимальным кол-вом событий, а так же временем формирования пачки ( см. groupedWithin)

Список переменных окружения Nestor

Переменная Тип Обязательная Значение по умолчанию Описание
SERVER_PORT Int Нет 8080 Порт, на котором слушает HTTP-сервер.
CONSUMER_TOPIC String Нет document Название Kafka-топика для команд журналирования событий.
CONSUMER_CHUNK_SIZE String Нет 1000 Размер пачки обрабатываемых событий.
CONSUMER_CHUNK_WITHIN Duration String Нет 10 seconds Время, за которое должна обработаться пачка событий, что определяет производительность сервиса.
CONSUMER_GROUP String Нет document Имя группы-консьюмеров сервиса журналирования.
VERDI_CONSUL String Да http://localhost:8500 Адрес Consul.
VERDI_CONSUL_AUTH_USER String Нет "" Название учетной записи Сonsul. Если название не указано, то настройки авторизации не будут применены.
VERDI_CONSUL_AUTH_PASSWORD String Нет "" Пароль учетной записи Сonsul.
VERDI_KAFKA_ADDRESS String Да localhost:9092 Адрес брокера Kafka.
VERDI_KAFKA_TOPIC String Нет commandevents Название Kafka-топика для отправки сообщений со статусами выполняемых команд. ОБЯЗАТЕЛЬНО должно соответствовать названию этого топика в сервисе статуса команд.
VERDI_KAFKA_AUTH_USER String Нет "" Название учетной записи Kafka. Если название не указано, то настройки авторизации не будут применены.
VERDI_KAFKA_AUTH_PASSWORD String Нет "" Пароль учетной записи Kafka.
VERDI_KAFKA_AUTH_PRINCIPAL String Нет "" Principal учетной записи Kafka в Kerberos(в случае соединения с kafka через Kerberos).
VERDI_KAFKA_AUTH_KEYTAB_PATH String Нет "" Путь до keytab-файла (в случае соединения с kafka через Kerberos).
VERDI_KAFKA_AUTH_TRUSTSTORE_LOCATION String Нет "" Путь до хранилища сертификатов (Java key store). Если путь не указан, то сертификат применяться не будет.
VERDI_KAFKA_AUTH_TRUSTSTORE_PASSWORD String Нет "" Пароль к хранилищу сертификатов.
VERDI_KAFKA_AUTH_MODE String Нет "" Режим аутентификации: static - одна учетная запись на все запросы, mapping - учетная запись зависит от запроса.
VERDI_KAFKA_AUTH_CONFIG String Нет "" Настройки для аутентификации: если AuthMode = mapping, то необходим JSON с List[KafkaAuthConfig]. Переменная соответствует полю authConfig из KafkaAuthSettings.
VERDI_KAFKA_AUTH_CACHE_SIZE Int Нет "" Максимальный размер кеша для Kafka producer (количество активных соединений).
VERDI_KAFKA_CONNECTION_CHECK_TEST_MESSAGES_INTERVAL Duration String Нет 4 minutes Применяется только для producer-ов со способом аутентификации kerberos. Интервал отправки тестовых сообщений кафки в топик connectionCheck.testMessagesTopicName. Тестовые сообщения (null, service producer test) отправляются регулярно с этим интервалом.
VERDI_KAFKA_CONNECTION_CHECK_INTERVAL Duration String Нет 60 seconds Применяется только для producer-ов со способом аутентификации kerberos. Интервал проверки того, сколько тестовых сообщений было отправлено за данный период. Если количество сообщений за этот период равно количеству сообщений за прошлый период, то начинается отсчет периода без сообщений.
VERDI_KAFKA_CONNECTION_CHECK_FAILED_AFTER_INTERVAL Duration String Нет 5 minutes Применяется только для producer-ов со способом аутентификации kerberos. Максимальная продолжительность периода без успешно отправленных тестовых сообщений. По ее достижении сервис будет объявлен больным.
VERDI_KAFKA_AUTH_CACHE_TTL Duration String Нет "" Время жизни Kafka producer в кэше.
VERDI_HOST String Да localhost Хост, публикуемый в ServiceDiscovery. По нему на данный сервис будут обращаться другие через HTTP. Указанный адрес должен быть виден другим сервисам. Пример: имя kubernetes/docker_swarm service.
VERDI_TTL Duration String Нет 30 seconds Период после последней отправки health check, в течение которого ServiceDiscovery считает данный сервис живым.
VERDI_HEALTH_CHECK Duration String Нет 10 seconds Периодичность отправки health check в ServiceDiscovery.
VERDI_COMMAND_STORAGE_UPDATE_PERIOD Duration String Нет 1 minutes Время кэширования данных по командам из CommandDiscovery.
VERDI_SERVICE_DISCOVERY_UPDATE_PERIOD Duration String Нет 30 seconds Время кэширования данных по сервисам из ServiceDiscovery.
VERDI_ALLOW_INTERNAL_COMMANDS Boolean Нет true Можно ли сервису отправлять внутрисистемные команды.
VERDI_CONSIDER_ALL_COMMANDS_AS_INTERNAL Boolean Нет false Флаг, определяющий будут ли все обращения в другие сервисы являться внутренними (т.е. не требовать авторизацию). Детальное описание механизма: Внутренние команды.
VERDI_CONSUL_CONNECTION_MAX_RETRY Int Нет 5 Максимальное количество попыток подключений к Consul.
VERDI_CONSUL_CONNECTION_RETRY_DELAY Duration String Нет 1 seconds Таймаут между неудачными попытками подключения к Consul.
VERDI_KAFKA_SYNC_POLL_PERIOD Duration String Нет 1 seconds Периодичность запроса статуса команды отправленной через Kafka.
VERDI_KAFKA_SYNC_POLL_TIMEOUT Duration String Нет 1 minute Время ожидания завершения команды отправленной через Kafka.
TECHCONSTANT_SERVICE_NAME String Нет Сервис журналирования событий Название сервиса для TechConstant.
TECHCONSTANT_SERVICE_DESC String Нет Сервис для хранения и доступа к событиям Описание сервиса для TechConstant.
TECHCONSTANT_REGISTRATION_BASEDELAY Duration String Нет 30 seconds Базовая задержка для "retry с экспоненциальной задержкой".
ELASTIC_HOST String Нет localhost Хост Elasticsearch.
ELASTIC_PORT Int Нет 9200 Порт Elasticsearch.
ELASTIC_SSL Boolean Нет false Использовать ли SSL для соединении с Elasticsearch.
ELASTIC_TRACK_TOTAL_HITS Int Нет null Управление переменной trackTotalHits в запросах к Elasticsearch. Обозначает ограничение количества документов которое будет найдено. Значение null обозначает снятие ограничения.
ELASTIC_AUTH_USER String Нет "" Название учетной записи для Elasticsearch.
ELASTIC_AUTH_PASSWORD String Нет "" Пароль учетной записи для Elasticsearch.
ELASTIC_AUTH_STORE_TYPE String Нет pem Тип хранилища сертификата для Elasticsearch.
ELASTIC_AUTH_STORE_LOCATION String Нет "" Путь до хранилища сертификата для Elasticsearch.
EVENTSTORAGE_ELASTIC_INDEX String Нет events-journal Название индекса для хранения журналов в Elasticsearch.
EVENTSTORAGE_RETENTION Duration String Нет 7 days Продолжительность хранения журналов.
EVENTSTORAGE_MEMORY_CAP String Нет 64 MB Максимальная доступная память для хранилища журналов. Необходимо для расчета процента используемой памяти. Возможные сокращения: b, kb, mb, gb.
EVENTSTORAGE_MEMORY_WARNING_PERCENT Int Нет 70 Процент используемой памяти, при котором будет сформировано событие в журнал.
EVENTSTORAGE_MEMORY_CRITICAL_PERCENT Int Нет 90 Процент используемой памяти, при котором сообщения из kafka перестанут потребляться, консьюмер будет выключен, а при EVENTSTORAGE_MAKE_ILL_ON_CRITICAL_PERCENT = true сервис будет помечен больным.
EVENTSTORAGE_MAKE_ILL_ON_CRITICAL_PERCENT Boolean Нет false Флаг, определяющий то, будет ли сервис помечен больным при достижении EVENTSTORAGE_MEMORY_CRITICAL_PERCENT.
EVENTSTORAGE_MEMORY_CHECK_DELAY Duration String Нет 10 seconds Период проверки используемой хранилищем памяти.
EVENTSTORAGE_ROLLOVER String Нет daily Периодичность создания новых индексов (т.к. нет возможности хранить все данные в одном): hourly - каждый час, daily - каждый день, weekly - каждую неделю.
EVENTSTORAGE_ROLLOVER_ENABLED Boolean Нет true Включен ли rollover для хранилища. OpenSearch не поддерживает rollover.
EVENTSTORAGE_DEFAULT_PAGE_SIZE Int Нет 10 Размер страницы по умолчанию, при выдачи списка событий.
EVENTSTORAGE_DEFAULT_SORT_FIELD String Нет eventDate Поле для сортировки по умолчанию, при выдачи списка событий.
EVENTSTORAGE_DEFAULT_SORT_ORDER String Нет Desc Направление для сортировки по умолчанию, при выдачи списка событий: Asc - "по возрастанию", Desc - "по убыванию".
EVENTSTORAGE_UPDATE_TEMPLATE_PAGE_SIZE Int Нет 1000 Количество элементов, которые запрашивает команда updateEventsTemplate на одной странице, когда выкачивает из базы события для обновления, подходящие под переданный запрос.
ENGINE_TYPE String Нет elastic Тип хранилища данных elastic или openSearch или clickhouse. Про работу с ClickHouse смотри подробнее в Особенности работы с Clickhouse.
OPEN_SEARCH_HOST String Нет localhost Хост OpenSearch.
OPEN_SEARCH_PORT Int Нет 9200 Порт OpenSearch.
OPEN_SEARCH_SSL Boolean Нет false Использовать ли SSL для соединении с OpenSearch.
OPEN_SEARCH_TRACK_TOTAL_HITS Int Нет null Управление переменной trackTotalHits в запросах к OpenSearch. Обозначает ограничение количества документов которое будет найдено. Значение null обозначает снятие ограничения.
OPEN_SEARCH_AUTH_USER String Нет "" Название учетной записи для OpenSearch.
OPEN_SEARCH_AUTH_PASSWORD String Нет "" Пароль учетной записи для OpenSearch.
OPEN_SEARCH_AUTH_STORE_TYPE String Нет pem Тип хранилища сертификата для OpenSearch.
OPEN_SEARCH_AUTH_STORE_LOCATION String Нет "" Путь до хранилища сертификата для OpenSearch.
CLICKHOUSE_HOST String Нет localhost Хост ClickHouse.
CLICKHOUSE_PORT Int Нет 8123 Порт ClickHouse.
CLICKHOUSE_DATABASE String Нет default Название базы данных в ClickHouse.
CLICKHOUSE_DISKNAME String Нет default Название используемого диска в ClickHouse.
CLICKHOUSE_AUTH_USER String Нет "" Название учетной записи для ClickHouse. Всегда требуется при использовании ENGINE_TYPE = "clickhouse". Сервис не поддерживает работу с ClickHouse, в котором отсутствует аутентификация. (Всегда должен быть логин и пароль).
CLICKHOUSE_AUTH_PASSWORD String Нет "" Пароль учетной записи для ClickHouse. Всегда требуется при использовании ENGINE_TYPE = "clickhouse". Сервис не поддерживает работу с ClickHouse, в котором отсутствует аутентификация. (Всегда должен быть логин и пароль).
CLICKHOUSE_RETRIES Int Нет 3 Количество ретраев при отправке запросов в ClickHouse.
CLICKHOUSE_RESPONSE_TIMEOUT Duration String Нет 1 second Время ожидания ответа от ClickHouse.
CLICKHOUSE_QUEUE_SIZE Int Нет 1024 Максимальный размер внутренней очереди запросов к ClickHouse.
CLICKHOUSE_FRAME_MAX_SIZE Int Нет 1048576 Максимальный размер одной строки при запросе данных от ClickHouse.
CLICKHOUSE_CLUSTER String Нет cluster Название используемого кластера ClickHouse.
CLICKHOUSE_CONNECT_TYPE String Нет cluster-aware Название режима подключения к ClickHouse.
CLICKHOUSE_CONNECT_HEALTH_INTERVAL Duration String Нет 10 seconds Минимальное время между 2 проверками работоспособности на одном хосте.
CLICKHOUSE_CONNECT_HEALTH_TIMEOUT Duration String Нет 1 seconds Максимальный тайм-аут простоя соединения для проверки работоспособности.
CLICKHOUSE_CONNECT_SCANNING_INTERVAL Duration String Нет 60 seconds Интервал между запросами в таблице кластеров для обновления хостов кластера клиентов.
CLICKHOUSE_CONNECT_FALLBACK_CONFIG Boolean Нет false Откат к хосту из конфигурации при инициализации.
CLICKHOUSE_HTTP_COMPRESSION Boolean Нет false Использовать ли сжатие при отправке по HTTP.
VERDI_COMMANDS_HTTP_RETRY_ATTEMPTS Int Нет 5 Поле attempts из RetrySettings.
VERDI_COMMANDS_HTTP_RETRY_DELAY Duration String Нет 5 seconds Поле delay из RetrySettings.
VERDI_COMMANDS_HTTP_RETRY_KIND String Нет OnSomeExceptions(ConnectException) CommandResultRetryConditionKind.
SERVER_AUTHORIZER_KIND String Нет authzforce Вид авторизатора, который используется в сервисе. Допустимые значения: authzforce, oberto. При указании неизвестного значения будет использовано значение по-умолчанию.
AUTHZFORCE_ADDR String Нет http://localhost:8080/authzforce-ce Адрес AuthZforce server (переменная должна быть непустой, если SERVER_AUTHORIZER_KIND="authzforce").
AUTHZFORCE_DOMAIN String Нет "" Доступный DomainID в AuthZforce server (переменная должна быть непустой, если SERVER_AUTHORIZER_KIND="authzforce").
AUTHZFORCE_CONNECT_TIMEOUT Duration String Нет 5 seconds Таймаут подключения к authzforce (переменная должна быть непустой, если SERVER_AUTHORIZER_KIND="authzforce").

Команды сервиса Nestor

Список реализованных в сервисе команд, моделей EntityType и действий Actions, которые можно использовать при настройке авторизации.
Не все поля EntityType доступны для использования в настройке авторизации.
Если указан прочерк "-", то данное значение не влияет на авторизацию:

Назначение команды Название команды EntityType Actions
Поиск событий searchEvents Event SearchEvents
Создание события createEvent - -
Получение события getEvent Event GetEvent
Обновление поля renderedData у событий updateEventsTemplate Event Update

UpdateEventsTemplate (Nestor)

На входе объект Search с фильтрами для получения списка событий, поле renderedData в которых нужно обновить (поля sorting и paging при поиске учитываться не будут)

{
  "query": "",
  "context": {},
  "sorting": {
    "fieldName": "title",
    "order": "asc"
  },
  "paging": {
    "page": 1,
    "count": 10
  }
}

На выходе объект со статистикой того, сколько успешных и неуспешных обновлений поля renderedData произошло для каждого конкретного eventType (results), а также того сколько событий не было обработано из-за ошибки их получения(unhandledEvents)

{
  "unhandledEvents": 10,
  "results": {
    "createDataModel": {
      "updated": 123,
      "errors": 1,
      "templateErrors": 1
    },
    "postmanTestEventType": {
      "updated": 11,
      "errors": 0,
      "templateErrors": 4
    }
  }
}

Обновляет поле renderedData у всех событий, подходящих под критерии поиска, на основе значений из поля data и шаблона При этом sorting и paging при поиске не учитываются. Во время исполнения команды все подходящие под фильтры события вычитаются постранично последовательными запросами. При этом размер страницы, который будет получен в одном конкретном запросе будет равен значению переменной EVENTSTORAGE_UPDATE_TEMPLATE_PAGE_SIZE.

Запрос принимает параметры фильтров в параметре Search.

Доступные поля для фильтрации и виды фильтров по ним:

Поле Виды фильтров Регистронезависимость
id InSetQuery только для ASCII-символов
eventDate InSetQuery, RangeQuery только для ASCII-символов
storeDate InSetQuery, RangeQuery только для ASCII-символов
eventType InSetQuery, LikeQuery только для ASCII-символов
userId InSetQuery, LikeQuery только для ASCII-символов
eventCategory InSetQuery, LikeQuery только для ASCII-символов
application InSetQuery, LikeQuery только для ASCII-символов
data InSetQuery, LikeQuery, TsQuery при использовании openSearch и elasticSearch; InSetQuery, LikeQuery, TsQuery при использовании Clickhouse полная
renderedData LikeQuery, TsQuery при использовании openSearch и elasticSearch; InSetQuery, LikeQuery при использовании Clickhouse полная
dependencies.entityClass InSetQuery, AllInSetQuery, LikeQuery только для ASCII-символов
dependencies.entityId InSetQuery, AllInSetQuery, LikeQuery только для ASCII-символов
dependencies.dependencyType InSetQuery, AllInSetQuery, LikeQuery только для ASCII-символов

Маппинг фильтров nestor в запросы elasticSearch/openSearch и clickhouse аналогичен маппингу описанному для команды searchEvents

Имя команды для вызова: updateEventsTemplate.
Поддерживается синхронный и асинхронный вызов.
Результат выполнения команды журналируется.

CreateEvent (Nestor)

На входе данные нового события

{
  "eventDate": 1683901401795,
  "eventType": "journalDeleteGroup",
  "userId": "0e7c15e6-2a7b-46c2-8571-d9dc9d6e3726",
  "eventCategory": "Success",
  "application": "Mon",
  "data": "{\"eventType\":\"journalDeleteGroup\",\"payload\":\"CODECODE\",\"result\":true,\"data\":\"Наименование наименование\"}",
  "dependencies": []
}

На выходе сообщение об успешности выполнения команды

{
  "result": "success"
}

Сохраняет новое событие в журнале.

Имя вызова команды: createEvent.
Поддерживается асинхронный и синхронный вызов.
Результат выполнения команды не журналируется.

Команда только внутренняя (нельзя вызвать через Api Gateway), не требует аутентификации.

GetEvent (Nestor)

На входе JSON-объект с ID запрашиваемого события

{
  "id": "42883340-f2cd-4eac-92ca-36ef46d4d038"
}

На выходе данные запрашиваемого события

{
  "id": "42883340-f2cd-4eac-92ca-36ef46d4d038",
  "eventDate": 1683901401795,
  "storeDate": 1683901411816,
  "eventType": "journalDeleteGroup",
  "userId": "0e7c15e6-2a7b-46c2-8571-d9dc9d6e3726",
  "eventCategory": "Success",
  "application": "Mon",
  "data": "{\"eventType\":\"journalDeleteGroup\",\"payload\":\"CODECODE\",\"result\":true,\"data\":\"Наименование наименование\"}",
  "dependencies": []
}

Получение события по его ID.

Имя вызова команды: getEvent.
Поддерживается только синхронный вызов.
Результат выполнения команды не журналируется.

SearchEvents (Nestor)

На входе параметры поиска событий

{
  "query": "eventType",
  "context": {
    "eventType": {
      "kind": "any",
      "values": [
        "importCatalogs",
        "journalDeleteGroup"
      ]
    }
  },
  "sorting": {
    "fieldName": "eventDate",
    "order": "Desc"
  },
  "paging": {
    "page": 1,
    "count": 2
  }
}

На выходе результат поиска

{
  "items": [
    {
      "id": "42883340-f2cd-4eac-92ca-36ef46d4d038",
      "eventDate": 1683901401795,
      "storeDate": 1683901411816,
      "eventType": "journalDeleteGroup",
      "userId": "0e7c15e6-2a7b-46c2-8571-d9dc9d6e3726",
      "eventCategory": "Success",
      "application": "Mon",
      "data": "{\"eventType\":\"journalDeleteGroup\",\"payload\":\"CODECODE\",\"result\":true,\"data\":\"Наименование наименование\"}",
      "renderedData": "Была удалена группа пользователей \"Наименование наименование\" с кодом \"CODECODE\"",
      "dependencies": []
    },
    {
      "id": "881b3ffa-6273-44ed-a798-08e75959a644",
      "eventDate": 1682515867969,
      "storeDate": 1682515877987,
      "eventType": "journalDeleteGroup",
      "userId": "d5b8f850-1af6-4f94-82ef-fe304bb90618",
      "eventCategory": "Success",
      "application": "Mon",
      "data": "{\"eventType\":\"journalDeleteGroup\",\"payload\":\"Test1\",\"result\":true,\"data\":\"Тестовая 1\"}",
      "renderedData": "Была удалена группа пользователей \"Тестовая 1\" с кодом \"Test1\"",
      "dependencies": []
    }
  ],
  "total": 206
}

Возвращает список событий, подходящих под критерии поиска и пагинации.

Доступные поля для фильтрации и виды фильтров по ним:

Поле Виды фильтров Регистронезависимость
id InSetQuery только для ASCII-символов
eventDate InSetQuery, RangeQuery только для ASCII-символов
storeDate InSetQuery, RangeQuery только для ASCII-символов
eventType InSetQuery, LikeQuery только для ASCII-символов
userId InSetQuery, LikeQuery только для ASCII-символов
eventCategory InSetQuery, LikeQuery только для ASCII-символов
application InSetQuery, LikeQuery только для ASCII-символов
data InSetQuery, LikeQuery, TsQuery при использовании openSearch и elasticSearch; InSetQuery, LikeQuery, TsQuery при использовании Clickhouse полная
renderedData LikeQuery, TsQuery при использовании openSearch и elasticSearch; InSetQuery, LikeQuery при использовании Clickhouse полная
dependencies.entityClass InSetQuery, AllInSetQuery, LikeQuery только для ASCII-символов
dependencies.entityId InSetQuery, AllInSetQuery, LikeQuery только для ASCII-символов
dependencies.dependencyType InSetQuery, AllInSetQuery, LikeQuery только для ASCII-символов

Маппинг фильтров nestor в запросы elasticSearch/openSearch и clickhouse:

Фильтр Запрос к nestor Запрос elasticSearch/openSearch Запрос к clickhouse
InSetQuery("value1", "value2") {"query": "fieldName", "context" : {"fieldName": {"kind": "any","values": ["value1", "value2"]}} {"query" : {"bool" : { "should" : [{"term" : {"fieldName" : {"value" : "value1", "case_insensitive": true}}}, {"term" : {"fieldName" : {"value" : "value2", , "case_insensitive": true}}}] }}} select * from journal where lowerUTF8(fieldName) in ('value1', 'value2')
LikeQuery("value1") {"query": "fieldName", "context" : {"fieldName": "like value1"}} {"query" : {"term" : {"fieldName" : {"value" : "value1", "case_insensitive": true}}}} select * from journal where fieldName ilike 'value1'
LikeQuery("%value1") {"query": "fieldName", "context" : {"fieldName": "like %value1"}} {"query" : {"regexp" : {"fieldName" : {"value" :".value1", "case_insensitive": true}}}} select * from journal where fieldName ilike '%value1'
LikeQuery("__value1") {"query": "fieldName", "context" : {"fieldName": "like __value1"}} {"query" : {"regexp" : {"fieldName" : {"value" :".{2}value1", "case_insensitive": true}}}} select * from journal where fieldName ilike '__value1'
RangeQuery(1, 4) {"query": "fieldName", "context" : {"fieldName": "1_4"}} {"query" : {"range" : {"fieldName" : {"gte" : 1, "lte" : 2}}}} select * from journal where fieldName >= 1 and fieldName =< 4
AllInSetQuery("value1", "value2") (для полей объектов массива) {"query": "arrayFieldName.objectFieldName", "context" : {"arrayFieldName.objectFieldName": {"kind": "all","values": ["value1", "value2"]}}} {"query" : {"bool" : {"must" : [{"nested": {"path": "arrayFieldName", "query": {"term" : {"arrayFieldName.objectFieldName" : {"value" : "value1", "case_insensitive": true}}} }}, {"nested": {"path": "arrayFieldName", "query": {"term" : {"arrayFieldName.objectFieldName" : {"value" : "value2", "case_insensitive": true}}} }}] }}} select * from journal where arrayExist(element -> lowerUTF8(element) in ('value1', 'value2'), arrayFieldName.objectFieldName)
TsQuery("b + c - e * d & f: j ! h") {"query": "fieldName", "context" : {"fieldName": "ts b + c - e * d & f:* j ! h"}} {"query": {"simple_query_string": {"query": "b\+ c \- e \* d + f* j - h", "flags": "OR|AND|PREFIX|NOT|PRECEDENCE|WHITESPACE|ESCAPE|PHRASE", "fields": ["fieldName"]}}} -

Доступные поля для сортировки:

Поле Примечание
id -
eventDate -
storeDate -
eventType -
userId -
eventCategory -
application -
dependencies.entityClass -
dependencies.entityId -
dependencies.dependencyType -

Если поле sorting отсутствует, то список сортируется согласно соответствующей конфигурации сервиса (см. параметры EVENTSTORAGE_DEFAULT_SORT_FIELD и EVENTSTORAGE_DEFAULT_SORT_ORDER)

Если поле paging отсутствует, то в paging.page устанавливается 1, а в paging.count используется значение из переменной окружения EVENTSTORAGE_DEFAULT_PAGE_SIZE.

Имя вызова команды: searchEvents.
Поддерживается только синхронный вызов.
Результат выполнения команды не журналируется.

Модели сервиса Nestor

UpdateEventsTemplateResult (Nestor)

Поле Тип Обязательное Описание
unhandledEvents Int да Количество событий, которые не были обработаны из-за ошибки их получения
results Map[String, UpdateEventsTemplateStats] да Результаты обновления событий, которые были получены, сгруппированные по типам событий

UpdateEventsTemplateStats (Nestor)

Поле Тип Обязательное Описание
updated Int да Количество успешно обновленных событий
errors Int да Количество событий, обновление которых завершилось с ошибкой
templateErrors Int да Количество событий, обновление которых завершилось с ошибкой шаблона. К ошибкам шаблона относятся: отсутствие константы, отсутствие шаблона, исключения во время применения шаблона

Dependency (Nestor)

Поле Тип Обязательное Описание
entityClass String Да Класс зависимости
entityId String Да Идентификатор зависимости
dependencyType String Да Тип зависимости
case class Dependency(entityClass: String, entityId: String, dependencyType: String)

NewEvent (Nestor)

Поле Тип Обязательное Описание
eventDate Long Да Дата события
eventType String Да Тип события
userId UUID Да Идентификатор связанного с событием пользователя
eventCategory String Да Статус события
application String Да Идентификатор связанного с событием приложения
data String Да Данные события
dependencies List[Dependency] Да Иные связанные с событием сущности Dependency
case class NewEvent(
                     eventDate: Long,
                     eventType: String,
                     userId: String,
                     eventCategory: String,
                     application: String,
                     data: String,
                     dependencies: List[Dependency]
                   )

Event (Nestor)

Поле Тип Обязательное Описание
id UUID Да Идентификатор события
eventDate TimeStamp Да Дата события
storeDate TimeStamp Да Дата сохранения события
eventType String Да Тип события
userId UUID Да Идентификатор связанного с событием пользователя
eventCategory String Да Статус события
application String Да Идентификатор связанного с событием приложения
data String Да Данные события
renderedData String Да Текст с результатом применения шаблона к данным события
dependencies List[Dependency] Да Иные связанные с событием сущности Dependency
case class Event(
                  id: UUID,
                  eventDate: Long,
                  storeDate: Long,
                  eventType: String,
                  userId: String,
                  eventCategory: String,
                  application: String,
                  data: String,
                  dependencies: List[Dependency]
                )

Особенности работы с Clickhouse

Начиная с версии rc3.1.0 для работы с Clickhouse используется тип таблицы ReplicatedMergeTree. Для успешного функционирования сервиса с таким типом таблиц даже при использовании clickhouse, который содержит в себе только одну ноду, нужно обязательно иметь на стенде ноду Zookeeper или Clickhouse Keeper, настроенную для взаимодействия с нодой clickhouse как с кластером.

Oberto-client: клиент для сервиса Oberto

Библиотека предоставляет интерфейс и реализацию клиента для сервиса Oberto.

Пример создания Oberto-client

Пример внедрения зависимости:

make[ObertoClient[F]].from {
  (
    dispatcher: Dispatcher,
    fromFuture: FromFuture[F],
    executionContext: ExecutionContext
  ) =>
    implicit val ff: FromFuture[F] = fromFuture
    implicit val ec: ExecutionContext = executionContext

    new LiveObertoClient[F](dispatcher)
}

Для регистрации клиента на Future следует использовать метод makeFutureBased объекта ObertoClient:

make[ObertoClient[Future]].from {
  (
    dispatcher: Dispatcher,
    executionContext: ExecutionContext
  ) =>
    implicit val ec: ExecutionContext = executionContext

    ObertoClient.makeFutureBased(dispatcher)
}

Для того чтобы использовать библиотеку oberto-client, нужно добавить зависимость "com.embedika.verdi" %% "oberto-client" % verdiVersion.

Все классы находятся в пакетах с корнем com.embedika.verdi.oberto.

Основной интерфейс для взаимодействия ObertoClient[F[_]].

Реализация интерфейса LiveObertoClient[F[_]: Monad: FromFuture].

Предоставляемый функционал Oberto-client

Oberto-client предоставляет методы вызова соответствующих команд сервиса Oberto. Формат входных и выходных данных методов Oberto-client аналогичен формату входных и выходных данных команд сервиса Oberto.

Получение политик

Добавление или обновление политик

Удаление политик

Авторизация действий

Oberto: сервис системы прав

Сервис отвечает за редактирование правил доступа к различным ресурсам и проверку доступности пользователей к ресурсам. Команды могут приходить только по HTTP.

Проект сервиса содержит несколько директорий:

В сервисе реализованы следующие команды (все команды "синхронные"):

Локальный запуск сервиса Oberto

При запуске сервиса ожидается, что уже развернута необходимая инфраструктура:

Запуск Oberto из консоли с помощью SBT

sbt run

Список всех переменных окружения для сервиса Oberto

Переменная Тип Обязательная Значение по умолчанию Описание
OBERTO_HTTP_HOST string Нет 0.0.0.0 Хост для HttpListener.
OBERTO_HTTP_PORT int Нет 8192 Порт для HttpListener.
OBERTO_KAFKA_SERVERS string Да localhost:9092 Адрес Kafka.
OBERTO_KAFKA_TOPIC string Нет OBERTO_commands Название топика для входящих команд.
OBERTO_KAFKA_COMMANDEVENT_TOPIC string Нет commandevents Название топика для входящих/исходящих событий.
OBERTO_KAFKA_CONSUMER_GROUP string Нет "" Название группы для чтения топика событий.
OBERTO_KAFKA_CONSUMER_POLL_TIMEOUT duration string нет 10 milliseconds timeout запроса poll для kafka consumer
OBERTO_KAFKA_CONSUMER_POLL_INTERVAL duration string нет 100 milliseconds интервал между запросами poll для kafka consumer
OBERTO_KAFKA_CONSUMER_PROPS string нет "max.poll.records=500;max.partition.fetch.bytes=524288" дополнительные параметры для kafka consumer в формате "key1=value1;key2=value2"
OBERTO_KAFKA_AUTH_USER string Нет "" Название учетной записи Kafka. Если название не указано, то настройки авторизации не будут применены.
OBERTO_KAFKA_AUTH_PASSWORD string Нет "" Пароль учетной записи Kafka.
OBERTO_KAFKA_AUTH_PRINCIPAL string Нет "" Principal учетной записи Kafka в Kerberos(в случае соединения с kafka через Kerberos).
OBERTO_KAFKA_AUTH_KEYTAB_PATH string Нет "" Путь до keytab-файла (в случае соединения с kafka через Kerberos).
OBERTO_KAFKA_AUTH_TRUSTSTORE_LOCATION string Нет "" Путь до хранилища сертификатов (Java key store). Если путь не указан, то сертификат применяться не будет.
OBERTO_KAFKA_AUTH_TRUSTSTORE_PASSWORD string Нет "" Пароль к хранилищу сертификатов.
OBERTO_KAFKA_AUTH_MODE string Нет static Режим аутентификации: static - одна учетная запись на все запросы, mapping - учетная запись зависит от запроса.
OBERTO_KAFKA_AUTH_CONFIG string Нет "" Настройки для аутентификации: если AuthMode = mapping, то необходим JSON с List[KafkaAuthConfig]. Переменная соответствует полю authConfig из KafkaAuthSettings.
OBERTO_KAFKA_AUTH_CACHE_SIZE long Нет Максимальный размер кеша для Kafka producer (количество активных соединений).
OBERTO_KAFKA_CONNECTION_CHECK_TEST_MESSAGES_INTERVAL duration string Нет 4 minutes Применяется только для producer-ов со способом аутентификации kerberos. Интервал отправки тестовых сообщений кафки в топик connectionCheck.testMessagesTopicName. Тестовые сообщения (null, service producer test) отправляются регулярно с этим интервалом.
OBERTO_KAFKA_CONNECTION_CHECK_INTERVAL duration string Нет 60 seconds Применяется только для producer-ов со способом аутентификации kerberos. Интервал проверки того, сколько тестовых сообщений было отправлено за данный период. Если количество сообщений за этот период равно количеству сообщений за прошлый период, то начинается отсчет периода без сообщений.
OBERTO_KAFKA_CONNECTION_CHECK_FAILED_AFTER_INTERVAL duration string Нет 5 minutes Применяется только для producer-ов со способом аутентификации kerberos. Максимальная продолжительность периода без успешно отправленных тестовых сообщений. По ее достижении сервис будет объявлен больным.
OBERTO_KAFKA_AUTH_CACHE_TTL duration string Нет Время жизни Kafka producer в кеше.
OBERTO_CONSUL_ADDR string Да http://localhost:8500 Адрес Сonsul.
OBERTO_CONSUL_AUTH_USER string Нет "" Название учетной записи Сonsul. Если название не указано, то настройки авторизации не будут применены.
OBERTO_CONSUL_AUTH_PASSWORD string Нет "" Пароль учетной записи Сonsul.
OBERTO_TRACE_DURATION boolean Нет false Нужно ли логировать длительность выполнения команд.
OBERTO_DISCOVERABLE_ID string Нет another_oberto_instance ID данного сервиса.
OBERTO_DISCOVERABLE_NAME string Да oberto Название группы сервисов, к которой принадлежит данный.
OBERTO_DISCOVERABLE_HOST string Нет localhost Адрес текущего инстанса сервиса, который будет виден через ServiceDiscovery.
OBERTO_DISCOVERABLE_PORT int Нет ${OBERTO_HTTP_PORT} Адрес текущего инстанса сервиса, который будет виден через ServiceDiscovery.
OBERTO_DISCOVERABLE_LIVETIME duration string Нет 2 minutes Время с последнего HeathCheck, в течении которого сервис считается "живым".
OBERTO_DISCOVERABLE_HEALTHPASS duration string Нет 1 minute Периодичность отправки HeathCheck.
OBERTO_INTERNALCMD_ALLOW boolean Нет true Можно ли сервису отправлять "внутренние" команды.
OBERTO_SENDERLIB_CONSIDER_ALL_COMMANDS_AS_INTERNAL boolean Нет false Флаг, определяющий будут ли все обращения в другие сервисы являться внутренними (т.е. не требовать авторизацию). Детальное описание механизма: Внутренние команды.
OBERTO_SENDERLIB_COMMANDS_CACHE_UPDATEPERIOD duration string Нет 10 minutes Время, на которое будут кешироваться данные о командах.
OBERTO_SENDERLIB_SERVICES_CACHE_UPDATEPERIOD duration string Нет 30 seconds Время, на которое будут кешироваться данные о сервисах.
OBERTO_AUTHZFORCE_ENABLE boolean Нет false Включены ли команды/функции связанные с AuthZforce server.
OBERTO_AUTHZFORCE_ADDR string Да http://localhost:8080/authzforce-ce Адрес AuthZforce server.
OBERTO_AUTHZFORCE_DOMAIN string Нет not defined Доступный DomainID в AuthZforce server.
OBERTO_AUTHZFORCE_DEFAULT string Нет deny Поведение контроля доступа по умолчанию: deny - все запрещено, пока не будет получено разрешение; permit - все разрешено, пока не будет получен запрет.
OBERTO_AUTHZFORCE_PREFER_RULE string Нет deny Выбор приоритета для правил: deny - при наличии двух и более применяемых правил для запроса авторизации, приоритет отдается первому запрещающему правилу; permit - в случае нескольких применяемых правил, приоритет отдается первому разрешающему правилу.
OBERTO_AUTHZFORCE_PROVIDER_TYPE string Нет "" Тип AttributeProvider, который используется в Authzforce server (указан в его конфиге). Указывается в случае, если нужно работать с AttributeProvider из сервиса Oberto.
OBERTO_AUTHZFORCE_PROVIDER_ID string Нет "" Идентификатор AttributeProvider, который используется в Authzforce server (указан в его конфиге). Указывается в случае, если нужно работать с AttributeProvider из сервиса Oberto.
OBERTO_AUTHZFORCE_DEBUG_RETURN_POLICY_ID boolean Нет false Добавлять ли в ответ от Authzforce список политик, которые учитывались при расчете ответа.
OBERTO_AUTHZFORCE_ATTRIBUTES_CACHE_SIZE long Нет 1000 Максимальный размер кеша атрибутов для локального AttributeProvider, который используется в Oberto.
OBERTO_AUTHZFORCE_ATTRIBUTES_CACHE_TTL duration string Нет 5 minutes Максимальное время кеширования атрибутов для локального AttributeProvider, который используется в Oberto.
OBERTO_AUTHZFORCE_ATTRIBUTES_REQUEST_TIMEOUT duration string Нет 30 seconds Максимальное время ожидания завершения запроса атрибутов из сервиса data-model для локального AttributeProvider, который используется в Oberto.
OBERTO_AUTHZFORCE_ATTRIBUTES_CMD_MAPPING string Нет "" Список префиксов атрибутов и связанных с ними команд. Отображение 1 к 1. Требуется особый формат.
OBERTO_AUTHZFORCE_POLICIES_REQUEST_TIMEOUT duration string Нет 30 seconds Максимальное время ожидания завершения запроса политики для локального PolicyProvider, который используется в Oberto.
OBERTO_AUTHZFORCE_POLICIES_REF_DEPTH int Нет 10 Максимальная глубина вложенных ссылок на политики.
OBERTO_AUTHZFORCE_POLICIES_MAX_VERSIONS int Нет 10 Максимальное количество версий для одной политики.
OBERTO_AUTHZFORCE_POLICIES_CLEAN_PERIOD duration string Нет 10 minutes Период проверки списка политик для удаления версий, которые превышают лимит OBERTO_AUTHZFORCE_POLICIES_MAX_VERSIONS.
OBERTO_AUTHZFORCE_POLICIES_DENY_BY_DEFAULT boolean Нет true Поведение по умолчанию: запрещено ли действие, если оно явно не регулируется.
OBERTO_AUTHZFORCE_POLICIES_COMBINE_ALG string Нет urn:oasis:names:tc:xacml:1.0:policy-combining-algorithm:first-applicable Идентификатор алгоритма для комбинации политик.
OBERTO_DEBUGMODE boolean Нет false Режим отладки, в котором можно редактировать политики без проверки наличия прав.
OBERTO_READABLE_NAME string Нет Сервис системы прав Читаемое название этого сервиса.
OBERTO_DESCRIPTION string Нет Сервис системы прав Читаемое описание этого сервиса.
OBERTO_DB_URL jdbc url string Нет "jdbc:postgresql://"${?OBERTO_DB_HOST}":"${?OBERTO_DB_PORT}"/"${?OBERTO_DB_NAME} Адрес базы данных. Можно использовать вместо DB_HOST, DB_PORT и DB_NAME.
OBERTO_DB_HOST string Да Хост сервера базы данных.
OBERTO_DB_PORT int Да Порт сервера базы данных.
OBERTO_DB_NAME string Да Название базы данных.
OBERTO_DB_USER string Да Пользователь базы данных.
OBERTO_DB_PASSWORD string Да Пароль для пользователя базы данных.
OBERTO_DB_THREADS int Нет 10 Количество потоков в пуле потоков для соединения с БД.
OBERTO_DB_QUEUE_SIZE int Нет 300 Размер очереди для действий базы данных, которые не могут быть выполнены немедленно, когда все потоки заняты. За пределами этого значения новые действия немедленно завершаются неудачей.
OBERTO_DB_CONN_MAX int Нет 10 Максимальное количество одновременных подключений к БД.
OBERTO_DB_CONN_TIMEOUT duration string Нет 20 second Максимальное время ожидания ответа для соединения к БД. Если это время превышено, а соединение не становится доступным, будет брошено исключение SQLException. 1000 мс — минимальное значение.
OBERTO_DB_ISOLATION string Нет READ_COMMITTED Уровень изоляции транзакций для новых подключений. Допустимые значения: NONE, READ_COMMITTED, READ_UNCOMMITTED, REPEATABLE_READ, SERIALIZABLE.
OBERTO_DB_READONLY boolean Нет false Read-only SQL транзакция может изменять только временные таблицы. Этот параметр управляет статусом «только для чтения» по умолчанию для каждой новой транзакции.
OBERTO_DB_CONN_MIN int Нет ${OBERTO_DB_THREADS} Минимальное количество одновременных подключений к БД.
OBERTO_DB_VALIDATION_TIMEOUT duration string Нет 1 seconds Максимальное время, в течение которого соединение будет проверяться на работоспособность. 1000 мс — минимальное значение.
OBERTO_DB_IDLE_TIMEOUT duration string Нет 10 minutes Максимальное время, в течение которого соединению разрешено простаивать в пуле. Значение 0 означает, что простаивающие соединения никогда не удаляются из пула.
OBERTO_DB_MAX_LIFETIME duration string Нет 30 minutes Максимальное время жизни соединения в пуле. Когда простаивающее соединение достигает этого времени ожидания, даже если оно недавно использовалось, оно будет удалено из пула. Значение 0 указывает на отсутствие максимального срока службы.
OBERTO_DB_INITIALIZATION_FAIL_FAST boolean Нет false Deprecated, начиная с версии Slick 3.3.0. Определяет, будет ли пул «быстро выходить из строя», если пул не может быть успешно заполнен начальными соединениями. Если соединения не могут быть созданы во время запуска пула, будет выдано исключение RuntimeException. Это свойство не имеет никакого эффекта, если minConnections равно 0.
OBERTO_DB_LEAK_DETECTION_THRESHOLD int Нет 0 Время, в течение которого соединение может находиться вне пула, прежде чем будет зарегистрировано сообщение, указывающее на возможную утечку соединения. Значение 0 означает, что обнаружение утечек отключено. Наименьшее приемлемое значение для включения обнаружения утечек составляет 10 с.
OBERTO_DB_CONNECTION_TEST_QUERY string Нет SELECT 1 Выражение, которое будет выполнено непосредственно перед получением соединения из пула для проверки того, что соединение с базой данных все еще активно. Оно зависит от базы данных и должно представлять собой запрос, требующий минимальной обработки базой данных (например, «VALUES 1»). Если этот параметр не установлен, вместо него используется метод JDBC4 Connection.isValid().
OBERTO_DB_AUTO_COMMIT boolean Нет true Это свойство определяет то, как будут вести себя по умолчанию возвращаемые соединения относительно autocommit-а.
OBERTO_DB_SCHEMA string Нет public Устанавливает schema по умолчанию.
OBERTO_DB_ISOLATE_INTERNAL_QUERIES boolean Нет false Определяет то, изолируются ли с помощью транзакций внутренние запросы пула (например запрос connection alive test). Свойство применяется только если autoCommit выключен.
OBERTO_DB_INITIALIZATION_FAIL_TIMEOUT int Нет 1 Работает, начиная с версии Slick 3.3.0. Определяет, будет ли пул «быстро выходить из строя», если пул не может быть успешно заполнен начальными соединениями. Любое положительное число считается числом миллисекунд для попытки получить начальное соединение; поток приложения будет заблокирован в течение этого периода. Если соединение не может быть получено до истечения этого времени, будет брошено исключение. Данный таймаут применяется после периода connectionTimeout. Если значение равно нулю (0), HikariCP попытается получить и проверить подключение. Если соединение получено, но проверка не пройдена, будет брошено исключение, и пул не будет запущен. Однако, если соединение не может быть получено, пул запустится, но последующие попытки получить соединение могут потерпеть неудачу. Значение меньше нуля пройдет любую первоначальную попытку подключения, и пул немедленно запустится, пытаясь получить соединения в фоновом режиме. Следовательно, последующие попытки получить соединение могут потерпеть неудачу.
OBERTO_DB_REGISTER_MBEANS boolean Нет false Зарегистрированы ли JMX Management Beans («MBeans»).
OBERTO_SENDERLIB_COMMANDS_HTTP_RETRY_ATTEMPTS int Нет 5 Поле attempts из RetrySettings.
OBERTO_SENDERLIB_COMMANDS_HTTP_RETRY_DELAY duration string Нет 5 seconds Поле delay из RetrySettings.
OBERTO_SENDERLIB_COMMANDS_HTTP_RETRY_KIND string Нет OnSomeExceptions(ConnectException) CommandResultRetryConditionKind.
OBERTO_SENDERLIB_CONSUL_CONNECTION_RETRY_MAX int нет 5 Количество попыток переподключения к Consul
OBERTO_SENDERLIB_CONSUL_CONNECTION_RETRY_DELAY duration string нет 1 second Задержка при попытках переподключения к Consul
OBERTO_LICENSE_PATH string Да "" Путь до файла с лицензией (только binary format). Данная переменная обязательна для работы.
OBERTO_LICENSE_KEY string Да "" Путь до файла с публичным ключом лицензией. Данная переменная обязательна для работы.
OBERTO_JOURNAL_MODE string нет WriteToJournal Режим журналирования Nestor. Допустимые значения: WriteToJournal (Отправка в сервис журналирования), WriteToTopic (Отправка события в очередь)
OBERTO_JOURNAL_TOPIC string Да, если переменная OBERTO_JOURNAL_MODE = WriteToTopic "" Название очереди журналирования. Для режима WriteToJournal значение игнорируется.
OBERTO_LICENSE_PATH_PRIORITY string Нет "" Порядок использования лицензий. При пустом значении - порядок будет соответствовать порядку путей до файлов лицензий (OBERTO_LICENSE_PATH). Строка должна содержать приоритет для каждой лицензии, приоритеты разделяются запятой (например, 1,5,2) - лицензии будут обрабатываться в порядке возрастания приоритета.

Режим отладки (debug mode)

Режим отладки нужен для того, чтобы добавить/удалить/изменить политики без наличия на это прав. Например, когда политики настроены неверно и пропал доступ к редактированию самих политик.
Также этот режим может быть полезен при первоначальной настройке. При разворачивании сервиса, в нем присутствует политика, которая разрешает все действия "permit-all", но пока не будет добавлена какая-либо политика. Этот режим поможет избежать ситуации, когда политика, разрешающая редактирование политик, не была добавлена первой.

Режим отладки включается установкой переменной окружения OBERTO_DEBUGMODE=true.

Политики по умолчанию

При каждом запуске сервис Oberto проверят доступные хранилища политик на возможность создать политики по умолчанию.
Политиками по умолчанию являются:

Внешние AttributeProvider

Сервис Oberto, в добавок к стандартному DataModel, умеет работать с внешними AttributeProvider-ами, которые используются при проверке правил доступа к ресурсу.
AttributeProvider-ы нужны для получения атрибутов, которые используются в правиле, но не были переданы в запросе авторизации AuthorizationRequestDTO.

Пример:

В итоге, в момент проверки правила у нас есть следующие атрибуты:

Неизвестный атрибут datamodel.MyDocument.authorId будет передан PdpEngine-ом (authzforce) в общий атрибут провайдер сервиса Oberto.

Процесс обработки запроса общим провайдером атрибутов

Все атрибуты должны соответствовать паттернам: либо ServiceName.Resource.PathToField либо Resource.PathToField.
Все сервисы (ServiceName) должны быть в маппинге сервис-команда (переменная OBERTO_AUTHZFORCE_ATTRIBUTES_CMD_MAPPING).

  1. Атрибут проверяется на соответствие паттернам
  2. Если в названии атрибута присутствует ServiceName, то происходит попытка поиска команды из маппинга
  3. Отправка запроса
    1. Если команда найдена в маппинге, то отправляется запрос с телом AttributeRequest
    2. Если команда не найдена, то отправляется запрос в сервис data-model: internalGetObject (обычное поле) или internalRichGetObject (поле связанного объекта).
  4. При возможности, ответ от внешнего сервиса кешируется (зависит от настроек )
  5. После получения ответа от внешнего сервиса, ответ преобразуется в AttributeResponse
  6. общий провайдер атрибутов в Oberto извлекает из AttributeResponse поле value, чтобы вернуть его в PdpEngine (authzforce)

К внешним AttributeProvider-ам предъявляются следующие требования:

Возможные ошибки

Ресурс не найден

{
  "code": {
    "statusCode": 404
  },
  "message": "ERROR: Entity object not found",
  "stackTrace": null,
  "businessError": null,
  "data": null
}

Внешний провайдер должен вернуть
ErrorResponse(code = ErrorResponseCode.HttpError(404), message = Some("ERROR: Entity object not found"))

Запрашиваемое поле не найдено в ресурсе / несоответствие схеме

{
  "code": "InvalidParameters",
  "message": "ERROR: field first_field for entityType 'MyDocument' not found",
  "stackTrace": null,
  "businessError": null,
  "data": null
}

Если запрашиваемое поле не соответствует схеме (например, "MyDocument" не содержит "first_field"),
то внешний провайдер должен вернуть
ErrorResponse(code = ErrorResponseCode.InvalidParameters, message = Some("ERROR: field first_field for entityType 'MyDocument' not found"))

Список команд сервиса Oberto

В описании команд используется путь/route для отправки команды в сам сервис, а не в ApiGateway. В качестве Input-а для команд, сервис всегда ожидает CommandRequest (как и любой другой сервис, принимающий команды), так что в описании команды указано лишь описание поля payload для CommandRequest.

Информация по добавлению команд можно прочитать в описании шаблона

Информация по описанию правил для разграничения доступов: Формат описания правил

Название команды EntityType Actions
oberto_ListPolicyRecords PolicySet Edit
oberto_ListPolicyRecordsV2 PolicySet Edit
oberto_GetPolicyValue PolicySet Edit
oberto_GetPolicyValueV2 PolicySet Edit
oberto_DeletePolicy PolicySet Edit
oberto_DeletePolicyV2 PolicySet Edit
oberto_DeleteAllPolicyVersions PolicySet Edit
oberto_DeleteAllPolicyVersionsV2 PolicySet Edit
oberto_UpdatePolicy PolicySet Edit
oberto_UpdatePolicyV2 PolicySet Edit
oberto_OverridePoliciesFromSource PolicySet Edit
oberto_Authorize - -
oberto_AuthorizeV2 - -
oberto_AuthorizeList - -
oberto_AuthorizationRequest - -

ListPolicyRecords (oberto)

Payload для команды

null

Результат выполнения команды

[
  {
    "id": "Any_Policy_Name",
    "priority": 1000,
    "versions": [
      "0.1.0",
      "0.1.1",
      "0.1.2"
    ]
  }
]

Возвращает список политик с информацией об их идентификаторе и приоритете, а также со списком их версий.

Поддерживается только синхронный вызов.
Результат выполнения команды не журналируется.

Команда Путь
oberto_ListPolicyRecords HTTP POST "/v1/policy/list"

ListPolicyRecordsV2 (oberto)

Payload для команды

null

Результат выполнения команды

[
  {
    "id": "Any_Policy_Name",
    "priority": 1000,
    "versions": [
      "0.1.0",
      "0.1.1",
      "0.1.2"
    ]
  }
]

Возвращает список политик с информацией об их идентификаторе и приоритете, а также со списком их версий. В отличие от ListPolicyRecords, обращается за политиками не в authzforce по http, а в таблицу PolicySet базы данных сервиса oberto.

Поддерживается только синхронный вызов.
Результат выполнения команды не журналируется.

Команда Путь
oberto_ListPolicyRecordsV2 HTTP POST "/v1/policy/list_v2"

GetPolicyValue (oberto)

Payload для команды

{
  "id": "Any_Policy_Name",
  "version": "0.1.1"
}

Результат выполнения команды

{
  "policyId": "Any_Policy_Name",
  "version": "0.1.1",
  "priority": 1000,
  "description": "Policy effects description",
  "rules": [
    {
      "ruleId": "Policy_rule_ID",
      "rule": "permit Actions(View_WebDoc, somesvc_ListItems, other_UpdateEntity) if User.email endsWith '_employee@email.io'",
      "priority": 1,
      "filters": "ResourceType.innerObject.value >= '100'"
    }
  ]
}

Возвращает данные указанной версии политики.

Поддерживается только синхронный вызов.
Результат выполнения команды не журналируется.

Команда Путь
oberto_GetPolicyValue HTTP POST "/v1/policy/single"

GetPolicyValueV2 (oberto)

Payload для команды

{
  "id": "Any_Policy_Name",
  "version": "0.1.1"
}

Результат выполнения команды

{
  "policyId": "Any_Policy_Name",
  "version": "0.1.1",
  "priority": 1000,
  "description": "Policy effects description",
  "rules": [
    {
      "ruleId": "Policy_rule_ID",
      "rule": "permit Actions(View_WebDoc, somesvc_ListItems ,other_UpdateEntity) if User.email endsWith '_employee@email.io'",
      "priority": 1,
      "filters": "ResourceType.innerObject.value >= '100'"
    }
  ]
}

Возвращает данные указанной версии политики. В отличие от GetPolicyValue, обращается за политиками не в authzforce по http, а в таблицу PolicySet базы данных сервиса oberto.

Поддерживается только синхронный вызов.
Результат выполнения команды не журналируется.

Команда Путь
oberto_GetPolicyValueV2 HTTP POST "/v1/policy/single_v2"

DeletePolicy (oberto)

Payload для команды

{
  "id": "Any_Policy_Name",
  "version": "0.1.1"
}

Результат выполнения команды

true

Удаляет указанную версию политики.

Поддерживается только синхронный вызов.
Результат выполнения команды журналируется.

Команда Путь
oberto_DeletePolicy HTTP POST "/v1/policy/delete"

DeletePolicyV2 (oberto)

Payload для команды

{
  "id": "Any_Policy_Name",
  "version": "0.1.1"
}

Результат выполнения команды

true

Удаляет указанную версию политики. В отличие от DeletePolicy, обращается за политиками не в authzforce по http, а в таблицу PolicySet базы данных сервиса oberto.

Поддерживается только синхронный вызов.
Результат выполнения команды журналируется.

Команда Путь
oberto_DeletePolicyV2 HTTP POST "/v1/policy/delete_v2"

DeleteAllPolicyVersions (oberto)

Payload для команды

"Any_Policy_Name"

Результат выполнения команды

true

Удаляет все версии для указанного идентификатора политики.

Поддерживается только синхронный вызов.
Результат выполнения команды журналируется.

Команда Путь
oberto_DeleteAllPolicyVersions HTTP POST "/v1/policy/deleteAll"

DeleteAllPolicyVersionsV2 (oberto)

Payload для команды

"Any_Policy_Name"

Результат выполнения команды

true

Удаляет все версии для указанного идентификатора политики. В отличие от DeleteAllPolicyVersions, обращается за политиками не в authzforce по http, а в таблицу PolicySet базы данных сервиса oberto.

Поддерживается только синхронный вызов.
Результат выполнения команды журналируется.

Команда Путь
oberto_DeleteAllPolicyVersionsV2 HTTP POST "/v1/policy/deleteAll_v2"

UpdatePolicy (oberto)

Payload для команды

{
  "policyId": "Any_Policy_Name",
  "version": "0.1.1",
  "priority": 1000,
  "description": "Policy effects description",
  "rules": [
    {
      "ruleId": "Policy_rule_ID",
      "rule": "permit Actions(View_WebDoc, somesvc_ListItems ,other_UpdateEntity) if User.email endsWith '_employee@email.io'",
      "priority": 1,
      "filters": "ResourceType.innerObject.value >= '100'"
    }
  ]
}

Результат выполнения команды

true

Добавляет версию политики. Каждая версия должна иметь уникальное policyId и уникальную version внутри политики. Policy_rule_ID должны быть уникальными внутри текущей версии.

Поддерживается только синхронный вызов.
Результат выполнения команды журналируется.

Команда Путь
oberto_UpdatePolicy HTTP POST "/v1/policy/update"

UpdatePolicyV2 (oberto)

Payload для команды

{
  "policyId": "Any_Policy_Name",
  "version": "0.1.1",
  "priority": 1000,
  "description": "Policy effects description",
  "rules": [
    {
      "ruleId": "Policy_rule_ID",
      "rule": "permit Actions(View_WebDoc, somesvc_ListItems ,other_UpdateEntity) if User.email endsWith '_employee@email.io'",
      "priority": 1,
      "filters": "ResourceType.innerObject.value >= '100'"
    }
  ]
}

Результат выполнения команды

true

Добавляет версию политики. Каждая версия должна иметь уникальное policyId и уникальную version внутри политики. Policy_rule_ID должны быть уникальными внутри текущей версии. В отличие от UpdatePolicy, обращается за политиками не в authzforce по http, а в таблицу PolicySet базы данных сервиса oberto.

Поддерживается только синхронный вызов.
Результат выполнения команды журналируется.

Команда Путь
oberto_UpdatePolicyV2 HTTP POST "/v1/policy/update_v2"

OverridePoliciesFromSource (oberto)

На входе источник политик для override (поддерживает только значение "Authzforce")

"Authzforce"

На выходе количество добавленных версий политик

10

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

Поддерживается только синхронный вызов.
Результат выполнения команды журналируется.

Команда Путь
oberto_OverridePoliciesFromSource HTTP POST "/v1/policy/overridePoliciesFromSource"

Authorize (oberto)

Payload для команды

{
  "resourceId": "123456",
  "resourceType": "ProposalFile",
  "actions": [
    "DownloadFile",
    "View_WebDoc"
  ],
  "attributes": {
    "my_custom_attribute": [
      "value_for_this_attribute",
      "another_value"
    ]
  }
}

Результат выполнения команды

{
  "DownloadFile": true,
  "View_WebDoc": true
}

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

Поддерживается только синхронный вызов.
Результат выполнения команды не журналируется.

Команда Путь
oberto_Authorize HTTP POST "/v1/authorize"

AuthorizeV2 (oberto)

Payload для команды

{
  "resourceId": "123456",
  "resourceType": "ProposalFile",
  "actions": [
    "DownloadFile",
    "View_WebDoc"
  ],
  "attributes": {
    "my_custom_attribute": [
      "value_for_this_attribute",
      "another_value"
    ]
  }
}

Результат выполнения команды

{
  "DownloadFile": true,
  "View_WebDoc": true
}

Проверяет доступность действий для конкретного ресурса, указанных во входных параметрах. Отличается от "первой версии" тем, что не делает вызов в Authzforce-server (локальный расчет политик).

Поддерживается только синхронный вызов.
Результат выполнения команды не журналируется.

Команда Путь
oberto_AuthorizeV2 HTTP POST "/v1/authorize_v2"

AuthorizeList (oberto)

Payload для команды

[
  {
    "resourceId": "0000",
    "resourceType": "resource_type_name_1",
    "actions": [
      "action_name_1",
      "action_name_2"
    ],
    "attributes": {}
  },
  {
    "resourceId": "1111",
    "resourceType": "resource_type_name_1",
    "actions": [
      "action_name_2"
    ],
    "attributes": {}
  },
  {
    "resourceId": "0000",
    "resourceType": "resource_type_name_1",
    "actions": [
      "action_name_3"
    ],
    "attributes": {}
  }
]

Результат выполнения команды

[
  {
    "resourceId": "0000",
    "resourceType": "resource_type_name_1",
    "actions": {
      "action_name_1": true,
      "action_name_2": false,
      "action_name_3": false
    }
  },
  {
    "resourceId": "1111",
    "resourceType": "resource_type_name_1",
    "actions": {
      "action_name_2": false
    }
  }
]

Проверяет доступность действий для произвольного списка ресурсов, указанных во входных параметрах. Команда работает только с oberto. Сервис Authzforce не поддерживается.

Имя команды для вызова: oberto_AuthorizeList.
Поддерживается только синхронный вызов.
Результат выполнения команды не журналируется.

Команда Путь
oberto_AuthorizeList HTTP POST "/v1/authorizeList"

AuthorizationRequest (oberto)

Payload для команды

{
  "attributes": [
    {
      "id": "MyDocument.id",
      "cat": "urn:oasis:names:tc:xacml:3.0:attribute-category:resource",
      "values": [
        "123",
        "987"
      ]
    },
    {
      "id": "User.departmentCode",
      "cat": "urn:oasis:names:tc:xacml:1.0:subject-category:access-subject",
      "values": [
        "FirstDepartmentCode",
        "SecondDepartmentCode"
      ]
    }
  ],
  "userContext": {
    "id": "67287d83-25dd-4d3c-9559-e5cc02860a3f",
    "emailOpt": "test_user_email@embedika.ru",
    "groupIds": [
      "group_for_regular_users",
      "group_for_admins"
    ]
  }
}

Результат выполнения команды

{
  "allow": true,
  "entityFilters": "MyResource.name contains 'Test resource'"
}

Выполняет запрос авторизации с указанными параметрами. Не делает вызов в Authzforce-server (локальный расчет политик). Если во входных данных не указано поле "userContext", то будут использованы данные пользователя, который вызвал данную команду.

Поддерживается только синхронный вызов.
Результат выполнения команды не журналируется.

Команда Путь
oberto_AuthorizationRequest HTTP POST "/v1/authorizationRequest"

Модели сервиса Oberto

PolicyId (oberto)

Идентификатор политики. Соответствует типу String.

XacmlPolicySource (oberto)

Идентификатор источника политик. Поддерживаемые значения: Authzforce.

CommandsAuthorization (oberto)

Данные для авторизации набора действий по отношению к заданному ресурсу.

Поле Тип Обязательное Описание
resourceId String Нет Идентификатор конкретного объекта с типом resourceType, для которого проверяются actions.
resourceType String Нет Название типа ресурса, для которого проверяются actions.
actions List[String] Да Список идентификаторов действий. Может быть пустым, но тогда и результат будет пустым (завершение команды без проверок доступа).
attributes Map[String, List[String]] Нет Произвольный список атрибутов ресурса (можно задавать атрибуты любого ресурса).
Пример: '{ "MyDocument.authorId": ["123"] }'.

AuthorizeListCommandResponse (oberto)

Результат выполнения команды пакетной авторизации: данные о наличии доступа для набора действий по отношению к заданному ресурсу.

Поле Тип Обязательное Описание
resourceId String Нет Идентификатор конкретного объекта с типом resourceType, для которого проверяются actions.
resourceType String Нет Название типа ресурса, для которого проверяются actions.
actions Map[String, Boolean] Да Список соответствия идентификатора действия и результата проверки наличия доступа.

PolicyRecord (oberto)

Запись с информацией о политике и набором ее версий.

Поле Тип Обязательное Описание
id PolicyId Да Идентификатор политики
priority Int Нет Приоритет политики (чем меньше, тем раньше она будет проверена). null = после всех политик, у которых установлен приоритет.
versions List[String] Да Список версий политик. Версия представлена в виде строки (semver) и должна соответствовать regexp "\d{1,16}\.\d{1,16}\.\d{1,16}", где доступны только цифры и точки: "0.1.0".

SinglePolicy (oberto)

Идентификатор конкретной версии политики.

Поле Тип Обязательное Описание
id PolicyId Да Идентификатор политики
version String Да Версия политики. В данной структуре, версия не должна соответствовать какому-либо формату.

PolicyUpdateDto (oberto)

Данные новой версии политики.

Поле Тип Обязательное Описание
policyId PolicyId Да Идентификатор политики. Должен быть уникальным значением в рамках всей системы.
version String Да Версия политики, представленная в виде строки (semver). Должна быть уникальной в рамках политики и соответствовать regexp "\d{1,16}\.\d{1,16}\.\d{1,16}".
priority Int Нет Приоритет политики (чем меньше, тем раньше она будет проверена). null = после всех политик, у которых установлен приоритет.
description String Да Описание политики.
rules List[PolicyRuleDto] Да Список правил.

PolicyRuleDto (oberto)

Описание правила применяемого в политике.

Поле Тип Обязательное Описание
ruleId String Да Идентификатор правила. Должен быть уникальным значением в рамках политики.
rule String Да Правило применения эффекта (permit/deny). Формат описания правил.
priority Int Да Приоритет правила (чем меньше, тем раньше оно будет проверено).
filters Condition Нет Фильтры, которые нужно применить при обращении к списку.

AuthorizationRequestDTO (oberto)

Параметры запроса авторизации.

Поле Тип Обязательное Описание
attributes List[AttributeWithValues] Да Список атрибутов и их значений для запроса.
userContext UserContext Нет Данные о пользователе, для которого будет проверяться доступность. Нужно в том случае, если проверяемый пользователь отличается от пользователя, который вызвал запрос авторизации.

AttributeProviderSettings (oberto)

Настройки провайдера атрибутов в Oberto.

Поле Тип Обязательное Описание Значение по умолчанию
cacheConfig VerdiCacheConfig Нет Настройки для кеша атрибутов. maxSize = 1000, elementTTL = 5 minutes
requestTimeout duration string Нет Время ожидания выполнения запроса к внешней системе. 30 seconds
commandsMapping string Нет Список префиксов атрибутов и связанных с ними команд. Отображение 1 к 1. ""

AttributeProvider-CommandsMapping (oberto)

Формат для маппинга префиксов атрибутов в команды внешних сервисов.

Для задания маппинга используется строка, в которой закодированы пары ключ значение через символ =.
В строке можно указывать несколько пар через разделитель ;, "Prefix1=CommandName1;Prefix2=CommandName2".

Например, MyResourceCode=My_Command_name; EntityType1 = internalGetObject ; Order= get_order_attribute_by_name.

Если в настройках задан некорректный формат, то при запуске сервиса Oberto будет ошибка ConfigurationException.

AttributeValueRequest (oberto)

Запрос значения атрибута у конкретного объекта.

Поле Тип Обязательное Описание
requestId string Да Идентификатор запроса значения атрибута.
maybeServiceProvider Option[string] Нет Префикс, который может быть использован в качестве ключа для маппинга.
objectIdentity EntityObjectIdentity Да Идентификатор требуемого объекта.
fieldPathLowerCase string Да Путь для требуемого атрибута в lower case.
context Map[string, Seq[string]] Да Контекст запроса авторизации.

AttributeRequest (oberto)

Настройки провайдера атрибутов в Oberto.

Поле Тип Обязательное Описание
id EntityObjectIdentity Да Идентификатор требуемого объекта.
fieldPath string Да Путь для требуемого атрибута в lower case.
context Map[string, Seq[string]] Да Контекст запроса авторизации.

AttributeResponse (oberto)

Настройки провайдера атрибутов в Oberto.

Поле Тип Обязательное Описание
id EntityObjectIdentity Да Идентификатор объекта.
value Either[Vector[string], string] Да Значение атрибута: Left - несколько значений, Right - одно значение.

EntityObjectIdentity

Идентификатор объекта.

Поле Тип Обязательное Описание
entityType string Да Типа сущности
objectId uuid Да Идентификатор объекта, который уникален в рамках указанного типа

Формат описания правил

RuleFormat (oberto)

Формат описания правил.

Шаблон для описания правил

{
  permit
  |
  deny
} Actions(name, name, ...) if CONDITION

Варианты описания сравнения значений:
1) {User|name}.field.path Operation 'Value'
2) {anyOf|allOf} {User|name}.field.path Operation {anyOf|allOf} ['Value', 'Value', 'Value', ...]

Примеры правил: 1) разрешает редактирования политик (тип "PolicySet") если email пользователя начинается с "manager": permit Actions(Edit) if (resource.entityType == 'PolicySet' and User.email startsWith 'manager')

P.S. Условие на конкретный тип ресурса ("resource.entityType == 'PolicySet'") может быть записано, как только название ресурса без дополнительных условий ("PolicySet")

2) разрешает просмотр журнала событий (тип отсутствует, т.е. ограничивается только действием) если группа пользователя одна из списка или доступ требуется для определенного пользователя: permit Actions(ViewEventsJournal) if (User.groupId == anyOf ['manager', 'admin', 'business_admin'] or User.id = '123456789')

Описание правила можно разделить на несколько частей "Effect Actions IfClause"

  1. Effect может содержать одно из двух ключевых слов: permin, deny

  2. Actions содержит список действий, на которые будет распространяться правило. Список правил начинается со слова Actions, заключен в скобки и разделен запятыми.
    Для списка A,B,C => Actions(A, B, C).

  3. IfClause содержит условия для пользователя и целевого ресурса, при выполнении которых будет применяться правило.
    Условия начинаются со слова if и разделены на группы. Внутри каждой группы могут быть другие группы условий или само условие.
    Более подробно, структура описана на странице Condition.

    Доступные операции для сравнения значений:
        == два значения равны
        >= левое значение больше или равно правому
        <= левое значение меньше или равно правому
        contains левое значение содержит подстроку, равную правой
        startsWith левое значение начинается со строки, что справа
        endsWith левое значение заканчивается строкой, что справа

Plagiarism-plugin: плагин пересечений по тексту

Плагин отвечает за обработку одного из возможных шагов сервиса индексации - шага с payload-типом Plugin.

Плагин читает из kafka-топика сообщения от сервиса Indexation, содержащие stepProgress, и обрабатывает файловые поля сущности stepProgress.entityObject. Обрабатываются только поля, содержащиеся в step.payload.fields. Во время обработки плагин обращается к Lamp, чтобы найти файловые поля других сущностей, содержимое файлов в которых пересекается с содержимым полей step.payload.fields у сущности stepProgress.entityObject. После этого, если степень похожести файлов превышает APP_MEASURE_THRESHOLD, между файловыми полями step.payload.fields сущности stepProgress.entityObject и найденными файловыми полями других сущностей создаются ссылки в data-model.

Подробнее процесс обработки сообщений описан в документации трейта BaseFlow проекта IntelligentPluginCore.

Конфигурирование PlagiarismPlugin

Требования к запуску PlagiarismPlugin

Запуск из консоли с помощью SBT

sbt boot/run

При запуске сервиса ожидается, что уже развернута необходимая инфраструктура:

Список переменных окружения для сервиса PlagiarismPlugin

Переменная Тип Обязательная Значение по умолчанию Описание
CONSUMER_TOPIC string Нет plagiarismPlugin Топик, в который поступает StepProgress на обработку.
CONSUMER_GROUP string Нет plagiarismPlugin Имя группы-консьюмеров сервиса plagiarismPlugin.
LAMP_USE_VERSION_2 boolean Нет false Использовать ли LAMP2 (true) или LAMP1 (false).
LAMP_BUFFER_SIZE int Нет 10 Буфер на отправку сообщений в клиент LAMP.
LAMP_RECONNECT_SCHEDULE string Нет I(2 seconds) Стратегия переподключения клиента LAMP (формат см. lamp.transport.model.Schedule).
LAMP_HOST string Нет lamp-dev.dev.embedika.ru Адрес клиента LAMP (должен быть непустым, если LAMP_ENABLE=true).
LAMP_PORT int Нет 443 Порт клиента LAMP (должен быть непустым, если LAMP_ENABLE=true).
LAMP_TLS boolean Нет true Признак защищенного подключения к LAMP.
LAMP_TLS_CERTIFICATE string Нет Путь файла с сертификатом для подключения к LAMP.
LAMP_TLS_PRIVATE_KEY string Нет Путь файла с приватным ключом для подключения к LAMP.
LAMP_TLS_ROOT_TRUSTED_CERTS string Нет Путь файла с центром сертификации (Certification Authority, CA) для подключения к LAMP.
LAMP_TIMEOUT duration string Нет 1 minute Таймаут отправки сообщения и получения результатов через клиент LAMP.
LAMP_MAX_MESSAGE_SIZE int Нет 524288000 Максимальный допустимый размер сообщений в LAMP.
LAMP_CACHEABLE_SERVICES string Нет extraction,keywords,lemmatization Строка, содержащая список сервисов LAMP, результаты которых будут кэшироваться внутри LAMP. При вызове одного рута LAMP может происходить обращение к нескольким сервисам LAMP.
LAMP_PARAMETERS_OPERATION string Нет plagiarism Название операции, которое в качестве параметра передается в Lamp.
APP_LINK_TYPE string Нет plagiarism Тип ссылки, создаваемой плагином в data-model.
APP_LINK_OWNER string Нет plagiarism_mapper Link owner ссылки, создаваемой плагином в data-model.
APP_MEASURE_NAME string Нет intersections measureName, которое будет использовано в объекте, лежащем в поле additionalData при создании ссылки в data-model.
APP_MEASURE_THRESHOLD float Нет 0.5 Пороговое значение measure. Ссылки создаются только между документами, мера схожести между которыми больше или равна этому значению.
APP_LAMP_ROUTE string Нет plagiarism_search_route Рут Lamp, к которому обращается плагин с запросом поиска пересекающихся файлов.
APP_CREATE_LINKS_PER_MESSAGE int Нет 100 Размер батча для запроса к data-model c командой createObjectsLinks.
PLUGIN_INFO_READABLE_NAME string Нет Плагин для построения ссылок на основе содержательных пересечений Значение в поле name у тех. константы плагина.
PLUGIN_INFO_DESCRIPTION string Нет Проходит по всем объектам и строит ссылки между ними на основе содержательных пересечений их файлов Значение в поле description у тех. константы плагина.
PLUGIN_INFO_VERSION int Нет 1 Значение в поле serviceVersion у тех. константы плагина.
APP_INDEXATION_CHUNK_SIZE int Нет 100 Значения, поступающие в топик CONSUMER_TOPIC, обрабатываются батчами. Батч поступает в обработку либо если из топика было получено количество сообщений равное максимальному размеру батча, либо если от получения первого элемента батча прошло время равное максимальной разнице получения элементов в батче. Эта переменная устанавливает максимальный размер батча.
APP_INDEXATION_WITHIN duration string Нет 1 minutes Значения, поступающие в топик CONSUMER_TOPIC, обрабатываются батчами. Батч поступает в обработку либо если из топика было получено количество сообщений равное максимальному размеру батча, либо если от получения первого элемента батча прошло время равное максимальной разнице получения элементов в батче. Эта переменная устанавливает максимальную разницу времени получения элементов в батче.
APP_MAX_RETRY int Нет 2 Максимальное количество ретраев, которое произойдет при обращении к LAMP, если он возвращает ошибку.
CONSUMER_PROGRESS_TOPIC string Нет progress Топик, в который плагин пишет об окончании обработки.
PRODUCER_INDEXATION_EVENT_TOPIC string Нет entityObjectEvent Топик, в который плагин отправляет запрос на переиндексацию backlinks.
VERDI_HOST string Нет localhost Адрес, который будет зарегистрирован за данным экземпляром сервиса.
VERDI_TTL duration string Нет 30 seconds Время, в течение которого экземпляр сервиса считается "активным". Таймер обновляется каждый раз, когда сервис присылает "health check".
VERDI_HEALTH_CHECK duration string Нет 10 seconds Периодичность отправки "health check".
VERDI_CONSUL string Нет http://localhost:8500 Адрес Consul.
VERDI_CONSUL_AUTH_USER string Нет Название учетной записи Сonsul. Если название не указано, то настройки авторизации не будут применены.
VERDI_CONSUL_AUTH_PASSWORD string Нет Пароль учетной записи Сonsul.
VERDI_KAFKA_ADDRESS string Нет localhost:9092 Адрес Kafka.
VERDI_KAFKA_TOPIC string Нет commandevents Название топика для отправки сообщений со статусом команд.
VERDI_KAFKA_PRODUCER_PROPS string Нет max.request.size=1048576 Дополнительные параметры для Kafka producer. Заполняются по шаблону "key1=value1;key2=value2".
VERDI_KAFKA_AUTH_USER string Нет Название учетной записи Kafka. Если название не указано, то настройки авторизации не будут применены.
VERDI_KAFKA_AUTH_PASSWORD string Нет Пароль учетной записи Kafka.
VERDI_KAFKA_AUTH_PRINCIPAL string Нет Principal учетной записи Kafka в Kerberos (в случае соединения с kafka через Kerberos).
VERDI_KAFKA_AUTH_KEYTAB_PATH string Нет Путь до keytab-файла (в случае соединения с kafka через Kerberos).
VERDI_KAFKA_AUTH_TRUSTSTORE_LOCATION string Нет Путь до хранилища сертификатов (Java key store). Если путь не указан, то сертификат применяться не будет.
VERDI_KAFKA_AUTH_TRUSTSTORE_PASSWORD string Нет Пароль к хранилищу сертификатов.
VERDI_KAFKA_AUTH_MODE string Нет static Режим аутентификации: static - одна учетная запись на все запросы, mapping - учетная запись зависит от запроса.
VERDI_KAFKA_AUTH_CONFIG string Нет Настройки для аутентификации: если AuthMode = mapping, то необходим JSON с List[KafkaAuthConfig]. Переменная соответствует полю authConfig из KafkaAuthSettings.
VERDI_KAFKA_AUTH_CACHE_SIZE int Нет Максимальный размер кэша для Kafka producer (количество активных соединений).
VERDI_KAFKA_AUTH_CACHE_TTL duration string нет Время жизни Kafka producer в кэше.
VERDI_ALLOW_INTERNAL_COMMANDS boolean Нет true Можно ли сервису отправлять внутрисистемные команды.
VERDI_CONSIDER_ALL_COMMANDS_AS_INTERNAL boolean Нет false Флаг, определяющий будут ли все обращения в другие сервисы являться внутренними (т.е. не требовать авторизацию). Детальное описание механизма: Внутренние команды.
VERDI_COMMAND_STORAGE_UPDATE_PERIOD duration string Нет 1 minutes Время кэширования данных по командам из CommandDiscovery.
VERDI_SERVICE_DISCOVERY_UPDATE_PERIOD duration string Нет 30 seconds Время кэширования данных по сервисам из ServiceDiscovery.
VERDI_CONSUL_CONNECTION_MAX_RETRY int Нет 5 Максимальное количество попыток подключения к Consul после обрыва соединения.
VERDI_CONSUL_CONNECTION_RETRY_DELAY duration string Нет 1 seconds Задержка перед попыткой подключения к Consul.
VERDI_KAFKA_SYNC_POLL_PERIOD duration string Нет 1 seconds Периодичность запроса статуса команды, отправленной через Kafka.
VERDI_KAFKA_SYNC_POLL_TIMEOUT duration string Нет 1 minute Время ожидания завершения команды, отправленной через Kafka.
VERDI_COMMANDS_HTTP_RETRY_ATTEMPTS int Нет 5 Поле attempts из RetrySettings.
VERDI_COMMANDS_HTTP_RETRY_DELAY duration string Нет 5 seconds Поле delay из RetrySettings.
VERDI_COMMANDS_HTTP_RETRY_KIND string Нет OnSomeExceptions(ConnectException) CommandResultRetryConditionKind.

Команды сервиса PlagiarismPlugin

Сервис PlagiarismPlugin не содержит в себе никакие команды. Вместо этого он обрабатывает kafka-сообщения, поступающие из сервиса индексации.

Для обработки сообщений PlagiarismPlugin использует реализации BaseFlow, предоставляемые IntelligentPluginCore.

Два файла с идентификаторами id1 и id2 в PlagiarismPlugin считаются пересекающимися, если:

  1. при запросе c id1 к Lamp в ответ поступило сообщение message с типом PlagiarismMessage
  2. id2 содержится в message.foundIds
  3. id2 соответствует lampMeasure из message.originalities
  4. при этом (1 - min(1, lampMeasure)) >= APP_MEASURE_THRESHOLD.

Sagas: библиотека для описания cаг

Сага/Saga представляет собой цепочку переходов между состояниями (шагов).. Каждый переход имеет две операции: переход к следующему состоянию (переход впепед) или откат изменений вызваных переходом (переход назад). Под операцией перехода понимается любая операция, которая соответстует List[A] => A. Где, A это базовый класс для всех результатов операций. Результаты выполненых операций складываются в один список, таким образом List[A] представляет собой состояние Саги, которое содержит результаты выполненых переходов.

Для описания состояния Саги используется класс SagaState. Для описания переходов есть несколько интерфесов, но все они расширяют базовый Transition. Для описания Саги, как списка переходов используется SagaDefinition.

Описание Саги в коде

Базовый тип для результатов выполнения переходов Саги

sealed trait StagesForSagaName

Результаты переходов

object StagesForSagaName {

    // init or empty stage
    case class FirstStage(args: SagaArgumentClass) extends StagesForSagaName

    case class SecondStage(firstStageRes: Option[FirstOperationResult]) extends StagesForSagaName

    case class ThirdStage() extends StagesForSagaName

    case class FourthStage(thirdStageRes: ThirdOperationResult) extends StagesForSagaName

}

Реализация переходов

case class FirstWithoutCommandsOp_SagaName(dispatcher: Dispatcher,
                                           sagaLogger: Logger)
                                          (implicit ec: ExecutionContext)
    extends SyncSagaStageTransition[Future, StagesForSagaName] {
    override protected type OperationContext = Unit

    override protected def transitionImpl(previousStages: List[StagesForSagaName], context: Unit): Future[StagesForSagaName] = {
        sagaLogger.info("Execute FirstOperation in SagaName")

        val operationArguments = convertToForwardArgs(previousStages)
        val opResult = FirstOperationResult(operationArguments.toList.mkString(" => "))

        val resultStage = StagesForSagaName.SecondStage(Some(opResult))

        Future.successful(resultStage)
    }

    override protected def rollbackImpl(previousStages: List[StagesForSagaName], context: Unit): Future[Unit] = {
        sagaLogger.info("Execute compensation for FirstOperation in SagaName: Nothing to do")

        Future.successful(())
    }

    override protected def transitionResultByOperationId(operationIdentifier: Option[OperationId]): Future[Option[Future[StagesForSagaName]]] = Future.successful(None)

    override protected def rollbackResultByOperationId(operationIdentifier: Option[OperationId]): Future[Option[Future[Unit]]] = Future.successful(None)

    override protected def generateOperationContext(isRollback: Boolean, previousStages: List[StagesForSagaName]): Future[Unit] = Future.successful(())

    override protected def extractOperationId(context: Unit): Option[OperationId] = None

    private def convertToForwardArgs(s: List[StagesForSagaName]): SagaArgumentClass = ???
}

case class SecondSyncOp_SagaName(durationTracingEnable: Boolean,
                                 dispatcher: Dispatcher,
                                 sagaLogger: Logger)
                                (implicit ec: ExecutionContext)
    extends SyncSagaStageTransition[Future, StagesForSagaName]
        with CommandSendingSupport
        with OperationIdAsCommandIdHelper {

    override protected def transitionImpl(previousStages: List[StagesForSagaName], context: RequestContext): Future[StagesForSagaName] = {
        sagaLogger.info("Execute SecondOperation")

        val commandArgs = convertToForwardArgs(previousStages)

        dispatcher.sendCommandSync(CommandsForSagaName.CommandToCallOn_SecondStage, commandArgs)(context)
            .flatMap {
                case Right(commandResult) =>
                    commandResult.value.flatMap(_.as[SecondOperationResult].toOption) match {
                        case Some(secondStageRes) if secondStageRes.someInnerResult > 100 =>
                            val resultStage = StagesForSagaName.ThirdStage()
                            Future.successful(resultStage)
                        case _ =>
                            // rollback
                            Future.failed(new RuntimeException("Second operation in SagaName ended unexpectedly"))
                    }

                case Left(_) =>
                    Future.failed(new RuntimeException("Failed to send command for Second operation in SagaName"))
            }
    }

    override protected def rollbackImpl(previousStages: List[StagesForSagaName], context: RequestContext): Future[Unit] = {
        sagaLogger.info("Execute compensation for SecondOperation")

        val compensationArgs = convertToRollbackArgs(previousStages)

        dispatcher.sendCommandSync(CommandsForSagaName.CommandToCallOn_SecondStage_Compensation, compensationArgs)(context)
            .flatMap {
                case Right(result) => // ignore compensation result
                    val resultStage = StagesForSagaName.SecondStage(None)
                    Future.successful(resultStage)

                case Left(_) =>
                    Future.failed(new RuntimeException("Failed to sent command"))
            }
    }

    override protected def transitionResultByOperationId(operationIdentifier: Option[OperationId]): Future[Option[Future[StagesForSagaName]]] = {
        sagaLogger.info(s"SecondOperation result have be restored from operationIdentifier '$operationIdentifier'")

        commandResultByOperationId[SecondOperationResult](operationIdentifier).map { resultOpt =>
            resultOpt.map(_ => Future.successful(StagesForSagaName.ThirdStage()))
        }
    }

    override protected def rollbackResultByOperationId(operationIdentifier: Option[OperationId]): Future[Option[Future[Unit]]] = {
        sagaLogger.info("SecondOperation compensation result have be restored from operationIdentifier '$operationIdentifier'")

        commandResultByOperationId[Json](operationIdentifier).map { resultOpt =>
            resultOpt.map(_ => Future.successful(Some()))
        }
    }

    override protected def generateOperationContext(isRollback: Boolean, previousStages: List[StagesForSagaName]): Future[RequestContext] = {
        val cr = if (!isRollback)
            makeRequestContext("Second operation in SagaName")
        else
            makeRequestContext("Compensation for Second operation in SagaName")

        Future.successful(cr)
    }

    private def convertToForwardArgs(s: List[StagesForSagaName]): Json = ???

    private def convertToRollbackArgs(s: List[StagesForSagaName]): Json = ???
}

case class ThirdAsyncOp_SagaName(durationTracingEnable: Boolean,
                                 dispatcher: Dispatcher,
                                 sagaLogger: Logger)
                                (implicit ec: ExecutionContext)
    extends AsyncSagaStageTransition[Future, StagesForSagaName]
        with FutureRollbackCallbackDefaultImpl {
    override protected type OperationContext = RequestContext

    override protected implicit val applicativeInstance: Applicative[Future] = cats.implicits.catsStdInstancesForFuture(ec)

    override protected def transitionImpl(previousStages: List[StagesForSagaName], context: RequestContext): Future[OperationCallback[Future, StagesForSagaName]] = {
        sagaLogger.info("Execute ThirdOperation")

        implicit val cr: RequestContext = makeRequestContext("???")

        val commandArgs = convertToForwardArgs(previousStages)

        dispatcher.sendCommandAsync(CommandsForSagaName.CommandToCallOn_ThirdStage, commandArgs)
            .flatMap {
                case Right(commandId) =>
                    val cb = getTransitionCallback(commandId)
                    Future.successful(cb)

                case Left(_) =>
                    Future.failed(new RuntimeException("Failed to sent command"))
            }
    }

    override protected def rollbackImpl(previousStages: List[StagesForSagaName], context: RequestContext): Future[OperationCallback[Future, Unit]] = {
        sagaLogger.info("Execute compensation for ThirdOperation")

        implicit val cr: RequestContext = makeRequestContext("???")

        val compensationArgs = convertToRollbackArgs(previousStages)

        dispatcher.sendCommandAsync(CommandsForSagaName.CommandToCallOn_ThirdStage_Compensation, compensationArgs)
            .flatMap {
                case Right(commandId) =>
                    val cb = getRollbackCallback(commandId)
                    Future.successful(cb)

                case Left(_) =>
                    Future.failed(new RuntimeException("Failed to sent command"))
            }
    }

    override def getTransitionCallback(commandId: CommandId): OperationCallback[Future, StagesForSagaName] = new ThirdOpTransitCallback(commandId)

    override protected def generateOperationContext(isRollback: Boolean, previousStages: List[StagesForSagaName]): Future[RequestContext] = {
        val cr = if (!isRollback)
            makeRequestContext("Third operation in SagaName")
        else
            makeRequestContext("Compensation for third operation in SagaName")

        Future.successful(cr)
    }

    override protected def extractOperationId(context: RequestContext): Option[OperationId] =
        Some(OperationId.fromCommandId(context.commandId))

    private def convertToForwardArgs(s: List[StagesForSagaName]): Json = ???

    private def convertToRollbackArgs(s: List[StagesForSagaName]): Json = ???
}


final class ThirdOpTransitCallback(val commandId: CommandId)
    extends OperationCallback[Future, StagesForSagaName] {
    override def callback(commandAggregatedStatus: CommandAggregatedStatus): Future[StagesForSagaName.FourthStage] = {
        commandAggregatedStatus.value.flatMap(_.as[ThirdOperationResult].toOption) match {
            case Some(thirdStageRes) =>
                val stageResult = StagesForSagaName.FourthStage(thirdStageRes)
                Future.successful(stageResult)

            case None =>
                Future.failed(new RuntimeException("Third operation in SagaName ended unexpectedly"))
        }
    }
}
case class SagaNameDefinition(sagaStageService: SagaStatePersistService[Future, StagesForSagaName],
                              firstOp: FirstWithoutCommandsOp_SagaName,
                              secondOp: SecondSyncOp_SagaName,
                              thirdOp: ThirdAsyncOp_SagaName)
    extends SagaDefinition[Future, SagaArgumentClass, StagesForSagaName] {
    override val steps: StageList[Future, StagesForSagaName] =
        StepsList(
            firstOp,
            secondOp,
            thirdOp
            )

    override protected def initStage(arguments: SagaArgumentClass): StagesForSagaName =
        StagesForSagaName.FirstStage(arguments)

    override def sendSagaEvent(message: SagaEventMessage): Future[Boolean] = 
        // Например, отправка в Kafka topic
        Future.successful(true)

    override def wholeSagaResult(sagaId: SagaId, sagaState: SagaState[TestStage]): Future[Option[Json]] =
        // Создание результата всей саги на основе состояния саги после завершения 
        Future.successful(None)
}

Чтобы описать Сагу как цепочку переходов нужно:

Используемые структуры

SagaDefinition

Описание саги в виде списка шагов/переходов. Это описание запускается с помощью SagaRunner

SagaRunner

Раннер саг, который контролирует выполнение саги на основе ее описания.

SagaState

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

Идентификатор в поле relatedOperationId относится к идентификатору в поле index.

StepsList

Список шагов/переходов Саги, который позволяет получить следующий шаг на основе состояния Саги. Для этого у каждого элемента в списке есть свой идентификатор.

StepsListElement

Обертка над SagaTransition, которая выбирает нужный метод для вызова.

SagaTransition

Описывает шаг Саги. Переход между двумя состояниями/стадиями. Каждый переход имеет две операции: прямой переход и откат.

Условия "успеха или не успеха", необходимость повторных попыток и сложности параллельного выполнения/отката операций (в разных Сагах) не лежат в зоне отвественности Саги. Т.е. все аспекты выполнения операции должны быть описаны при реализации трейта.

SyncSagaTransition

Описывает синхронный переход между состояниями саги.

AsyncSagaTransition

Описывает асинхронный переход между состояниями саги.

В данной реализации, результат операции - OperationCallback, который завязан на команды Verdi.

OperationCallback

Callback, который будет вызван при завершении команды с заданным CommandId.

SagaManager

Менеджер callback-ов саг, который вызывает необходимый callback при завершении команды или удаляет его если время ожидания превышено.

SagaStatus

Статус Саги.

Значение Описание
Initiated Сага была иницирована, т.е. был присвоен Идентификатор и созданно состояние
Running Сага запущенна, т.е. первая операция уже была запущенна и Сага в процессе прямого выполнения
Rollback Сага откатывается, т.е. был начат процесс отката
Success Сага успешно завершенна, т.е. Сага была запущенна и прямое выполнение завершилось без вызова отката.
Failure Сага неудачно завершенна, т.е. был вызван процесс отката и Сага завершила откат.

SagaEvent

Тип события саги.

Значение Описание
Initiated Сага иницирована, т.е. ей присвоен SagaId и первоначальное состояние.
Started Начался процесс прямого выполнения саги
RollbackStarted Начался процесс отката саги
FinishedSuccess Вся сага завершена успешно
FinishedFailure Вся сага завершена. Т.к. был процесс отката, то завершение считается неуспешным.
StepStarted Началось выполнение шага саги
StepCompleted Шаг саги завершен успешно
StepFailed Шаг саги завершен неуспешно/с ошибкой

SagaEventMessage

Сообщение описывающее событие саги

SagaStateService

Интерфейс для получения состояния саги из хранилища. Хранилище может быть любое: in-memory, Redis, PostgreSQL и т.п.

SagaStatePersistService

Интерфейс для записи состояния саги в хранилище. Хранилище может быть любое: in-memory, Redis, PostgreSQL и т.п.

Пример описания Саги

Полный пример описания Саги

package com.embedika.verdi.sagas.example

import cats.Applicative
import com.embedika.verdi.models.RequestContext
import com.embedika.verdi.models.command.{CommandAggregatedStatus, CommandId, CommandName, CommandStatus}
import com.embedika.verdi.sagas._
import com.embedika.verdi.senderlib.Dispatcher
import io.circe.{Decoder, Json}
import io.circe.generic.semiauto.deriveDecoder
import org.slf4j.Logger

import scala.concurrent.{ExecutionContext, Future}
import scala.util.Success

//
// stages description
//
case class SagaArgumentClass() {
    def toList: List[String] = ???
}

object SagaArgumentClass {
    implicit val jsonDecoder: Decoder[SagaArgumentClass] = deriveDecoder
}

case class FirstOperationResult(data: String)

object FirstOperationResult {
    implicit val jsonDecoder: Decoder[FirstOperationResult] = deriveDecoder
}

case class SecondOperationResult(someInnerResult: Int)

object SecondOperationResult {
    implicit val jsonDecoder: Decoder[SecondOperationResult] = deriveDecoder
}

case class ThirdOperationResult(data: Json, nedata: Json)

object ThirdOperationResult {
    implicit val jsonDecoder: Decoder[ThirdOperationResult] = deriveDecoder
}

sealed trait StagesForSagaName

object StagesForSagaName {

    // init or empty state
    case class FirstStage(args: SagaArgumentClass) extends StagesForSagaName

    case class SecondStage(firstStageRes: Option[FirstOperationResult]) extends StagesForSagaName

    case class ThirdStage() extends StagesForSagaName

    case class FourthStage(thirdStageRes: ThirdOperationResult) extends StagesForSagaName

}

object CommandsForSagaName {
    val CommandToCallOn_SecondStage = CommandName("second_stage_command")
    val CommandToCallOn_ThirdStage = CommandName("third_stage_command")
    val CommandToCallOn_FourthStage = CommandName("fourth_stage_command")

    val CommandToCallOn_SecondStage_Compensation = CommandName("second_stage_command_Compensation")
    val CommandToCallOn_ThirdStage_Compensation = CommandName("third_stage_command_Compensation")
    val CommandToCallOn_FourthStage_Compensation = CommandName("fourth_stage_command_Compensation")
}


//
// stages implementation
//

case class SagaNameDefinition(sagaStageService: SagaStatePersistService[Future, StagesForSagaName],
                              firstOp: FirstWithoutCommandsOp_SagaName,
                              secondOp: SecondSyncOp_SagaName,
                              thirdOp: ThirdAsyncOp_SagaName)
    extends SagaDefinition[Future, SagaArgumentClass, StagesForSagaName] {

    override val steps: StepsList[Future, StagesForSagaName] =
        StepsList(
            firstOp,
            secondOp,
            thirdOp
            )

    override protected def initStage(arguments: SagaArgumentClass): StagesForSagaName =
        StagesForSagaName.FirstStage(arguments)

    override def sendSagaEvent(message: SagaEventMessage): Future[Boolean] = Future.successful(true)

    override def wholeSagaResult(sagaId: SagaId, sagaState: SagaState[TestStage]): Future[Option[Json]] = 
        Future.successful(None)
}

case class FirstWithoutCommandsOp_SagaName(dispatcher: Dispatcher,
                                           sagaLogger: Logger)
                                          (implicit ec: ExecutionContext)
    extends SyncSagaTransition[Future, StagesForSagaName] {
    override protected type OperationContext = Unit

    override protected def transitionImpl(previousStages: List[StagesForSagaName], context: Unit): Future[StagesForSagaName] = {
        sagaLogger.info("Execute FirstOperation in SagaName")

        val operationArguments = convertToForwardArgs(previousStages)
        val opResult = FirstOperationResult(operationArguments.toList.mkString(" => "))

        val resultStage = StagesForSagaName.SecondStage(Some(opResult))

        Future.successful(resultStage)
    }

    override protected def rollbackImpl(previousStages: List[StagesForSagaName], context: Unit): Future[Unit] = {
        sagaLogger.info("Execute compensation for FirstOperation in SagaName: Nothing to do")

        Future.successful(())
    }

    override protected def transitionResultByOperationId(operationIdentifier: Option[OperationId]): Future[Option[Future[StagesForSagaName]]] = Future.successful(None)

    override protected def rollbackResultByOperationId(operationIdentifier: Option[OperationId]): Future[Option[Future[Unit]]] = Future.successful(None)

    override protected def generateOperationContext(isRollback: Boolean, previousStages: List[StagesForSagaName]): Future[Unit] = Future.successful(())

    override protected def extractOperationId(context: Unit): Option[OperationId] = None

    private def convertToForwardArgs(s: List[StagesForSagaName]): SagaArgumentClass = ???
}

case class SecondSyncOp_SagaName(durationTracingEnable: Boolean,
                                 dispatcher: Dispatcher,
                                 sagaLogger: Logger)
                                (implicit ec: ExecutionContext)
    extends SyncSagaTransition[Future, StagesForSagaName]
        with CommandSendingSupport
        with OperationIdAsCommandIdHelper {

    override protected def transitionImpl(previousStages: List[StagesForSagaName], context: RequestContext): Future[StagesForSagaName] = {
        sagaLogger.info("Execute SecondOperation")

        val commandArgs = convertToForwardArgs(previousStages)

        dispatcher.sendCommandSync(CommandsForSagaName.CommandToCallOn_SecondStage, commandArgs)(context)
            .flatMap {
                case Right(commandResult) =>
                    commandResult.value.flatMap(_.as[SecondOperationResult].toOption) match {
                        case Some(secondStageRes) if secondStageRes.someInnerResult > 100 =>
                            val resultStage = StagesForSagaName.ThirdStage()
                            Future.successful(resultStage)
                        case _ =>
                            // rollback
                            Future.failed(new RuntimeException("Second operation in SagaName ended unexpectedly"))
                    }

                case Left(_) =>
                    Future.failed(new RuntimeException("Failed to send command for Second operation in SagaName"))
            }
    }

    override protected def rollbackImpl(previousStages: List[StagesForSagaName], context: RequestContext): Future[Unit] = {
        sagaLogger.info("Execute compensation for SecondOperation")

        val compensationArgs = convertToRollbackArgs(previousStages)

        dispatcher.sendCommandSync(CommandsForSagaName.CommandToCallOn_SecondStage_Compensation, compensationArgs)(context)
            .flatMap {
                case Right(result) => // ignore compensation result
                    val resultStage = StagesForSagaName.SecondStage(None)
                    Future.successful(resultStage)

                case Left(_) =>
                    Future.failed(new RuntimeException("Failed to sent command"))
            }
    }

    override protected def transitionResultByOperationId(operationIdentifier: Option[OperationId]): Future[Option[Future[StagesForSagaName]]] = {
        sagaLogger.info(s"SecondOperation result have be restored from operationIdentifier '$operationIdentifier'")

        commandResultByOperationId[SecondOperationResult](operationIdentifier).map { resultOpt =>
            resultOpt.map(_ => Future.successful(StagesForSagaName.ThirdStage()))
        }
    }

    override protected def rollbackResultByOperationId(operationIdentifier: Option[OperationId]): Future[Option[Future[Unit]]] = {
        sagaLogger.info("SecondOperation compensation result have be restored from operationIdentifier '$operationIdentifier'")

        commandResultByOperationId[Json](operationIdentifier).map { resultOpt =>
            resultOpt.map(_ => Future.successful(Some()))
        }
    }

    override protected def generateOperationContext(isRollback: Boolean, previousStages: List[StagesForSagaName]): Future[RequestContext] = {
        val cr = if (!isRollback)
            makeRequestContext("Second operation in SagaName")
        else
            makeRequestContext("Compensation for Second operation in SagaName")

        Future.successful(cr)
    }

    private def convertToForwardArgs(s: List[StagesForSagaName]): Json = ???

    private def convertToRollbackArgs(s: List[StagesForSagaName]): Json = ???
}

case class ThirdAsyncOp_SagaName(durationTracingEnable: Boolean,
                                 dispatcher: Dispatcher,
                                 sagaLogger: Logger)
                                (implicit ec: ExecutionContext)
    extends AsyncSagaTransition[Future, StagesForSagaName]
        with FutureRollbackCallbackDefaultImpl {
    override protected type OperationContext = RequestContext

    override protected implicit val applicativeInstance: Applicative[Future] = cats.implicits.catsStdInstancesForFuture(ec)

    override protected def transitionImpl(previousStages: List[StagesForSagaName], context: RequestContext): Future[OperationCallback[Future, StagesForSagaName]] = {
        sagaLogger.info("Execute ThirdOperation")

        implicit val cr: RequestContext = makeRequestContext("???")

        val commandArgs = convertToForwardArgs(previousStages)

        dispatcher.sendCommandAsync(CommandsForSagaName.CommandToCallOn_ThirdStage, commandArgs)
            .flatMap {
                case Right(commandId) =>
                    val cb = getTransitionCallback(commandId)
                    Future.successful(cb)

                case Left(_) =>
                    Future.failed(new RuntimeException("Failed to sent command"))
            }
    }

    override protected def rollbackImpl(previousStages: List[StagesForSagaName], context: RequestContext): Future[OperationCallback[Future, Unit]] = {
        sagaLogger.info("Execute compensation for ThirdOperation")

        implicit val cr: RequestContext = makeRequestContext("???")

        val compensationArgs = convertToRollbackArgs(previousStages)

        dispatcher.sendCommandAsync(CommandsForSagaName.CommandToCallOn_ThirdStage_Compensation, compensationArgs)
            .flatMap {
                case Right(commandId) =>
                    val cb = getRollbackCallback(commandId)
                    Future.successful(cb)

                case Left(_) =>
                    Future.failed(new RuntimeException("Failed to sent command"))
            }
    }

    override def getTransitionCallback(commandId: CommandId): OperationCallback[Future, StagesForSagaName] = new ThirdOpTransitCallback(commandId)

    override protected def generateOperationContext(isRollback: Boolean, previousStages: List[StagesForSagaName]): Future[RequestContext] = {
        val cr = if (!isRollback)
            makeRequestContext("Third operation in SagaName")
        else
            makeRequestContext("Compensation for third operation in SagaName")

        Future.successful(cr)
    }

    override protected def extractOperationId(context: RequestContext): Option[OperationId] =
        Some(OperationId.fromCommandId(context.commandId))

    private def convertToForwardArgs(s: List[StagesForSagaName]): Json = ???

    private def convertToRollbackArgs(s: List[StagesForSagaName]): Json = ???
}


final class ThirdOpTransitCallback(val commandId: CommandId)
    extends OperationCallback[Future, StagesForSagaName] {
    override def callback(commandAggregatedStatus: CommandAggregatedStatus): Future[StagesForSagaName.FourthStage] = {
        commandAggregatedStatus.value.flatMap(_.as[ThirdOperationResult].toOption) match {
            case Some(thirdStageRes) =>
                val stageResult = StagesForSagaName.FourthStage(thirdStageRes)
                Future.successful(stageResult)

            case None =>
                // rollback
                Future.failed(new RuntimeException("Third operation in SagaName ended unexpectedly"))
        }
    }
}

Преобразование поисковой строки в DSL поиска

Поисковая строка может содержать ключи фильтров, скобки, операторы || и && Для поисковой строки должен существовать контекст - словарь ключей фильтров и значений для фильтрации

Пример реализации и использования QueryEvaluator

Пример поисковый строки

val query = "date && (eventType || user)"

Пример контекста

val context = Map("date" -> "1188583200000_", "type" -> "type1,type2", "user"->"user1")

Цель получить например sql

... eventDate >= 1188583200000 AND (eventType IN ('type1', 'type2') AND userId = 'user1')

В качестве DSL поиска будем использовать Fragment из doobie.util.fragment.Fragment Нам нужно определить type class для Fragment, который должен уметь создавать нейтральный элемент (в sql например это будет TRUE, т.к. TRUE может быть скомбинирован с любыми другими выражениями, не изменяя результат этих выражения, и выражение только с WHERE TRUE будет корректным sql) и реализовывать конъюнкцию и дизъюнкцию (AND и OR)

import com.embedika.verdi.search.MultiMonoid
import doobie.util.fragment.Fragment
import doobie.util.fragments.{ whereAnd, whereOr }

implicit val doobieAlg: MultiMonoid[Fragment] = new MultiMonoid[Fragment] {
    override def multiply(x: Fragment, y: Fragment): Fragment = whereAnd(x, y)

    override def empty: Fragment = Fragment.empty

    override def combine(x: Fragment, y: Fragment): Fragment = whereOr(x, y)
  }

Пример реализации фильтров

import doobie.Fragments
import doobie.implicits._
import cats.data.{ Kleisli, NonEmptyList }
import com.embedika.verdi.persistence.filters.{ RangeQuery, FilterQueryContext, InSetQuery }

val filters: Map[String, Kleisli[Option, FilterQueryContext, Fragment]] = Map(
    "date" -> Kleisli {
        case InSetQuery(values) => NonEmptyList.fromList(values).map(nonEmptyValues => Fragments.in(fr""""MyTable".date""", nonEmptyValues))
        case RangeQuery(Some(from), Some(to)) => Some(fr""""MyTable".date >= $from and "MyTable".date <= $to""")
        case RangeQuery(Some(from), None) => Some(fr""""MyTable".date >= $from""")
        case RangeQuery(None, Some(to)) => Some(fr""""MyTable".date <= $to""")
        case _                  => None
    },
    "type" -> Kleisli {
        case InSetQuery(values) => NonEmptyList.fromList(values).map(nonEmptyValues => Fragments.in(fr""""MyTable".type""", nonEmptyValues))
        case _                  => None
    },
    "user" -> Kleisli {
        case InSetQuery(values) if values.length == 1 => Some(fr""""MyTable".user = ${values.head}""")
        case _                  => None
    }
  )

В фильтрах должны описываться алгоритмы преобразования "1188583200000_" в "eventDate >= 1188583200000", "type1,type2" в "eventType IN ('type1', 'type2')" и т.д. В конце получаем финальный Fragment

import com.embedika.verdi.search.QueryEvaluator

def searchSomething(search: Search) = {
    val parsedContexts: Map[String, FilterQueryContext] = parseSearchContext(search.context)

    val evaluator = FiltersQueryEvaluator.create[FilterQueryContext, Fragment](parsedSearchContext, filters)
    val searchQuery = evaluator.evaluate(request.query)
}

private def parseSearchContext(context: Map[String, Json]): Map[String, FilterQueryContext] =
    context.flatMap { case (fieldName, queryContext) =>
        FilterQueryContext
            .decode(queryContext)
            .map { parsedContext =>
                fieldName.trim -> parsedContext
            }
    }

Senderlib: библиотека для работы с командами

Библиотека предоставляет API для отправки команд, получения их статуса, регистрации команд и регистрации сервиса обрабатывающего команды.

API библиотеки можно разделить на 3 секции:

Используемые структуры поделены на отдельные пакеты по сущностям.

Структуры models.command

Структуры models.dispatch

Структуры models.service

Общие структуры

Структуры для настройки Kafka

ServiceDiscovery

Предоставляет API реестра сервисов, который хранит реальные адреса сервисов

Методы

RegisterServiceInstance

Регистрирует инстанс сервиса в реестре сервисов с указанными параметрами

Регистрация экземпляра сервиса

import com.embedika.verdi.models._
import com.embedika.verdi.models.service._
import com.embedika.verdi.senderlib.ServiceDiscovery

import scala.concurrent.ExecutionContext
import scala.concurrent.Future
import scala.concurrent.duration._
import scala.util.{Failure, Success}

def registration(serviceRegistry: ServiceDiscovery,
                 ec: ExecutionContext): Future[(ServiceId, AsyncStoppable)] = {
    val serviceId = ServiceId("someid")
    val serviceName = ServiceName("somename")

    val healthCheckingAtConsulPeriod = 2.minutes
    val healthCheckPassingToConsulPeriod = 1.minutes

    val serviceInfo = DiscoverableService(
        id = serviceId,
        name = serviceName,
        host = "localhost",
        port = 8080,
        version = "v1",
        ttl = healthCheckingAtConsulPeriod
    )

    serviceRegistry.registerServiceInstance(serviceInfo)
        .transform {
            case Success(registerSuccess) if registerSuccess =>
                val cancellation = serviceRegistry.startServiceHealthChecking(serviceId, healthCheckPassingToConsulPeriod)

                Success((serviceId, cancellation))

            case Success(_) =>
                Failure(new Exception(s"Service instance registration failed:\n$serviceInfo"))

            case Failure(ex) =>
                Failure(ex)
        }(ec)
}

DeregisterServiceInstance

Удаляет определенный эксземпляр сервиса из реестра сервисов, чтобы его нельзя было найти

Удаление зарегистрированного экземпляра сервиса

import com.embedika.verdi.models._
import com.embedika.verdi.models.service._
import com.embedika.verdi.senderlib.ServiceDiscovery

import scala.concurrent.ExecutionContext
import scala.concurrent.Future

val ec: ExecutionContext = ???
val serviceRegistry: ServiceDiscovery = ???

def registration(): Future[(ServiceId, AsyncStoppable)] = ???

registration().map { case (serviceId, healthCheckPassing) =>
    /* wait for the instance to stop working and become needless */
    healthCheckPassing.stop()
    serviceRegistry.deregisterServiceInstance(serviceId)
}(ec)

StartServiceHealthChecking

Стартует процесс отправки состояния текущего экземпляра в реестр сервисов. Для отправки состояния создается задача, которая будет периодически запускаться. Результатом задачи является обновление статуса сервиса, чтобы сервис считался "активным" в реестре. Задача будет выполнятся в 0, T, 2T, 3T.

Регистрация экземпляра сервиса

import com.embedika.verdi.models.service._
import com.embedika.verdi.senderlib.ServiceDiscovery

import scala.concurrent.ExecutionContext
import scala.concurrent.duration._
import scala.util.{Failure, Success}

val ec: ExecutionContext = ???
val serviceRegistry: ServiceDiscovery = ???

val serviceId: ServiceId = ???
val serviceInfo: DiscoverableService = ???

val healthCheckPassingToRegistryPeriod: FiniteDuration = 1.minutes

serviceRegistry
    .registerServiceInstance(serviceInfo)
    .transform {
        case Success(registerSuccess) if registerSuccess =>
            val cancellation = serviceRegistry.startServiceHealthChecking(serviceId, healthCheckPassingToRegistryPeriod)

            Success((serviceId, cancellation))

        case Success(_) =>
            Failure(new Exception(s"Service instance registration failed:\n$serviceInfo"))

        case Failure(ex) =>
            Failure(ex)
    }(ec)

IsAlive

Проверяет есть ли живой экземпляр сервиса в реестре сервисов.

CommandDiscovery

Предоставляет API для работы с хранилищем команд.

Методы

CommandInfo

Ищет метаинформацию о команде по имени команды.

Получение информации о команде

import com.embedika.verdi.models.command._
import com.embedika.verdi.senderlib.CommandDiscovery

import scala.concurrent.ExecutionContext

val ec: ExecutionContext = ???
val commandDiscovery: CommandDiscovery = ???

def handleCommandInfo[A](cmdInfo: CommandInfo): A = ???

val commandName = CommandName("somename")

commandDiscovery
    .commandInfo(commandName)
    .map { infoOpt =>
        infoOpt.map(handleCommandInfo)
    }(ec)

PublishCommands

Публикует метаинформацию о командах. Метаинформацию об отдельных командах после можно найти по имени команды.

Публикация команд

import com.embedika.verdi.models.command.{CommandInfo, CommandName}
import com.embedika.verdi.models.dispatch._
import com.embedika.verdi.models.service.ServiceName
import com.embedika.verdi.senderlib.CommandDiscovery
import io.circe.syntax._

import scala.concurrent.ExecutionContext

val ec: ExecutionContext = ???
val commandDiscovery: CommandDiscovery = ???

def handleCommandsPublishingResult[A](isPublished: Seq[Boolean]): A = ???

val serviceName = ServiceName("somename")
val dispatchParameters = HttpDispatchParameters(
    method = HttpMethod.POST,
    route = Some("/someroute")
)

val commandName = CommandName("somename")

val commandMeta = CommandInfo(
    commandName = commandName,
    dispatchType = DispatchType.Http,
    serviceName = serviceName,
    parameters = dispatchParameters.asJson,
    permissions = Seq.empty,
    entityType = "EntityToImpact",
    description = Some("Http command that returns result when receives arguments"),
    isInternalCommand = true,
    withoutEvents = false
)

commandDiscovery
    .publishCommands(Seq(commandMeta))
    .map(isPublished => handleCommandsPublishingResult(isPublished))(ec)

ListCommandsInfo

Возвращает список всех команд, опубликованных в хранилище команд на данный момент.

Список команд

import com.embedika.verdi.models.command._
import com.embedika.verdi.senderlib.CommandDiscovery

import scala.concurrent.ExecutionContext

val ec: ExecutionContext = ???
val commandDiscovery: CommandDiscovery = ???

def handleCommandInfo[A](cmdInfo: Either[(CommandName, Exception), CommandInfo]): A = ???

commandDiscovery
    .listCommandsInfo()
    .map { infoList =>
        infoList.map(handleCommandInfo)
    }(ec)

UnpublishCommand

Удаляет команду по ее имени из хранилища команд.

Dispatcher

Предоставляет API для отправки комманд

Методы

SendCommandSync

Отправляет команду и дожидается завершения ее выполнения. Команда считается завершенной, если ее статус изменился на один из "конечных".

Возвращает CommandId и CommandAggregatedStatusJson отправленной команды. В случае ошибки, возвращает DispatchError.

Синхронное выполнение команды

import com.embedika.verdi.models.debug.TracingContext
import com.embedika.verdi.models._
import com.embedika.verdi.models.command._
import com.embedika.verdi.senderlib.Dispatcher

import scala.concurrent.ExecutionContext
import scala.concurrent.Future
import scala.util.{Failure, Success}
import io.circe.{Decoder, Json}
import io.circe.syntax._

val ec: ExecutionContext = ???
val dispatcher: Dispatcher = ???

val commandArgumentsAsJson: Json = ???
val commandArgumentsAsString = commandArgumentsAsJson.noSpaces
val commandName = CommandName("someAction")

case class CommandResult(res: Int)

object CommandResult {
    implicit val decoder: Decoder[CommandResult] = ???
}

val durationTracingEnable: Boolean = ???

val initBuilder = RequestContext.builder()
val reqCtxBuilder = if (durationTracingEnable) {
    initBuilder.withTracing("Doing '$commandName' synchronously")
} else {
    initBuilder
}

implicit val reqCtx: RequestContext = reqCtxBuilder.build()

def handleCommandResult[A](r: CommandResult): A = ???

dispatcher.sendCommandSync(commandName, commandArgumentsAsString)
    .transform {
        case Success(Right(commandAggregatedStatus)) =>
            val handledResult: Option[_] = for {
                commandResultAsJson <- commandAggregatedStatus.value
                commandResult <- commandResultAsJson.as[CommandResult].toOption
            } yield {
                handleCommandResult(commandResult)
            }

            Success(handledResult)

        case _ =>
            Success(None)
    }(ec)

SendCommandAsync

Отправляет команду без ожидания завершения ее выполнения.

Возвращает CommandId отправленной команды. В случае ошибки, возвращает DispatchError.

Асинхронное выполнение команды

import com.embedika.verdi.models.debug.TracingContext
import com.embedika.verdi.models._
import com.embedika.verdi.models.command._
import com.embedika.verdi.senderlib.Dispatcher

import scala.concurrent.ExecutionContext
import scala.concurrent.Future
import scala.util.{Failure, Success}
import io.circe.{Decoder, Json}
import io.circe.syntax._

val ec: ExecutionContext = ???
val dispatcher: Dispatcher = ???

val commandArgumentsAsJson: Json = ???
val commandArgumentsAsString = commandArgumentsAsJson.noSpaces
val commandName = CommandName("someAction")

case class CommandResult(res: Int)

object CommandResult {
    implicit val decoder: Decoder[CommandResult] = ???
}

val durationTracingEnable: Boolean = ???

val initBuilder = RequestContext.builder()
val reqCtxBuilder = if (durationTracingEnable) {
    initBuilder.withTracing("Doing '$commandName' asynchronously")
} else {
    initBuilder
}

implicit val reqCtx: RequestContext = reqCtxBuilder.build()

dispatcher.sendCommandAsync(commandName, commandArgumentsAsString)
    .transform {
        case Success(Right(commandId)) =>
            Success(Some(commandId))

        case _ =>
            Success(None)
    }(ec)

SendCommandEvent

Отправляет событие CommandEvent о процессе выполнения команды, которое будет учитываться в CommandAggregatedStatus

Возвращает Right(()) при успешной отправке события, иначе Left(errorResponse), где errorResponse - DispatchError, произошедшая в процессе.

Асинхронное выполнение команды

import com.embedika.verdi.models.command._
import com.embedika.verdi.senderlib.Dispatcher

import scala.concurrent.ExecutionContext
import scala.concurrent.Future
import io.circe.Encoder
import io.circe.syntax._

case class CommandResult(res: Int)
object CommandResult {
    implicit val encoder: Encoder[CommandResult] = ???
}

trait CommandStateSwitcher {
    protected val ec: ExecutionContext = ???
    protected val dispatcher: Dispatcher = ???

    def completeCommand(commandId: CommandId, 
                        result: CommandResult): Future[Either[ErrorResponse, Unit]] = {
        val eventPayload: Option[String] = Some(result.asJson.noSpaces)

        dispatcher.sendCommandEvent(commandId = commandId,
                                    newState = CommandStatus.Completed,
                                    payload = eventPayload)
    }
}

Status

Возвращает текущий статус CommandAggregatedStatusJson команды по ее CommandId, если он существует.

Получение текущего статуса команды

import com.embedika.verdi.models.debug.TracingContext
import com.embedika.verdi.models.{RequestContext, RequestContextBuilder}
import com.embedika.verdi.models.command._
import com.embedika.verdi.senderlib.Dispatcher

import scala.concurrent.ExecutionContext
import scala.concurrent.Future
import io.circe.Decoder
import io.circe.syntax._

import scala.util.{Failure, Success}

case class CommandResult(res: Int)

object CommandResult {
    implicit val decoder: Decoder[CommandResult] = ???
}

val ec: ExecutionContext = ???
val dispatcher: Dispatcher = ???

val commandId: CommandId = ???
def handleCommandResult[A](r: CommandResult): A = ???
def handleCommandError[A](error: ErrorResponse): A = ???

val durationTracingEnable: Boolean = ???

val initBuilder = RequestContext.builder()
val reqCtxBuilder = if (durationTracingEnable) {
    initBuilder.withTracing("Doing '$commandName' asynchronously")
} else {
    initBuilder
}

implicit val reqCtx: RequestContext = reqCtxBuilder.build()

dispatcher
    .status(commandId)
    .transform {
        case Success(Right(Some(commandAggregatedStatus))) =>
            val handledResult: Option[_] = for {
                commandResultAsJson <- commandAggregatedStatus.value
                commandResult <- commandResultAsJson.as[CommandResult].toOption
            } yield {
                handleCommandResult(commandResult)
            }

            Success(handledResult)

        case Success(Left(error)) =>
            handleCommandError(error)
            Success(None)

        case _ =>
            Success(None)
    }(ec)

PollStatus

Возвращает статус CommandAggregatedStatusJson команды по ее CommandId с задержкой Поведение команды и ее результат зависят от ситуации: * Если найден результат команды, то сразу же без задержки возвращает его. * Если результат не найден, то ждет его в течении timeout. Если по его прошествию результат все еще не найден, то возвращает последний статус, если он есть.

Получение результата или статуса команды

import com.embedika.verdi.models.debug.TracingContext
import com.embedika.verdi.models.{RequestContext, RequestContextBuilder}
import com.embedika.verdi.models.command._
import com.embedika.verdi.senderlib.Dispatcher

import scala.concurrent.ExecutionContext
import scala.concurrent.Future
import scala.concurrent.duration._
import io.circe.Decoder
import io.circe.syntax._

import scala.util.{Failure, Success}

case class CommandResult(res: Int)

object CommandResult {
    implicit val decoder: Decoder[CommandResult] = ???
}

val ec: ExecutionContext = ???
val dispatcher: Dispatcher = ???

val commandId: CommandId = ???
def handleCommandResult[A](r: CommandResult): A = ???
def handleCommandError[A](error: ErrorResponse): A = ???

val durationTracingEnable: Boolean = ???

val initBuilder = RequestContext.builder()
val reqCtxBuilder = if (durationTracingEnable) {
    initBuilder.withTracing("Doing '$commandName' asynchronously")
} else {
    initBuilder
}

implicit val reqCtx: RequestContext = reqCtxBuilder.build()

dispatcher
    .pollStatus(commandId, 5.seconds)
    .transform {
        case Success(Right(Some(commandAggregatedStatus))) if commandAggregatedStatus.status == CommandStatus.Completed =>
          val handledResult: Option[_] = for {
            commandResultAsJson <- commandAggregatedStatus.value
            commandResult <- commandResultAsJson.as[CommandResult].toOption
          } yield handleCommandResult(commandResult)

          Success(handledResult)

        case Success(Left(error)) =>
            handleCommandError(error)
            Success(None)

        case _ =>
            Success(None)
    }(ec)

models.command

Структуры, которые описывают команды.

CommandId

Содержит идентификатор команды.

Название поля Описание
raw ID в виде строки

CommandName

Содержит наименование команды.

Название поля Описание
raw Имя в виде строки

CommandAggregatedStatus

Содержит последний известный результат выполнения команды.

Название поля Описание
status Статус выполнения команды
timestamp Время получения результата команды (кол-во миллисекунд с 1970-01-01T00:00:00Z). Для HTTP команд это время получения ответа, а для Kafka - время события завершения команды.
value Опциональный результат выполнения команды. Может быть как JSON строкой, так и JSON объектом.
httpHeaders Заголовки HTTP ответа команды, которые нужно передавать клиенту также в виде заголовков HTTP. На APIGateway данное поле переносится из тела ответа в заголовки.

CommandAggregatedStatusJson

Содержит наименование команды.

Название поля Описание
raw JSON представление CommandAggregatedStatus в виде строки.

CommandEvent

Содержит описание события по команде.

Если размер контента в поле "value" превышает допустимый лимиты Kafka topic, то значение поля "value" будет заменено но стандратное сообщение:
"The command response size ($valueBytes) exceeded $valueMaxBytes bytes limit. The response could not be sent.".
В случае, если "value" содержит описание ошибки в структуре ErrorResponse, то эта структура будет сохранена, но будут заменены поля: "message" = стандартное сообщение,
"stackTrace" = null.

Название поля Описание
id ID события
status Новый статус выполнения команды
timestamp Время изменения статуса команды
value Опциональный результат выполнения команды, которы соответствует статусу. Может быть как JSON строкой, так и JSON объектом.

CommandInfo

Содержит описание команды.

Название поля Описание
незаполненная таблица

CommandStatus

Описывает статус выполнения команды.

Возможные значения Описание Дополнительно
Created Команда создана Обязательный начальный статус
InProcess Началась обработка команды Необязательный промежуточный статус
Completed Команда завершена Конечный статус. Считается успешным.
Failed Команда завершена с ошибкой Конечный статус. Считается неуспешным.
TimedOut Команда не завершилась за заданное время. Выполнение прекращено. Конечный статус. Считается неуспешным.

ErrorResponse

Ответ команды с ошибкой в качестве результата.

Название поля Тип Обязательное Описание
code ErrorResponseCode да Тип ошибки
message String нет Сообщение об ошибке (см. https://confluence.dev.embedika.ru/pages/viewpage.action?pageId=889782432)
stackTrace String нет Информация о стеке вызовов во время ошибки
businessError businesserror нет Константа описывающая бизнес-ошибку (контекстно-специфичный код ошибки)
data Json нет Данные, которые необходимо передавать клиенту вместе с ошибкой
cause Throwable нет Поле не участвует в сериализации. Содержит исключение, которое является причиной ошибки.

ErrorResponseCode

Код обозначающий тип ошибки в ответе.

Возможные значения Тип Описание
InvalidParameters String Для команды переданы неверные параметры.
NotAvailableDestinations String Нет ни одного доступного получателя для данной команды.
NotValidResponse String Некорректный HTTP ответ по команде.
CannotWaitCommandCompletion String Async команда не успела завершится за определенное время.
CannotSend String Невозможно отправить команду или результат ее работы. Содержит описание причины.
Exception String Необработанный exception. Может содержать Throwable и его сообщение, являющийся причиной ошибки.
HttpError(statusCode: Int) Json Результат команды следует интерпретировать как HttpResponse с определенным статусом.

BusinessError

Значение описывающий бизнес-ошибку (контекстно-специфичный код ошибки). Соответствует типу String.

Список используемых значений для ошибок учетной записи пользователя:

Список используемых значений для ошибок лицензионных ограничений:

models.dispatch

Структуры, которые описывают способ отправки команд.

DispatchError

Содержит идентификатор команды.

Возможные значения Описание
InvalidParameters Для команды переданы неверные параметры
NotAvailableDestinations Нет ни одного доступного получателя для данной команды
NotValidResponse Некорректный HTTP ответ по команде
CannotWaitCommandCompletion Команда не завершена
CannotSend Невозможно отправить команду или результат ее работы. Содержит описание причины.
Exception Необработанный exception. Содержит Throwable, являющийся причиной ошибки.

DispatchType

Описывает тип отправки команды

Возможные значения Описание
Http Отправка команды с помощью HTTP (HTTP request)
Kafka Отправка команды с помощью Kafka (Kafka message)

HttpDispatchParameters

Содержит параметры отправки команды по HTTP.

Возможные значения Описание
незаполненная таблица

HttpMethod

Описывает используемый метод HTTP

Возможные значения Описание
GET GET запрос
POST POST запрос

KafkaDispatchParameters

Содержит параметры отправки команды через Apache Kafka.

Название поля Описание
незаполненная таблица

models.service

Структуры, которые описывают принимающий команды сервис.

ServiceId

Содержит идентификатор сервиса. Например, "documents-service-instance-1".

Название поля Описание
raw ID в виде строки

ServiceName

Содержит наименование сервиса. Например, "documents-service".

Название поля Описание
raw Имя в виде строки

ServiceAddress

Содержит адрес сервиса. Например, "192.168.0.1".

Название поля Описание
raw Адрес в виде строки

DiscoverableService

Описание сервиса, который можно найти в реестре сервисов.

Название поля Описание
незаполненная таблица

GeneralStructs

Общие структуры, не привязанные к какой-либо сущности.

AsyncStoppable

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

Имеет метод def stop(): Future[Boolean], который останавливает текущую операцию.

SyncStoppable

Интерфейс описывающий процесс, который можно синхронно прервать

Senderlib-kafka

KafkaAuthConfig (senderlib)

Параметры для авторизации kafka-клиента (доступ к топикам).

Поле Тип Обязательное Описание Ограничения
passwordBased PasswordBasedCredentials Нет Реквизиты для аутентификации в kafka с помощью пароля Должно быть заполнено, если не заполнено kerberosBased
kerberosBased KerberosBasedCredentials Нет Реквизиты для аутентификации в kafka с помощью kerberos Должно быть заполнено, если не заполнено passwordBased
truststore TrustStoreConfig Нет Параметры для хранилища сертификатов
topic string Нет Название топика, к которому привязаны данные
kind string Нет Тип сущности, к которой привязаны данные "producer" или "consumer" или "both"(равнозначно параметрам, валидным для "producer" и "consumer") или "admin"(не входит в "both")

PasswordBasedCredentials (senderlib)

Поле Тип Обязательное Описание Ограничения
user string Да Имя пользователя
password string Да Пароль пользователя

KerberosBasedCredentials (senderlib)

Поле Тип Обязательное Описание Ограничения
principal string Да Kerberos principal, соответствующий пользователю
keytabPath string Да Путь до файла keytab

TrustStoreConfig (senderlib)

Параметры для хранилища сертификатов (Java key store)

Поле Тип Обязательное Описание Ограничения
location string Да Путь до хранилища сертификатов
password string Нет Пароль к хранилищу сертификатов

KafkaAuthSettings (senderlib)

Параметры для авторизации kafka-клиента (доступ к топикам).

Поле Тип Обязательное Описание Ограничения
staticAuth KafkaAuthConfig Нет Данные для статической аутентификации (не зависит от топика)
authMode string Нет Режим аутентификации "Static"(одна учетная запись на все запросы) или "Mapping"(учетная запись зависит от запроса)
authConfig string Нет Данные для аутентификации в указанном режиме, если он отличается от KafkaAuthMode.Static Строка в формате JSON с типом List[KafkaAuthConfig]
clientsCache VerdiCacheConfig Нет Настройки кеширования Kafka-клиентов

RetrySettings (senderlib)

Настойки для повтороного вызова функций

Поле Тип Обязательное Описание Ограничения
attempts string Да Максимальное количество повторных вызовов. Чтобы исключить возможность повторного вызова, нужно установить значение 0.
delay duration string Да Константная задержка перед повторным вызовом

CommandResultRetryConditionKind (senderlib)

Вид условия, по которому результат команды будет считаться неуспешным и команду следует вызвать повторно.
Соответствует типу String.

Возможные значения Описание
OnFailStatuses Если результат команды ErrorResponse или результат имеет CommandStatus, который является неуспешным
OnAllExceptions Если результат команды ErrorResponse и имеет ErrorResponseCode = Exception
OnSomeExceptions(Name1, Name2, ..) Содержит список значений с разделителем , (запятая). Если результат команды ErrorResponse, имеет ErrorResponseCode = Exception. Значения в полях message или cause должны содержать одно из значений.

SenderLibSettings

Настойки для создания senderlib-объектов через VerdiFactory. Для создания SenderLibSettings используется конфиг com.typesafe.config.Config.

Поле Тип Обязательное Значение по умолчанию Описание Ограничения
allowInternalCommands bool да Возможность отправлять внутренние команды
commandsCacheUpdatePeriod duration string да "0 ns" Период обновления кеша с информацией о командах
servicesCacheUpdatePeriod duration string да "0 ns" Период обновления кеша с информацией о сервисах
commandsPrefix string нет "commands" Префикс в kv хранилище для команд
consulConnectionMaxRetry int нет 5 Максимальное кол-во попыток подключения к Consul
consulConnectionRetryDelay duration string нет "1 seconds" Фиксированные интервалы между попытками подключения к Consul
kafkaSyncPollingTimeout duration string нет "10 seconds" Время ожидания завершения kafka-команд, которые клиент отправил "синхронно"
httpCommandsRetryAttempts int нет 5 Максимальное количество повторных вызовов для HTTP команд
httpCommandsRetryDelay duration string нет "5 seconds" Константная задержка перед повторным вызовом HTTP команды
httpCommandsRetryKind int нет "OnSomeExceptions(ConnectException)" Вид условия, по которому результат команды будет считаться неуспешным и команду следует вызвать повторно
considerAllCommandsAsInternal bool нет false Флаг настройки отправки всех команд как внутренних

Similarity-plugin: плагин пересечений по смыслу

Плагин отвечает за обработку одного из возможных шагов сервиса индексации - шага с payload-типом Plugin.

Плагин читает из kafka-топика сообщения от сервиса Indexation, содержащие stepProgress, и обрабатывает файловые поля сущности stepProgress.entityObject. Обрабатываются только поля, содержащиеся в step.payload.fields. Во время обработки плагин обращается к Lamp, чтобы найти файловые поля других сущностей, содержимое файлов в которых по смыслу похоже на содержимое файлов соответствующих полей step.payload.fields у сущности stepProgress.entityObject. После этого, если степень похожести файлов превышает APP_MEASURE_THRESHOLD, между файловыми полями step.payload.fields сущности stepProgress.entityObject и найденными файловыми полями других сущностей создаются ссылки в data-model.

Подробнее процесс обработки сообщений описан в документации трейта BaseFlow проекта IntelligentPluginCore.

Конфигурирование SimilarityPlugin

Требования к запуску SimilarityPlugin

Запуск из консоли с помощью SBT

sbt boot/run

При запуске сервиса ожидается, что уже развернута необходимая инфраструктура:

Список переменных окружения для сервиса SimilarityPlugin

Переменная Тип Обязательная Значение по умолчанию Описание
CONSUMER_TOPIC string Нет similarityPlugin Топик, в который поступает StepProgress на обработку.
CONSUMER_GROUP string Нет similarityPlugin Имя группы-консьюмеров сервиса similarityPlugin.
LAMP_USE_VERSION_2 boolean Нет false Использовать ли LAMP2 (true) или LAMP1 (false).
LAMP_BUFFER_SIZE int Нет 10 Буфер на отправку сообщений в клиент LAMP.
LAMP_RECONNECT_SCHEDULE string Нет I(2 seconds) Стратегия переподключения клиента LAMP (формат см. lamp.transport.model.Schedule).
LAMP_HOST string Нет lamp-dev.dev.embedika.ru Адрес клиента LAMP (должен быть непустым, если LAMP_ENABLE=true).
LAMP_PORT int Нет 443 Порт клиента LAMP (должен быть непустым, если LAMP_ENABLE=true).
LAMP_TLS boolean Нет true Признак защищенного подключения к LAMP.
LAMP_TLS_CERTIFICATE string Нет Путь файла с сертификатом для подключения к LAMP.
LAMP_TLS_PRIVATE_KEY string Нет Путь файла с приватным ключом для подключения к LAMP.
LAMP_TLS_ROOT_TRUSTED_CERTS string Нет Путь файла с центром сертификации (Certification Authority, CA) для подключения к LAMP.
LAMP_TIMEOUT duration string Нет 1 minute Таймаут отправки сообщения и получения результатов через клиент LAMP.
LAMP_MAX_MESSAGE_SIZE int Нет 524288000 Максимальный допустимый размер сообщений в LAMP.
LAMP_CACHEABLE_SERVICES string Нет extraction,keywords,lemmatization Строка, содержащая список сервисов LAMP, результаты которых будут кэшироваться внутри LAMP. При вызове одного рута LAMP может происходить обращение к нескольким сервисам LAMP.
LAMP_PARAMETERS_OPERATION string Нет faiss Название операции, которое в качестве параметра передается в Lamp.
APP_LINK_TYPE string Нет similarity Тип ссылки, создаваемой плагином в data-model.
APP_LINK_OWNER string Нет faiss_similarity Link owner ссылки, создаваемой плагином в data-model.
APP_MEASURE_NAME string Нет similarity measureName, которое будет использовано в объекте, лежащем в поле additionalData при создании ссылки в data-model.
APP_MEASURE_THRESHOLD float Нет 0.5 Пороговое значение measure. Ссылки создаются только между документами, мера схожести между которыми больше или равна этому значению.
APP_LAMP_ROUTE string Нет faiss_search_route Рут Lamp, к которому обращается плагин с запросом поиска пересекающихся файлов.
APP_CREATE_LINKS_PER_MESSAGE int Нет 100 Размер батча для запроса к data-model c командой createObjectsLinks.
PLUGIN_INFO_READABLE_NAME string Нет Плагин для построения ссылок между объектами, близкими по смыслу Значение в поле name у тех. константы плагина.
PLUGIN_INFO_DESCRIPTION string Нет Проходит по всем объектам и строит ссылки между ними на основе близости по смыслу их файлов Значение в поле description у тех. константы плагина.
PLUGIN_INFO_VERSION int Нет 1 Значение в поле serviceVersion у тех. константы плагина.
APP_INDEXATION_CHUNK_SIZE int Нет 100 Значения, поступающие в топик CONSUMER_TOPIC, обрабатываются батчами. Батч поступает в обработку либо если из топика было получено количество сообщений равное максимальному размеру батча, либо если от получения первого элемента батча прошло время равное максимальной разнице получения элементов в батче. Эта переменная устанавливает максимальный размер батча.
APP_INDEXATION_WITHIN duration string Нет 1 minutes Значения, поступающие в топик CONSUMER_TOPIC, обрабатываются батчами. Батч поступает в обработку либо если из топика было получено количество сообщений равное максимальному размеру батча, либо если от получения первого элемента батча прошло время равное максимальной разнице получения элементов в батче. Эта переменная устанавливает максимальную разницу времени получения элементов в батче.
APP_MAX_RETRY int Нет 2 Максимальное количество ретраев, которое произойдет при обращении к LAMP, если он возвращает ошибку.
CONSUMER_PROGRESS_TOPIC string Нет progress Топик, в который плагин пишет об окончании обработки.
PRODUCER_INDEXATION_EVENT_TOPIC string Нет entityObjectEvent Топик, в который плагин отправляет запрос на переиндексацию backlinks.
VERDI_HOST string Нет localhost Адрес, который будет зарегистрирован за данным экземпляром сервиса.
VERDI_TTL duration string Нет 30 seconds Время, в течение которого экземпляр сервиса считается "активным". Таймер обновляется каждый раз, когда сервис присылает "health check".
VERDI_HEALTH_CHECK duration string Нет 10 seconds Периодичность отправки "health check".
VERDI_CONSUL string Нет http://localhost:8500 Адрес Consul.
VERDI_CONSUL_AUTH_USER string Нет Название учетной записи Сonsul. Если название не указано, то настройки авторизации не будут применены.
VERDI_CONSUL_AUTH_PASSWORD string Нет Пароль учетной записи Сonsul.
VERDI_KAFKA_ADDRESS string Нет localhost:9092 Адрес Kafka.
VERDI_KAFKA_TOPIC string Нет commandevents Название топика для отправки сообщений со статусом команд.
VERDI_KAFKA_PRODUCER_PROPS string Нет max.request.size=1048576 Дополнительные параметры для Kafka producer. Заполняются по шаблону "key1=value1;key2=value2".
VERDI_KAFKA_AUTH_USER string Нет Название учетной записи Kafka. Если название не указано, то настройки авторизации не будут применены.
VERDI_KAFKA_AUTH_PASSWORD string Нет Пароль учетной записи Kafka.
VERDI_KAFKA_AUTH_PRINCIPAL string Нет Principal учетной записи Kafka в Kerberos (в случае соединения с kafka через Kerberos).
VERDI_KAFKA_AUTH_KEYTAB_PATH string Нет Путь до keytab-файла (в случае соединения с kafka через Kerberos).
VERDI_KAFKA_AUTH_TRUSTSTORE_LOCATION string Нет Путь до хранилища сертификатов (Java key store). Если путь не указан, то сертификат применяться не будет.
VERDI_KAFKA_AUTH_TRUSTSTORE_PASSWORD string Нет Пароль к хранилищу сертификатов.
VERDI_KAFKA_AUTH_MODE string Нет static Режим аутентификации: static - одна учетная запись на все запросы, mapping - учетная запись зависит от запроса.
VERDI_KAFKA_AUTH_CONFIG string Нет Настройки для аутентификации: если AuthMode = mapping, то необходим JSON с List[KafkaAuthConfig]. Переменная соответствует полю authConfig из KafkaAuthSettings.
VERDI_KAFKA_AUTH_CACHE_SIZE int Нет Максимальный размер кэша для Kafka producer (количество активных соединений).
VERDI_KAFKA_AUTH_CACHE_TTL duration string нет Время жизни Kafka producer в кэше.
VERDI_ALLOW_INTERNAL_COMMANDS boolean Нет true Можно ли сервису отправлять внутрисистемные команды.
VERDI_CONSIDER_ALL_COMMANDS_AS_INTERNAL boolean Нет false Флаг, определяющий будут ли все обращения в другие сервисы являться внутренними (т.е. не требовать авторизацию). Детальное описание механизма: Внутренние команды.
VERDI_COMMAND_STORAGE_UPDATE_PERIOD duration string Нет 1 minutes Время кэширования данных по командам из CommandDiscovery.
VERDI_SERVICE_DISCOVERY_UPDATE_PERIOD duration string Нет 30 seconds Время кэширования данных по сервисам из ServiceDiscovery.
VERDI_CONSUL_CONNECTION_MAX_RETRY int Нет 5 Максимальное количество попыток подключения к Consul после обрыва соединения.
VERDI_CONSUL_CONNECTION_RETRY_DELAY duration string Нет 1 seconds Задержка перед попыткой подключения к Consul.
VERDI_KAFKA_SYNC_POLL_PERIOD duration string Нет 1 seconds Периодичность запроса статуса команды, отправленной через Kafka.
VERDI_KAFKA_SYNC_POLL_TIMEOUT duration string Нет 1 minute Время ожидания завершения команды, отправленной через Kafka.
VERDI_COMMANDS_HTTP_RETRY_ATTEMPTS int Нет 5 Поле attempts из RetrySettings.
VERDI_COMMANDS_HTTP_RETRY_DELAY duration string Нет 5 seconds Поле delay из RetrySettings.
VERDI_COMMANDS_HTTP_RETRY_KIND string Нет OnSomeExceptions(ConnectException) CommandResultRetryConditionKind.

Команды сервиса SimilarityPlugin

Сервис SimilarityPlugin не содержит в себе никакие команды. Вместо этого он обрабатывает kafka-сообщения, поступающие из сервиса индексации.

Для обработки сообщений SimilarityPlugin использует реализации BaseFlow, предоставляемые IntelligentPluginCore.

Два файла с идентификаторами id1 и id2 в SimilarityPlugin считаются пересекающимися, если:

  1. при запросе c id1 к Lamp в ответ поступило сообщение message с типом FaissMessage
  2. id2 содержится в message.ids
  3. id2 соответствует lampMeasure из message.similarities
  4. при этом lampMeasure >= APP_MEASURE_THRESHOLD.

Tagging-plugin: плагин присвоения тегов файлам

Плагин отвечает за обработку одного из возможных шагов сервиса индексации - шага с payload-типом Plugin.

Плагин читает из kafka-топика сообщения от сервиса indexation, содержащие stepProgress, и обрабатывает файловые поля из stepProgress.files сущности stepProgress.entityObject. Сервис индексации присылает в stepProgress.files только поля, содержащиеся в step.payload.fields.

Во время обработки плагин:

  1. Из каждого полученного stepProgress извлекает список информации о файловых полях из stepProgress.files для последующей обработки.
  2. Для каждого обрабатываемого файлового поля плагин выполняет следующие шаги:
    1. Обращается к S3 и получает метаданные файла. Из них извлекает fileName.
    2. Пытается достать из кэша объект TaggingRules. В случае успеха игнорирует шаги 3-5 и переходит сразу к шагу 6.
    3. В случае отсутствия TaggingRules в кэше плагин обращается к сервису alexandrina и получает список CatalogItem, которые содержатся в справочнике с кодом, равным значению TAGS_CATALOG_CODE. Архивные CatalogItem игнорируются.
    4. У каждого полученного CatalogItem плагин достает из json-поля metadata поле extensions. Поле extensions содержит список расширений файла, которые могут использоваться для того, чтобы сопоставить файлу тэг с идентификатором сatalogItem.code.
    5. Записывает в кэш объект TaggingRules - соответствие между расширением и списком тэгов, которые нужно сопоставить файлу с таким расширением.
    6. Извлекает из fileName, полученного в шаге 1 расширение файла someExtension. Обращается к data-model с командой WriteFileTags и таким образом прикрепляет к файлу все тэги, которые соответствуют расширению someExtension в TaggingRules. У одного файла может быть несколько тэгов.

Конфигурирование TaggingPlugin

Требования к запуску TaggingPlugin

Запуск из консоли с помощью SBT

sbt boot/run

При запуске сервиса ожидается, что уже развернута необходимая инфраструктура:

Список переменных окружения для сервиса TaggingPlugin

Переменная Тип Обязательная Значение по умолчанию Описание
CONSUMER_TOPIC string Нет taggingPlugin Топик, в который поступает StepProgress на обработку.
CONSUMER_GROUP string Нет taggingPlugin Имя группы-консьюмеров сервиса taggingPlugin.
PLUGIN_INFO_READABLE_NAME string Нет Плагин для тегирования файлов Значение в поле name у тех. константы плагина.
PLUGIN_INFO_DESCRIPTION string Нет Проходит по всем файлам и назначаем им теги на основе их расширения Значение в поле description у тех. константы плагина.
PLUGIN_INFO_VERSION int Нет 1 Значение в поле serviceVersion у тех. константы плагина.
TAGS_CATALOG_CODE string Нет FileTags Код справочника в сервисе alexandrina, который хранит доступные в системе тэги.
TAGS_CATALOG_TITLE string Нет Типы файлов Человекочитаемое описание справочника в сервисе alexandrina, который хранит доступные в системе тэги.
TAGS_CACHE_LIFETIME duration string Нет 1 hour Время жизни TaggingRules в кеше.
TAGS_CACHE_FILLTIME duration string Нет 10 seconds Максимальное время выполнения запроса к alexandrina для получения элементов каталога тегов и преобразования их в TaggingRules.
FS_URI url string Нет http://localhost:9000/ Адрес для подключения к хранилищу файлов по S3-API.
FS_ACCESS_KEY_ID string Да Ключ доступа для хранилища файлов (aka логин).
FS_SECRET_ACCESS_KEY string Да Секретный ключ для хранилища файлов (aka пароль).
FS_UPLOAD_PARALLELISM int Нет 4 Параллелизм для загрузки файлов.
FS_AUTH_MODE string Нет static Режим аутентификации: static - одна учетная запись на все запросы, mapping - учетная запись зависит от запроса.
FS_AUTH_CONFIG string Нет Настройки для аутентификации: если AuthMode = mapping, то необходим JSON с маппингом учетных записей.
FS_CACHE_SIZE int Нет 1 Максимальный размер кеша клиентов для хранилища файлов (количество активных соединений).
FS_CACHE_TTL duration string Нет Время жизни клиента в кеше.
FS_RETRY_ATTEMPTS int нет 5 Количество ретраев, которое будет произведено в случае Exception-а в операции FSClient-а и при вычитывании стрима в get операциях FSClient-а.
FS_RETRY_DELAY duration string нет 10 millis Задержка между ретраями операций FSClient-а.
FS_ZIO_SHORT_MESSAGE_MODE boolean нет false Флаг включения режима сохранения ошибок работы с файловым хранилищем в сервисе журналирования nestor. При включении режима ошибки в логах будут отображаться в сокращенном формате: Short zio message mode. ExceptionType: ТИП ОШИБКИ, Exception id: 'СГЕНЕРИРОВАННЫЙ UUID' added to journal. Указанный id будет фиксироваться в event записи nestor'а в поле data.id
APP_INDEXATION_CHUNK_SIZE int Нет 100 Значения, поступающие в топик CONSUMER_TOPIC, обрабатываются батчами. Батч поступает в обработку либо если из топика было получено количество сообщений равное максимальному размеру батча, либо если от получения первого элемента батча прошло время, равное максимальной разнице получения элементов в батче. Эта переменная устанавливает максимальный размер батча.
APP_INDEXATION_WITHIN duration string Нет 1 minutes Значения, поступающие в топик CONSUMER_TOPIC, обрабатываются батчами. Батч поступает в обработку либо если из топика было получено количество сообщений равное максимальному размеру батча, либо если от получения первого элемента батча прошло время, равное максимальной разнице получения элементов в батче. Эта переменная устанавливает максимальную разницу времени получения элементов в батче .
APP_MAX_RETRY int Нет 2 Максимальное количество ретраев, которое произойдет при обращении LAMP, если он возвращает ошибку.
CONSUMER_PROGRESS_TOPIC string Нет progress Топик, в который плагин пишет об окончании обработки.
VERDI_HOST string Нет localhost Адрес, который будет зарегистрирован за данным экземпляром сервиса.
VERDI_TTL duration string Нет 30 seconds Время, в течение которого экземпляр сервиса считается "активным". Таймер обновляется каждый раз, когда сервис присылает "health check".
VERDI_HEALTH_CHECK duration string Нет 10 seconds Периодичность отправки "health check".
VERDI_CONSUL string Нет http://localhost:8500 Адрес Consul.
VERDI_CONSUL_AUTH_USER string Нет Название учетной записи Сonsul. Если название не указано, то настройки авторизации не будут применены.
VERDI_CONSUL_AUTH_PASSWORD string Нет Пароль учетной записи Сonsul.
VERDI_KAFKA_ADDRESS string Нет localhost:9092 Адрес Kafka.
VERDI_KAFKA_TOPIC string Нет commandevents Название топика для отправки сообщений со статусом команд.
VERDI_KAFKA_PRODUCER_PROPS string Нет max.request.size=1048576 Дополнительные параметры для Kafka producer. Заполняются по шаблону "key1=value1;key2=value2".
VERDI_KAFKA_AUTH_USER string Нет Название учетной записи Kafka. Если название не указано, то настройки авторизации не будут применены.
VERDI_KAFKA_AUTH_PASSWORD string Нет Пароль учетной записи Kafka.
VERDI_KAFKA_AUTH_PRINCIPAL string Нет Principal учетной записи Kafka в Kerberos (в случае соединения с kafka через Kerberos).
VERDI_KAFKA_AUTH_KEYTAB_PATH string Нет Путь до keytab-файла (в случае соединения с kafka через Kerberos).
VERDI_KAFKA_AUTH_TRUSTSTORE_LOCATION string Нет Путь до хранилища сертификатов (Java key store). Если путь не указан, то сертификат применяться не будет.
VERDI_KAFKA_AUTH_TRUSTSTORE_PASSWORD string Нет Пароль к хранилищу сертификатов.
VERDI_KAFKA_AUTH_MODE string Нет static Режим аутентификации: static - одна учетная запись на все запросы, mapping - учетная запись зависит от запроса.
VERDI_KAFKA_AUTH_CONFIG string Нет Настройки для аутентификации: если AuthMode = mapping, то необходим JSON с List[KafkaAuthConfig]. Переменная соответствует полю authConfig из KafkaAuthSettings.
VERDI_KAFKA_AUTH_CACHE_SIZE int Нет Максимальный размер кэша для Kafka producer (количество активных соединений).
VERDI_KAFKA_AUTH_CACHE_TTL int Нет Время жизни Kafka producer в кэше.
VERDI_ALLOW_INTERNAL_COMMANDS boolean Нет true Можно ли сервису отправлять внутрисистемные команды.
VERDI_CONSIDER_ALL_COMMANDS_AS_INTERNAL boolean Нет false Флаг, определяющий будут ли все обращения в другие сервисы являться внутренними (т.е. не требовать авторизацию). Детальное описание механизма: Внутренние команды.
VERDI_COMMAND_STORAGE_UPDATE_PERIOD duration string Нет 1 minutes Время кэширования данных по командам из CommandDiscovery.
VERDI_SERVICE_DISCOVERY_UPDATE_PERIOD duration string Нет 30 seconds Время кэширования данных по сервисам из ServiceDiscovery.
VERDI_CONSUL_CONNECTION_MAX_RETRY int Нет 5 Максимальное количество попыток подключения к Consul после обрыва соединения.
VERDI_CONSUL_CONNECTION_RETRY_DELAY duration string Нет 1 seconds Задержка перед попыткой подключения к Consul.
VERDI_KAFKA_SYNC_POLL_PERIOD duration string Нет 1 seconds Периодичность запроса статуса команды отправленной через Kafka.
VERDI_KAFKA_SYNC_POLL_TIMEOUT duration string Нет 1 minute Время ожидания завершения команды отправленной через Kafka.
VERDI_COMMANDS_HTTP_RETRY_ATTEMPTS int Нет 5 Поле attempts из RetrySettings.
VERDI_COMMANDS_HTTP_RETRY_DELAY duration string Нет 5 seconds Поле delay из RetrySettings.
VERDI_COMMANDS_HTTP_RETRY_KIND string Нет OnSomeExceptions(ConnectException) CommandResultRetryConditionKind.
JOURNAL_MODE string нет WriteToJournal Режим журналирования Nestor. Допустимые значения: WriteToJournal (Отправка в сервис журналирования), WriteToTopic (Отправка события в очередь)
JOURNAL_TOPIC string да, если переменная JOURNAL_MODE = WriteToTopic "" Название очереди журналирования. Для режима WriteToJournal значение игнорируется.

Модели сервиса TaggingPlugin

TaggingRules (tagging-plugin)

Соответствует типу Map[String, Set[String]]. Ключом в данном Map является строка с расширением файла, а значением - набор идентификаторов тэгов, соответствующих этому расширению.

CatalogItem (tagging-plugin)

Элемент справочника. Копия модели CatalogItem из сервиса alexandrina без поля isProtected.

Поле Тип Обязательное Значение по умолчанию Описание Ограничения
id uuid string да ID элемента справочника
catalogId uuid string да ID справочника Комбинация catalogId и code каждого элемента справочника должна быть уникальной.
code string да Строковый код элемента Длина не более 32 символов.
Комбинация catalogId и code каждого элемента справочника должна быть уникальной.
title string да Человекочитаемое название элемента Длина не более 200 символов.
archived boolean да Признак архивности
metadata json object да Дополнительные данные справочника - объект JSON
created TimeStamp нет TimeStamp.now Дата создания элемента справочника
modified TimeStamp нет TimeStamp.now Дата последнего изменения элемента справочника
version integer нет 1 Версия данных элемента. Нужна для оптимистичных блокировок

Tech-constants: сервис технического справочника

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

Пример использования:
Для функциональности журналирования сервисы регистрируют константы типа journalEventType с наименованием и шаблоном описания событий, которые используются на фронтенде для отображения необходимой информации в человекочитаемом виде.

Информация по добавлению команд можно прочитать в описании шаблона.

Конфигурирование TechConstants

Требования к запуску TechConstants

Запуск из консоли с помощью SBT

TECH_CONSTANTS_DB_HOST=localhost
TECH_CONSTANTS_DB_PORT=5432
TECH_CONSTANTS_DB_NAME=techConstants_db
TECH_CONSTANTS_DB_USER=$TECH_CONSTANTS_DB_USER
TECH_CONSTANTS_DB_PASSWORD=$TECH_CONSTANTS_DB_PASSWORD
sbt boot/run

При запуске сервиса ожидается, что уже развернута необходимая инфраструктура:

Список переменных окружения для сервиса TechConstants

Переменная Тип Обязательная Значение по умолчанию Описание
TECH_CONSTANTS_HTTP_HOST string Нет 0.0.0.0 Хост для HttpListener.
TECH_CONSTANTS_HTTP_PORT int Нет 8192 Порт для HttpListener.
TECH_CONSTANTS_KAFKA_SERVERS string Нет localhost:9092 Адрес Kafka.
TECH_CONSTANTS_KAFKA_TOPIC string Нет tech_constants_commands Название топика для команд.
TECH_CONSTANTS_KAFKA_TOPIC_PARTITIONS int Нет 10 Количество партиций в топике команд.
TECH_CONSTANTS_KAFKA_CONSUMER_GROUP string Нет tech_constants_consumer_group Название consumer-группы для чтения команд.
TECH_CONSTANTS_KAFKA_COMMANDEVENT_TOPIC string Нет commandevents Название топика для отправки сообщений со статусом команд.
TECH_CONSTANTS_KAFKA_CONSUMER_RESTART_MIN_BACKOFF duration string Нет 1 second Минимальная задержка перед перезапуском.
TECH_CONSTANTS_KAFKA_CONSUMER_RESTART_MAX_BACKOFF duration string Нет 30 seconds Максимально возможная задержка перед перезапуском.
TECH_CONSTANTS_KAFKA_CONSUMER_RESTART_RANDOM_FACTOR double Нет 0.2 Коэффициент величины дополнительной случайной задержки (jitter) относительно основной задержки (При значении 0.2 задержка может быть до 20% больше, чем при 0). Если после умножения задержки на TECH_CONSTANTS_KAFKA_CONSUMER_RESTART_RANDOM_FACTOR получится меньше 1 миллисекунды, то jitter будет приравнен к нулю.
TECH_CONSTANTS_KAFKA_CONSUMER_RESTART_MAX_RESTARTS int Нет 5 Максимальное количество перезапусков в заданный период времени. После превышения этого числа сервис будет объявлен больным. Все рестарты для каждого отдельного сообщения увеличивают и общий счетчик рестартов консьюмера, поэтому при использовании TECH_CONSTANTS_KAFKA_CONSUMER_PER_MESSAGE_RESTART_MAX_RESTARTS нужно указывать TECH_CONSTANTS_KAFKA_CONSUMER_RESTART_MAX_RESTARTS > TECH_CONSTANTS_KAFKA_CONSUMER_PER_MESSAGE_RESTART_MAX_RESTARTS или не указывать TECH_CONSTANTS_KAFKA_CONSUMER_PER_MESSAGE_RESTART_MAX_RESTARTS совсем.
TECH_CONSTANTS_KAFKA_CONSUMER_RESTART_MAX_RESTARTS_WITHIN duration string Нет 5 minutes Период времени для ограничения перезапусков.
TECH_CONSTANTS_KAFKA_CONSUMER_PER_MESSAGE_RESTART_MAX_RESTARTS int Нет 2 Максимальное количество раз, которое консьюмер перезапустится с неизменной очередью сообщений (в пределах DATA_MODEL_KAFKA_CONSUMER_RESTART_MAX_RESTARTS_WITHIN), прежде чем проигнорировать сообщение, на котором происходит ошибка (Указано количество рестартов, а не прочтений. Если TECH_CONSTANTS_KAFKA_CONSUMER_RESTART_MAX_RESTARTS = 2, то ошибочное сообщение будет обработано 3 раза, после чего произойдет 3ий рестарт и оно будет проигнорировано). Если указать 0, то перезапуск произойдет, но сообщение будет обработано только в первый раз, когда произошла ошибка. Если указать значение меньше 0, то перезапуски все равно будут происходить, но игнорирование сообщений, вызывающих ошибку, будет отключено.
TECH_CONSTANTS_KAFKA_CONSUMER_PER_MESSAGE_RESTART_CACHE_SIZE int Нет 100 Для каждого сообщения счетчик перепрочтений хранится в кэше. Максимальное количество значений в этом кэше.
TECH_CONSTANTS_KAFKA_CONSUMER_PER_MESSAGE_RESTART_CACHE_TTL duration string Нет 5 minutes Для каждого сообщения счетчик перепрочтений хранится в кэше. Максимальное время жизни элемента в этом кэше. В случае отсутствия значения время жизни элемента не будет ограничено.
TECH_CONSTANTS_KAFKA_CONSUMER_POLL_TIMEOUT duration string нет 10 milliseconds timeout запроса poll для kafka consumer
TECH_CONSTANTS_KAFKA_CONSUMER_POLL_INTERVAL duration string нет 100 milliseconds интервал между запросами poll для kafka consumer
TECH_CONSTANTS_KAFKA_CONSUMER_PROPS string нет "max.poll.records=500;max.partition.fetch.bytes=524288" дополнительные параметры для kafka consumer в формате "key1=value1;key2=value2"
TECH_CONSTANTS_KAFKA_CONNECTION_CHECK_TEST_MESSAGES_INTERVAL duration string Нет 4 minutes Применяется только для producer-ов со способом аутентификации kerberos. Интервал отправки тестовых сообщений кафки в топик connectionCheck.testMessagesTopicName. Тестовые сообщения (null, service producer test) отправляются регулярно с этим интервалом.
TECH_CONSTANTS_KAFKA_CONNECTION_CHECK_INTERVAL duration string Нет 60 seconds Применяется только для producer-ов со способом аутентификации kerberos. Интервал проверки того, сколько тестовых сообщений было отправлено за данный период. Если количество сообщений за этот период равно количеству сообщений за прошлый период, то начинается отсчет периода без сообщений.
TECH_CONSTANTS_KAFKA_CONNECTION_CHECK_FAILED_AFTER_INTERVAL duration string Нет 5 minutes Применяется только для producer-ов со способом аутентификации kerberos. Максимальная продолжительность периода без успешно отправленных тестовых сообщений. По ее достижении сервис будет объявлен больным.
TECH_CONSTANTS_KAFKA_AUTH_USER string Нет Название учетной записи Kafka. Если название не указано, то настройки авторизации не будут применены.
TECH_CONSTANTS_KAFKA_AUTH_PASSWORD string Нет Пароль учетной записи Kafka.
TECH_CONSTANTS_KAFKA_AUTH_PRINCIPAL string Нет Principal учетной записи Kafka в Kerberos (в случае соединения с kafka через Kerberos).
TECH_CONSTANTS_KAFKA_AUTH_KEYTAB_PATH string Нет Путь до keytab-файла (в случае соединения с kafka через Kerberos).
TECH_CONSTANTS_KAFKA_AUTH_TRUSTSTORE_LOCATION string Нет Путь до хранилища сертификатов (Java key store). Если путь не указан, то сертификат применяться не будет.
TECH_CONSTANTS_KAFKA_AUTH_TRUSTSTORE_PASSWORD string Нет Пароль к хранилищу сертификатов.
TECH_CONSTANTS_KAFKA_AUTH_MODE string Нет static Режим аутентификации: static - одна учетная запись на все запросы, mapping - учетная запись зависит от запроса.
TECH_CONSTANTS_KAFKA_AUTH_CONFIG string Нет Настройки для аутентификации: если AuthMode = mapping, то необходим JSON с List[KafkaAuthConfig]. Переменная соответствует полю authConfig из KafkaAuthSettings.
TECH_CONSTANTS_KAFKA_AUTH_CACHE_SIZE int Нет Максимальный размер кэша для Kafka producer (количество активных соединений).
TECH_CONSTANTS_KAFKA_AUTH_CACHE_TTL duration string Нет Время жизни Kafka producer в кэше.
TECH_CONSTANTS_CONSUL_ADDR string Да http://localhost:8500 Адрес Сonsul.
TECH_CONSTANTS_CONSUL_AUTH_USER string Нет Название учетной записи Сonsul. Если название не указано, то настройки авторизации не будут применены.
TECH_CONSTANTS_CONSUL_AUTH_PASSWORD string Нет Пароль учетной записи Сonsul.
TECH_CONSTANTS_TRACE_DURATION boolean Нет false Признак необходимости трассировки выполнения команд.
TECH_CONSTANTS_DISCOVERABLE_ID string Нет another_tech_constants_instance Id сервиса в ServiceDiscovery.
TECH_CONSTANTS_DISCOVERABLE_NAME string Нет techConstants Имя сервиса в ServiceDiscovery.
TECH_CONSTANTS_DISCOVERABLE_HOST string Да localhost Хост, публикуемый в ServiceDiscovery.
TECH_CONSTANTS_DISCOVERABLE_PORT int Нет ${TECH_CONSTANTS_HTTP_PORT} Порт, публикуемый в ServiceDiscovery.
TECH_CONSTANTS_DISCOVERABLE_LIVETIME duration string Нет 2 minutes Период после отправки health check, в течение которого ServiceDiscovery считает сервис живым.
TECH_CONSTANTS_DISCOVERABLE_HEALTHPASS duration string Нет 1 minute Периодичность отправки health check в ServiceDiscovery.
TECH_CONSTANTS_AKKA_HTTP_CLIENT_MAXCON int Нет 512 Максимальное число одновременных исходящих HTTP-соединений.
TECH_CONSTANTS_AKKA_HTTP_CLIENT_MAXREQ int Нет 1024 Максимальное число одновременных исходящих HTTP-запросов.
TECH_CONSTANTS_AKKA_HTTP_SERVER_MAXCON int Нет 1024 Максимальное число одновременных входящих HTTP-соединений.
TECH_CONSTANTS_INTERNALCMD_ALLOW boolean Нет true Можно ли сервису отправлять внутрисистемные команды.
TECH_CONSTANTS_SENDERLIB_CONSIDER_ALL_COMMANDS_AS_INTERNAL boolean Нет false Флаг, определяющий будут ли все обращения в другие сервисы являться внутренними (т.е. не требовать авторизацию). Детальное описание механизма: Внутренние команды.
TECH_CONSTANTS_SENDERLIB_COMMANDS_CACHE_UPDATEPERIOD duration string Нет 10 minutes Время кэширования данных по командам из CommandDiscovery.
TECH_CONSTANTS_SENDERLIB_SERVICES_CACHE_UPDATEPERIOD duration string Нет 30 seconds Время кэширования данных по сервисам из ServiceDiscovery.
TECH_CONSTANTS_SENDERLIB_COMMANDS_HTTP_RETRY_ATTEMPTS int Нет 5 Поле attempts из RetrySettings.
TECH_CONSTANTS_SENDERLIB_COMMANDS_HTTP_RETRY_DELAY duration string Нет 5 seconds Поле delay из RetrySettings.
TECH_CONSTANTS_SENDERLIB_COMMANDS_HTTP_RETRY_KIND string Нет OnSomeExceptions(ConnectException) CommandResultRetryConditionKind.
TECH_CONSTANTS_SENDERLIB_CONSUL_CONNECTION_RETRY_MAX int нет 5 Количество попыток переподключения к Consul
TECH_CONSTANTS_SENDERLIB_CONSUL_CONNECTION_RETRY_DELAY duration string нет 1 second Задержка при попытках переподключения к Consul
TECH_CONSTANTS_DB_URL string Нет Адрес базы данных. Можно использовать вместо TECH_CONSTANTS_DB_HOST, TECH_CONSTANTS_DB_PORT и TECH_CONSTANTS_DB_NAME.
TECH_CONSTANTS_DB_HOST string Да Хост сервера базы данных.
TECH_CONSTANTS_DB_PORT int Да Порт сервера базы данных.
TECH_CONSTANTS_DB_NAME string Да Название базы данных.
TECH_CONSTANTS_DB_USER string Да Пользователь базы данных.
TECH_CONSTANTS_DB_PASSWORD string Да Пароль для пользователя базы данных.
TECH_CONSTANTS_DB_THREADS int Нет 10 Количество потоков в пуле потоков для соединения с БД.
TECH_CONSTANTS_DB_QUEUE_SIZE int Нет 300 Размер очереди для действий базы данных, которые не могут быть выполнены немедленно, когда все потоки заняты. За пределами этого значения новые действия немедленно завершаются неудачей.
TECH_CONSTANTS_DB_CONN_MAX int Нет 10 Максимальное количество одновременных подключений к БД.
TECH_CONSTANTS_DB_CONN_TIMEOUT duration string Нет 20 second Максимальное время ожидания ответа для соединения к БД. Если это время превышено, а соединение не становится доступным, будет брошено исключение SQLException. 1000 мс — минимальное значение.
TECH_CONSTANTS_DB_ISOLATION string Нет READ_COMMITTED Уровень изоляции транзакций для новых подключений. Допустимые значения: NONE, READ_COMMITTED, READ_UNCOMMITTED, REPEATABLE_READ, SERIALIZABLE.
TECH_CONSTANTS_DB_READONLY boolean Нет false Read-only SQL транзакция может изменять только временные таблицы. Этот параметр управляет статусом «только для чтения» по умолчанию для каждой новой транзакции.
TECH_CONSTANTS_DB_CONN_MIN int Нет ${TECH_CONSTANTS_DB_THREADS} Минимальное количество одновременных подключений к БД.
TECH_CONSTANTS_DB_VALIDATION_TIMEOUT duration string Нет 1 seconds Максимальное время, в течение которого соединение будет проверяться на работоспособность. 1000 мс — минимальное значение.
TECH_CONSTANTS_DB_IDLE_TIMEOUT duration string Нет 10 minutes Максимальное время, в течение которого соединению разрешено простаивать в пуле. Значение 0 означает, что простаивающие соединения никогда не удаляются из пула.
TECH_CONSTANTS_DB_MAX_LIFETIME duration string Нет 30 minutes Максимальное время жизни соединения в пуле. Когда простаивающее соединение достигает этого времени ожидания, даже если оно недавно использовалось, оно будет удалено из пула. Значение 0 указывает на отсутствие максимального срока службы.
TECH_CONSTANTS_DB_INITIALIZATION_FAIL_FAST boolean Нет false Deprecated, начиная с версии Slick 3.3.0. Определяет, будет ли пул «быстро выходить из строя», если пул не может быть успешно заполнен начальными соединениями. Если соединения не могут быть созданы во время запуска пула, будет выдано исключение RuntimeException. Это свойство не имеет никакого эффекта, если minConnections равно 0.
TECH_CONSTANTS_DB_LEAK_DETECTION_THRESHOLD int Нет 0 Время, в течение которого соединение может находиться вне пула, прежде чем будет зарегистрировано сообщение, указывающее на возможную утечку соединения. Значение 0 означает, что обнаружение утечек отключено. Наименьшее приемлемое значение для включения обнаружения утечек составляет 10 с.
TECH_CONSTANTS_DB_CONNECTION_TEST_QUERY string Нет SELECT 1 Выражение, которое будет выполнено непосредственно перед получением соединения из пула для проверки того, что соединение с базой данных все еще активно. Оно зависит от базы данных и должно представлять собой запрос, требующий минимальной обработки базой данных (например, «VALUES 1»). Если этот параметр не установлен, вместо него используется метод JDBC4 Connection.isValid().
TECH_CONSTANTS_DB_REGISTER_MBEANS boolean Нет false Зарегистрированы ли JMX Management Beans («MBeans»).
TECH_CONSTANTS_DB_AUTO_COMMIT boolean Нет true Это свойство определяет то, как будут вести себя по умолчанию возвращаемые соединения относительно autocommit-а.
TECH_CONSTANTS_DB_SCHEMA string Нет public Устанавливает schema по умолчанию.
TECH_CONSTANTS_DB_ISOLATE_INTERNAL_QUERIES boolean Нет false Определяет то, изолируются ли с помощью транзакций внутренние запросы пула (например, запрос connection alive test). Свойство применяется только если autoCommit выключен.
TECH_CONSTANTS_DB_INITIALIZATION_FAIL_TIMEOUT int Нет 1 Работает, начиная с версии Slick 3.3.0. Определяет, будет ли пул «быстро выходить из строя», если пул не может быть успешно заполнен начальными соединениями. Любое положительное число считается числом миллисекунд для попытки получить начальное соединение; поток приложения будет заблокирован в течение этого периода. Если соединение не может быть получено до истечения этого времени, будет брошено исключение. Данный таймаут применяется после периода connectionTimeout. Если значение равно нулю (0), HikariCP попытается получить и проверить подключение. Если соединение получено, но проверка не пройдена, будет брошено исключение, и пул не будет запущен. Однако, если соединение не может быть получено, пул запустится, но последующие попытки получить соединение могут потерпеть неудачу. Значение меньше нуля пройдет любую первоначальную попытку подключения, и пул немедленно запустится, пытаясь получить соединения в фоновом режиме. Следовательно, последующие попытки получить соединение могут потерпеть неудачу.
TECH_CONSTANTS_SERVER_AUTHORIZER_KIND string нет authzforce Вид авторизатора, который используется в сервисе. Допустимые значения: "authzforce", "oberto". При указании неизвестного значения будет использовано значение по умолчанию.
TECH_CONSTANTS_AUTHZFORCE_ADDR string нет http://localhost:8080/authzforce-ce Адрес AuthZforce server (переменная должна быть непустой, если SERVER_AUTHORIZER_KIND=authzforce).
TECH_CONSTANTS_AUTHZFORCE_DOMAIN string нет Доступный DomainID в AuthZforce server (переменная должна быть непустой, если SERVER_AUTHORIZER_KIND=authzforce).
TECH_CONSTANTS_AUTHZFORCE_CONNECT_TIMEOUT duration string нет 5 seconds Таймаут подключения к authzforce (переменная должна быть непустой, если SERVER_AUTHORIZER_KIND=authzforce).

Команды сервиса TechConstants

Список реализованных в сервисе команд, моделей EntityType и действий Actions, которые можно использовать при настройке авторизации.
Не все поля EntityType доступны для использования в настройке авторизации.
Если указан прочерк "-", то данное значение не влияет на авторизацию:

Назначение команды Имя вызова команды EntityType Actions
Регистрация сервиса techConstants_UpsertService - -
Получение списка сервисов techConstants_ListServices - -
Удаление сервиса techConstants_DeleteService - -
Регистрация типа констант techConstants_UpsertConstantType - -
Получение списка типов констант techConstants_ListConstantTypes - -
Удаление типа констант techConstants_DeleteConstantType - -
Автоматическая регистрация константы techConstants_UpsertAutoConstant Constant UpdateConstant
Автоматическая регистрация константы (внутренняя) techConstants_UpsertAutoConstant_Internal Constant UpdateConstant
Ручная регистрация константы techConstants_UpsertManualConstant Constant UpdateConstant
Получение константы techConstants_GetConstant Constant GetConstant
Получение константы (внутренняя) techConstants_GetConstant_Internal - -
Получение списка констант techConstants_ListAllConstants Constant ListConstants
Получение списка констант (внутренняя) techConstants_ListAllConstants_Internal - -
Получение всех констант определенного типа techConstants_ListConstantsByType Constant ListConstants
Получение всех констант определенного типа (внутренняя) techConstants_ListConstantsByType_Internal - -
Удаление автоматического значения константы techConstants_DeleteAutoConstant Constant DeleteConstant
Удаление ручного значения константы techConstants_DeleteManualConstant Constant DeleteConstant

UpsertService (TechConstants)

На входе свойства регистрируемого или обновляемого сервиса

{
  "code": "techConstants",
  "name": "Технический справочник",
  "description": "Сервис технического справочника"
}

На выходе Boolean (признак успешности исполнения)

true

Регистрирует или обновляет сервис, для которого будут указываться константы.

Имя вызова команды: techConstants_UpsertService.
Поддерживается асинхронный и синхронный вызов.
Результат выполнения команды не журналируется.

Команда только внутренняя (нельзя вызвать через Api Gateway), не требует аутентификации.

ListServices (TechConstants)

На выходе перечень зарегистрированных сервисов

[
  {
    "code": "techReferences",
    "name": "Технический справочник",
    "description": "Сервис технического справочника"
  }
]

Возвращает перечень зарегистрированных сервисов.

Имя вызова команды: techConstants_ListServices.
Поддерживается только синхронный вызов.
Результат выполнения команды не журналируется.

Нет сортировки по умолчанию.

DeleteService (TechConstants)

На входе код удаляемого сервиса

"techConstants"

На выходе Boolean (признак успешности исполнения)

true

Удаляет зарегистрированный сервис.

Имя вызова команды: techConstants_DeleteService.
Поддерживается асинхронный и синхронный вызов.
Результат выполнения команды не журналируется.

Команда только внутренняя (нельзя вызвать через Api Gateway), не требует аутентификации.

UpsertConstantType (TechConstants)

На входе свойства регистрируемого или обновляемого типа констант

{
  "code": "journal",
  "name": "Журнал",
  "description": "Описание типов событий журнала"
}

На выходе Boolean (признак успешности исполнения)

true

Регистрирует или обновляет тип констант.

Имя вызова команды: techConstants_UpsertConstantType.
Поддерживается асинхронный и синхронный вызов.
Результат выполнения команды не журналируется.

ListConstantTypes (TechConstants)

На выходе перечень зарегистрированных типов констант

[
  {
    "code": "journal",
    "name": "Журнал",
    "description": "Описание типов событий журнала"
  }
]

Возвращает перечень зарегистрированных типов констант.

Имя вызова команды: techConstants_ListConstantTypes.
Поддерживается только синхронный вызов.
Результат выполнения команды не журналируется.

Нет сортировки по умолчанию.

DeleteConstantType (TechConstants)

На входе код удаляемого типа констант

"journal"

На выходе Boolean (признак успешности исполнения)

true

Удаляет зарегистрированный тип констант.

Имя вызова команды: techConstants_DeleteConstantType.
Поддерживается асинхронный и синхронный вызов.
Результат выполнения команды не журналируется.

UpsertAutoConstant (TechConstants)

На входе свойства регистрируемой константы

{
  "code": "testConstant",
  "constantType": "testConstantType",
  "service": "testServiceType",
  "name": "Тестовая константа",
  "description": "Описание тестовой константы",
  "settings": {
    "test": "auto"
  },
  "serviceVersion": 1
}

На выходе Boolean (признак успешности исполнения)

true

Регистрирует или обновляет автоматическую константу (source - Auto). Должно вызываться сервисом. Константа будет обновлена, если значение serviceVersion, указанное в запросе, не ниже значения того же поля у сохраненной в справочнике константы. При этом в ином случае все равно будет возвращено true, как признак того, что запрос отработал корректно.

Имя вызова команды: techConstants_UpsertAutoConstant.
Поддерживается асинхронный и синхронный вызов.
Результат выполнения команды не журналируется.

UpsertAutoConstant_Internal (TechConstants)

На входе свойства регистрируемой константы

{
  "code": "testConstant",
  "constantType": "testConstantType",
  "service": "testServiceType",
  "name": "Тестовая константа",
  "description": "Описание тестовой константы",
  "settings": {
    "test": "auto"
  },
  "serviceVersion": 1
}

На выходе Boolean (признак успешности исполнения)

true

Регистрирует или обновляет автоматическую константу (source - Auto). Должно вызываться сервисом.
Константа будет обновлена, если значение serviceVersion, указанное в запросе, не ниже значения того же поля у сохраненной в справочнике константы. При этом в ином случае все равно будет возвращено true, как признак того, что запрос отработал корректно.

Имя вызова команды: techConstants_UpsertAutoConstant_Internal.
Поддерживается асинхронный и синхронный вызов.
Результат выполнения команды не журналируется.

Команда только внутренняя (нельзя вызвать через Api Gateway), не требует аутентификации.

UpsertManualConstant (TechConstants)

На входе свойства регистрируемой константы

{
  "code": "testConstant",
  "constantType": "testConstantType",
  "service": "testServiceType",
  "name": "Тестовая константа - переопределение вручную",
  "description": "Описание тестовой константы - переопределение вручную",
  "settings": {
    "test": "manual"
  }
}

На выходе Boolean (признак успешности исполнения)

true

Регистрирует или обновляет ручную константу (source - Manual). Должно вызываться человеком.

Имя вызова команды: techConstants_UpsertManualConstant.
Поддерживается асинхронный и синхронный вызов.
Результат выполнения команды не журналируется.

GetConstant (TechConstants)

На входе код и тип константы

{
  "code": "testConstant",
  "constantType": "testConstantType"
}

На выходе данные константы

{
  "code": "testConstant",
  "constantType": "testConstantType",
  "service": "testService",
  "name": "Тестовая константа - переопределение вручную",
  "description": "Описание тестовой константы - переопределение вручную",
  "settings": {
    "test": "manual"
  },
  "source": "Auto",
  "modified": 1732515433705
}

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

Имя вызова команды: techConstants_GetConstant.
Поддерживается только синхронный вызов.
Результат выполнения команды не журналируется.

GetConstant_Internal (TechConstants)

На входе код и тип константы

{
  "code": "testConstant",
  "constantType": "testConstantType"
}

На выходе данные константы

{
  "code": "testConstant",
  "constantType": "testConstantType",
  "service": "testService",
  "name": "Тестовая константа - переопределение вручную",
  "description": "Описание тестовой константы - переопределение вручную",
  "settings": {
    "test": "manual"
  },
  "source": "Auto",
  "modified": 1732515433705
}

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

Имя вызова команды: techConstants_GetConstant_Internal.
Поддерживается только синхронный вызов.
Результат выполнения команды не журналируется.

Команда только внутренняя (нельзя вызвать через Api Gateway), не требует аутентификации.

ListAllConstants (TechConstants)

На входе поисковой запрос

{
  "query": "source",
  "context": {
    "source": "auto"
  },
  "sorting": {
    "fieldName": "constanttype.name",
    "order": "Asc"
  },
  "paging": {
    "page": 1,
    "count": 5
  }
}

На выходе страница со списком констант

{
  "items": [
    {
      "code": "ViewDataModel",
      "constantType": "uiActionType",
      "service": "dataModel",
      "name": "Просмотр модели данных в виде схемы",
      "description": null,
      "settings": null,
      "source": "Auto",
      "modified": 1732515433705
    },
    {
      "code": "ViewDataModelSection",
      "constantType": "uiActionType",
      "service": "dataModel",
      "name": "Просмотр раздела \"Модель данных\"",
      "description": null,
      "settings": null,
      "source": "Auto",
      "modified": 1732515433705
    },
    {
      "code": "UpdateObject",
      "constantType": "uiActionType",
      "service": "dataModel",
      "name": "Редактирование объекта",
      "description": null,
      "settings": null,
      "source": "Auto",
      "modified": 1732515433705
    },
    {
      "code": "DocumentSearch",
      "constantType": "uiActionType",
      "service": "dataModel",
      "name": "Работа с разделом \"Поиск с использованием документа\"",
      "description": null,
      "settings": null,
      "source": "Auto",
      "modified": 1732515433705
    },
    {
      "code": "ViewObjectCard",
      "constantType": "uiActionType",
      "service": "dataModel",
      "name": "Просмотр карточки объекта",
      "description": null,
      "settings": null,
      "source": "Manual",
      "modified": 1732515433705
    }
  ],
  "total": 27
}

Получает список констант по поисковому запросу. Если зарегистрирована и автоматическая, и ручная константа (с одинаковым кодом и типом) - в списке будут получены данные только ручной константы.

Имя вызова команды: techConstants_ListAllConstants.
Поддерживается только синхронный вызов.
Результат выполнения команды не журналируется.

По умолчанию сортировка производится по полю code.

Запрос принимает параметры сортировки, фильтров и пейджинга в параметре Search.

Применяется к полям модели ConstantStoreDTO

Доступные поля для фильтрации и виды фильтров по ним:

Поле Виды фильтров
id InSetQuery
code InSetQuery, LikeQuery
name InSetQuery, LikeQuery
constantType InSetQuery
source InSetQuery
service InSetQuery

Доступные поля для сортировки:

Поле Примечание
code -
name -
constantType.name По человекочитаемому названию типа константы
source В алфавитном порядке. Строковое представление соответствующее — "Auto", "Manual"

ListAllConstants_Internal (TechConstants)

На входе поисковой запрос

{
  "query": "source",
  "context": {
    "source": "auto"
  },
  "sorting": {
    "fieldName": "constanttype.name",
    "order": "Asc"
  },
  "paging": {
    "page": 1,
    "count": 5
  }
}

На выходе страница со списком констант

{
  "items": [
    {
      "code": "ViewDataModel",
      "constantType": "uiActionType",
      "service": "dataModel",
      "name": "Просмотр модели данных в виде схемы",
      "description": null,
      "settings": null,
      "source": "Auto",
      "modified": 1732515433705
    },
    {
      "code": "ViewDataModelSection",
      "constantType": "uiActionType",
      "service": "dataModel",
      "name": "Просмотр раздела \"Модель данных\"",
      "description": null,
      "settings": null,
      "source": "Auto",
      "modified": 1732515433705
    },
    {
      "code": "UpdateObject",
      "constantType": "uiActionType",
      "service": "dataModel",
      "name": "Редактирование объекта",
      "description": null,
      "settings": null,
      "source": "Auto",
      "modified": 1732515433705
    },
    {
      "code": "DocumentSearch",
      "constantType": "uiActionType",
      "service": "dataModel",
      "name": "Работа с разделом \"Поиск с использованием документа\"",
      "description": null,
      "settings": null,
      "source": "Auto",
      "modified": 1732515433705
    },
    {
      "code": "ViewObjectCard",
      "constantType": "uiActionType",
      "service": "dataModel",
      "name": "Просмотр карточки объекта",
      "description": null,
      "settings": null,
      "source": "Manual",
      "modified": 1732515433705
    }
  ],
  "total": 27
}

Получает список констант по поисковому запросу. Если зарегистрирована и автоматическая, и ручная константа (с одинаковым кодом и типом) - в списке будут получены данные только ручной константы.

Имя вызова команды: techConstants_ListAllConstants_Internal.
Поддерживается только синхронный вызов.
Результат выполнения команды не журналируется.

Команда только внутренняя (нельзя вызвать через Api Gateway), не требует аутентификации.

По умолчанию сортировка производится по полю code.

Запрос принимает параметры сортировки, фильтров и пейджинга в параметре Search.

Применяется к полям модели ConstantStoreDTO

Доступные поля для фильтрации и виды фильтров по ним:

Поле Виды фильтров
id InSetQuery
code InSetQuery, LikeQuery
name InSetQuery, LikeQuery
constantType InSetQuery
source InSetQuery
service InSetQuery

Доступные поля для сортировки:

Поле Примечание
code -
name -
constantType.name По человекочитаемому названию типа константы
source В алфавитном порядке. Строковое представление соответствующее — "Auto", "Manual"

ListConstantsByType (TechConstants)

На входе коды и тип константы

{
  "codes": [
    "testConstant"
  ],
  "constantType": "testConstantType"
}

На выходе данные по списку констант

[
  {
    "code": "testConstant",
    "constantType": "testConstantType",
    "service": "testService",
    "name": "Тестовая константа - переопределение вручную",
    "description": "Описание тестовой константы - переопределение вручную",
    "settings": {
      "test": "manual"
    },
    "source": "Auto",
    "modified": 1732515433705
  }
]

Получает список констант по типу констант, и, опционально, перечню кодов констант. Если зарегистрирована и автоматическая, и ручная константа (с одинаковым кодом и типом) - в списке будут получены данные только ручной константы.

Имя вызова команды: techConstants_ListConstantsByType.
Поддерживается только синхронный вызов.
Результат выполнения команды не журналируется.

ListConstantsByType_Internal (TechConstants)

На входе коды и тип константы

{
  "codes": [
    "testConstant"
  ],
  "constantType": "testConstantType"
}

На выходе данные по списку констант

[
  {
    "code": "testConstant",
    "constantType": "testConstantType",
    "service": "testService",
    "name": "Тестовая константа - переопределение вручную",
    "description": "Описание тестовой константы - переопределение вручную",
    "settings": {
      "test": "manual"
    },
    "source": "Auto",
    "modified": 1732515433705
  }
]

Получает список констант по типу констант, и, опционально, перечню кодов констант. Если зарегистрирована и автоматическая, и ручная константа (с одинаковым кодом и типом) - в списке будут получены данные только ручной константы.

Имя вызова команды: techConstants_ListConstantsByType_Internal.
Поддерживается только синхронный вызов.
Результат выполнения команды не журналируется.

Команда только внутренняя (нельзя вызвать через Api Gateway), не требует аутентификации.

DeleteAutoConstant (TechConstants)

На входе код и тип константы

{
  "code": "testConstant",
  "constantType": "testConstantType"
}

На выходе Boolean (признак успешности исполнения)

true

Удаляет автоматическую константу. Если зарегистрирована и автоматическая, и ручная константа (с одинаковым кодом и типом) - ручная не удаляется.

Имя вызова команды: techConstants_DeleteAutoConstant.
Поддерживается асинхронный и синхронный вызов.
Результат выполнения команды не журналируется.

DeleteManualConstant (TechConstants)

На входе код и тип константы

{
  "code": "testConstant",
  "constantType": "testConstantType"
}

На выходе Boolean (признак успешности исполнения)

true

Удаляет ручную константу. Если зарегистрирована и автоматическая, и ручная константа (с одинаковым кодом и типом) - автоматическая не удаляется.

Имя вызова команды: techConstants_DeleteManualConstant.
Поддерживается асинхронный и синхронный вызов.
Результат выполнения команды не журналируется.

Модели сервиса TechConstants

Service (ServiceUpsertDTO)

Модель зарегистрированного (регистрируемого) сервиса.

Поле Тип Обязательное Значение по умолчанию Описание Ограничения
code string Да Код сервиса Длина не более 32.
Уникальное значение.
name string Да Наименование сервиса Длина не более 128.
description string Нет Описание сервиса

ConstantType (ConstantTypeUpsertDTO)

Модель зарегистрированного (регистрируемого) типа констант.

Поле Тип Обязательное Значение по умолчанию Описание Ограничения
code string Да Код типа констант Длина не более 32.
Уникальное значение.
name string Да Наименование типа констант Длина не более 128.
description string Нет Описание типа констант

Constant

Данные зарегистрированной константы.

Поле Тип Обязательное Значение по умолчанию Описание Ограничения
code string Да Код константы Длина не более 64.
Уникальное значение.
constantType string Да Код типа константы Длина не более 32.
Существующий код типа констант.
service string Да Код сервиса константы Длина не более 32.
Существующий код сервиса.
name string Да Наименование константы Длина не более 128.
description string Нет Описание константы
settings json Нет Дополнительные произвольные настройки константы
source string Да Источник константы: Auto или Manual (автоматическая или ручная константа) Длина не более 32.
modified TimeStamp Да Дата последнего обновления константы в миллисекундах (UTC from 1970)

ConstantStoreDTO

Хранимая модель зарегистрированных констант.

Поле Тип Обязательное Значение по умолчанию Описание Ограничения
id uuid Нет UUID.randomUUID Идентификатор константы
code string Да Код константы Длина не более 64.
Уникальное значение.
constantType string Да Код типа константы Длина не более 32.
Существующий код типа констант.
service string Да Код сервиса константы Длина не более 32.
Существующий код сервиса.
name string Да Наименование константы Длина не более 128.
description string Нет Описание константы
settings json Нет Дополнительные произвольные настройки константы
source string Да Источник константы: Auto или Manual (автоматическая или ручная константа) Длина не более 32.
modified TimeStamp Да TimeStamp.now Дата последнего изменения константы
serviceVersion string Нет Версия константы внутри сервиса

ConstantIdentityDTO

Данные для работы с одной константой (получение или удаление константы).

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

Поле Тип Обязательное Значение по умолчанию Описание Ограничения
code string Да Код константы Длина не более 64.
constantType string Да Код типа константы Длина не более 32.
Существующий тип константы.

ConstantUpsertAutoDTO

Данные для регистрации или обновления автоматической константы.

Поле Тип Обязательное Значение по умолчанию Описание Ограничения
code string Да Код константы. Константы разного типа могут иметь одинаковый код. Длина не более 64.
constantType string Да Код типа константы Длина не более 32.
Существующий код типа константы.
service string Да Код сервиса константы Длина не более 32.
Существующий код сервиса.
name string Да Наименование типа констант Длина не более 128.
description string Нет Описание типа констант
settings json Нет Дополнительные произвольные настройки константы
serviceVersion integer Да Версия константы внутри сервиса

ConstantUpsertManualDTO

Данные для регистрации или обновления ручной константы.

Поле Тип Обязательное Значение по умолчанию Описание Ограничения
code string Да Код константы. Константы разного типа могут иметь одинаковый код. Длина не более 64.
constantType string Да Код типа константы Длина не более 32.
Существующий код типа константы.
service string Да Код сервиса константы Длина не более 32.
Существующий код сервиса.
name string Да Наименование типа констант Длина не более 128.
description string Нет Описание типа констант
settings json Нет Дополнительные произвольные настройки константы

ConstantListByTypeDTO

Данные для получения списка констант определенного типа.

Поле Тип Обязательное Значение по умолчанию Описание Ограничения
constantType string Да Код типа константы Длина не более 32.
Существующий код типа констант.
codes array[string] Нет Перечень кодов констант, которые надо получить. Если не указано - получит все константы указанного типа.

Tech-constants-client: клиент для сервиса Tech-constants

Библиотека предоставляет интерфейс и реализацию клиента для сервиса Tech-constants.

Пример создания Tech-constants-client

Для того чтобы использовать библиотеку techconstantsclient, нужно добавить зависимость "com.embedika.verdi" %% "techconstantsclient" % verdiVersion.

Все классы находятся в пакете com.embedika.verdi.techConstants.client.

Основной интерфейс для взаимодействия TechConstantsClient[F[_]].

Реализация интерфейса LiveTechConstantsClientTF[F[_]: Monad: FromFuture], deprecated имплементация LiveTechConstantsClient

Пример для DI (izumi)

import com.embedika.verdi.techConstants.client.{LiveTechConstantsClientTF, TechConstantsClient}

make[TechConstantsClient[Future]].from {
    (dispatcher: Dispatcher, ec: ExecutionContext @Id("ec-system"), fromFuture: FromFuture[Future]) =>
        implicit val ffImpl: FromFuture[Future] = fromFuture
        implicit val ecImpl: ExecutionContext   = ec
        new LiveTechConstantsClientTF[Future](dispatcher)
}

Предоставляемый функционал Tech-constants-client

Tech-constants-client предоставляет методы вызова соответствующих команд сервиса Tech-constants. Формат входных и выходных данных методов Tech-constants-client аналогичен формату входных и выходных данных команд сервиса Tech-constants.

Регистрация данных

Получение констант

Удаление данных

Детали регистрации данных в сервисе технического справочника

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

Константа, по сути, является маппингом из "код константы + код типа константы" в "наименование + описание + дополнительные произвольные настройки". Константы разного типа могут иметь одинаковый собственный код.

Типы констант, на текущем этапе, являются предзаданными в сервисе техсправочника значениями и перечислены в объекте com.embedika.verdi.models.techConstant; однако сервис допускает регистрацию иных типов вызовом соответствующего апи.

Ниже будет описан процесс использования клиента для регистрации констант. Более подробную информацию, описание моделей данных и пр. можно найти в документации сервиса технического справочника.

Процесс регистрации констант

Предварительно, перед регистрацией, в проекте необходимо описать перечень его констант.

Пример инициализации перечня констант

import com.embedika.verdi.models.techConstant.TechConstant
import com.embedika.verdi.models.techConstant.CommonConstantTypes._

object TechConstants {
    object Journal {
        val createForm: TechConstant = TechConstant(
            code = ConstantCode("createForm"),
            constantType = JournalEventType,
            name = "Создана новая форма",
            description = None,
            settings = None,
            serviceVersion = 1
        )
        val updateForm: TechConstant = TechConstant(
            code = ConstantCode("updateForm"),
            constantType = NotificationType,
            name = "Создана новая форма",
            description = None,
            settings = None,
            serviceVersion = 1
        )
        val all: Seq[TechConstant] = Seq(createForm, updateForm)
    }

    object Notifications {
        //...
        val all: Seq[TechConstant] = Seq(???)
    }

    val all = Journal.all + Notifications.all
}

Основной процесс регистрации

Пример процесса регистрации

// Нужен для вызова techConstantsClient::registerService
private implicit def rc: RequestContext = RequestContext.builder().build()
val serviceName = ServiceName(config.getString("name"))

techConstantsClient
  .registerService(
    serviceName = serviceName,
    readableName = "Хранение UI",
    description = Some("...описание сервиса")
  )
  .flatMap {
    case Left(err) =>
    // Обработать ошибку (логи, остальные обработки если нужны)
    case Right(_) =>
      // Зарегистрировать все константы, например через Future.traverse или иным способом:
      Future.traverse(TechConstants.all)(techConstantsClient.registerConstantInternal(serviceName, _)).flatMap { results =>
        // Обработать ошибки если нужны
      }
  }

Имея клиент, можно начать сам процесс регистрации. Ожидается, что она будет происходить при рестарте сервиса, где-то на одном этапе с регистрацией команд.

Первым этапом должна вызываться регистрация текущего сервиса. В случае успешной регистрации сервиса, можно зарегистрировать его константы.

UI-storage: сервис хранения UI

Сервис принимает команды и хранит состояние в PostgreSQL. Команды могут приходить как по HTTP, так и через Kafka в топик ui_storage_commands.

Сервис разбит на несколько модулей, в виде sbt проектов:

В сервисе реализованы следующие команды:

Локальный запуск сервиса хранения UI

При запуске сервиса ожидается, что уже развернута необходимая инфраструктура:

Запуск сервиса хранения UI из консоли с помощью SBT

UI_STORAGE_DB_HOST=localhost UI_STORAGE_DB_PORT=5432 UI_STORAGE_DB_NAME=UIStorage_db UI_STORAGE_DB_USER=$UI_STORAGE_DB_USER UI_STORAGE_DB_PASSWORD=$UI_STORAGE_DB_PASSWORD sbt boot/run

Список переменных окружения сервиса хранения UI

Переменная Тип Обязательная Значение по умолчанию Описание
UI_STORAGE_HTTP_HOST string нет "0.0.0.0" Хост для HttpListener
UI_STORAGE_HTTP_PORT int нет 8192 Порт для HttpListener
UI_STORAGE_KAFKA_SERVERS string нет "localhost:9092" Адрес Kafka
UI_STORAGE_KAFKA_TOPIC string нет "ui_storage_commands" Название топика для команд
UI_STORAGE_KAFKA_CONSUMER_GROUP string нет "ui_storage_consumer_group" Название consumer-группы для чтения команд
UI_STORAGE_KAFKA_COMMANDEVENT_TOPIC string нет "commandevents" Название топика для отправки сообщений со статусом команд
UI_STORAGE_KAFKA_PARTITIONS int нет 10 Количество партиций в топике команд.
UI_STORAGE_KAFKA_CONSUMER_RESTART_MIN_BACKOFF duration string нет 1 second Минимальная задержка перед перезапуском.
UI_STORAGE_KAFKA_CONSUMER_RESTART_MAX_BACKOFF duration string нет 30 seconds Максимально возможная задержка перед перезапуском.
UI_STORAGE_KAFKA_CONSUMER_RESTART_RANDOM_FACTOR float нет 0.2 Коэффициент величины дополнительной случайной задержки(jitter) относительно основной задержки: 0.0 - без случайной задержки, 1.0 - до 100% задержки. Если после умножения задержки на UI_STORAGE_KAFKA_CONSUMER_RESTART_RANDOM_FACTOR получится меньше 1 миллисекунды, то jitter будет приравнен к нулю.
UI_STORAGE_KAFKA_CONSUMER_RESTART_MAX_RESTARTS int нет 5 Максимальное количество перезапусков в заданный период времени. После превышения этого числа сервис будет объявлен больным. Все рестарты для каждого отдельного сообщения увеличивают и общий счетчик рестартов консьюмера, поэтому при использовании UI_STORAGE_KAFKA_CONSUMER_PER_MESSAGE_RESTART_MAX_RESTARTS нужно указывать UI_STORAGE_KAFKA_CONSUMER_RESTART_MAX_RESTARTS > UI_STORAGE_KAFKA_CONSUMER_PER_MESSAGE_RESTART_MAX_RESTARTS или не указывать UI_STORAGE_KAFKA_CONSUMER_PER_MESSAGE_RESTART_MAX_RESTARTS совсем.
UI_STORAGE_KAFKA_CONSUMER_PER_MESSAGE_RESTART_MAX_RESTARTS int нет 2 Максимальное количество раз, которое консьюмер перезапустится с неизменной очередью сообщений(в пределах DATA_MODEL_KAFKA_CONSUMER_RESTART_MAX_RESTARTS_WITHIN), прежде чем проигнорировать сообщение, на котором происходит ошибка (Указано количество рестартов, а не прочтений. Если UI_STORAGE_KAFKA_CONSUMER_RESTART_MAX_RESTARTS = 2, то ошибочное сообщение будет обработано 3 раза, после чего произойдет 3ий рестарт и оно будет проигнорировано). Если указать 0, то перезапуск произойдет, но сообщение будет обработано только в первый раз, когда произошла ошибка. Если указать значение меньше 0, то перезапуски все равно будут происходить, но игнорирование сообщений, вызывающих ошибку, будет отключено.
UI_STORAGE_KAFKA_CONSUMER_PER_MESSAGE_RESTART_CACHE_SIZE int нет 100 Для каждого сообщения счетчик перепрочтений хранится в кэше. Максимальное количество значений в этом кэше.
UI_STORAGE_KAFKA_CONSUMER_PER_MESSAGE_RESTART_CACHE_TTL duration string нет 5 minutes Для каждого сообщения счетчик перепрочтений хранится в кэше.Максимальное время жизни элемента в этом кэше. В случае отсутствия значения время жизни элемента не будет ограничено.
UI_STORAGE_KAFKA_CONSUMER_RESTART_MAX_RESTARTS_WITHIN duration string нет 5 minutes Период времени для ограничения перезапусков.
UI_STORAGE_KAFKA_CONSUMER_POLL_TIMEOUT duration string нет 10 milliseconds timeout запроса poll для kafka consumer
UI_STORAGE_KAFKA_CONSUMER_POLL_INTERVAL duration string нет 100 milliseconds интервал между запросами poll для kafka consumer
UI_STORAGE_KAFKA_CONSUMER_PROPS string нет "max.poll.records=500;max.partition.fetch.bytes=524288" дополнительные параметры для kafka consumer в формате "key1=value1;key2=value2"
UI_STORAGE_KAFKA_AUTH_USER string нет "" Название учетной записи Kafka. Если название не указано, то настройки авторизации не будут применены.
UI_STORAGE_KAFKA_AUTH_PASSWORD string нет "" Пароль учетной записи Kafka.
UI_STORAGE_KAFKA_AUTH_PRINCIPAL string нет "" Principal учетной записи Kafka в Kerberos(в случае соединения с kafka через Kerberos).
UI_STORAGE_KAFKA_AUTH_KEYTAB_PATH string нет "" Путь до keytab-файла(в случае соединения с kafka через Kerberos).
UI_STORAGE_KAFKA_AUTH_TRUSTSTORE_LOCATION string нет "" Путь до хранилища сертификатов (Java key store). Если путь не указан, то сертификат применяться не будет.
UI_STORAGE_KAFKA_AUTH_TRUSTSTORE_PASSWORD string нет "" Пароль к хранилищу сертификатов.
UI_STORAGE_KAFKA_AUTH_MODE string нет "static" Режим аутентификации: static - одна учетная запись на все запросы, mapping - учетная запись зависит от запроса
UI_STORAGE_KAFKA_AUTH_CONFIG string нет "" Настройки для аутентификации: если AuthMode = mapping, то необходим JSON с List[KafkaAuthConfig]. Переменная соответствует полю authConfig из KafkaAuthSettings.
UI_STORAGE_KAFKA_AUTH_CACHE_SIZE int нет Максимальный размер кеша для Kafka producer (количество активных соединений).
UI_STORAGE_KAFKA_AUTH_CACHE_TTL duration string нет Время жизни Kafka producer в кеше.
UI_STORAGE_KAFKA_CONNECTION_CHECK_TEST_MESSAGES_INTERVAL duration string нет 4 minutes Применяется только для producer-ов со способом аутентификации kerberos. Интервал отправки тестовых сообщений кафки в топик connectionCheck.testMessagesTopicName. Тестовые сообщения (null, service producer test) отправляются регулярно с этим интервалом.
UI_STORAGE_KAFKA_CONNECTION_CHECK_INTERVAL duration string нет 60 seconds Применяется только для producer-ов со способом аутентификации kerberos. Интервал проверки того, сколько тестовых сообщений было отправлено за данный период. Если количество сообщений за этот период равно количеству сообщений за прошлый период, то начинается отсчет периода без сообщений.
UI_STORAGE_KAFKA_CONNECTION_CHECK_FAILED_AFTER_INTERVAL duration string нет 5 minutes Применяется только для producer-ов со способом аутентификации kerberos. Максимальная продолжительность периода без успешно отправленных тестовых сообщений. По ее достижении сервис будет объявлен больным.
UI_STORAGE_CONSUL_ADDR string нет "http://localhost:8500" Адрес Сonsul
UI_STORAGE_TRACE_DURATION bool нет false Признак необходимости трассировки выполнения команд
UI_STORAGE_DISCOVERABLE_ID string нет "ui_storage_instance" Id сервиса в ServiceDiscovery
UI_STORAGE_DISCOVERABLE_NAME string нет "UIStorage" Имя сервиса в ServiceDiscovery
UI_STORAGE_DISCOVERABLE_HOST string нет "localhost" Хост, публикуемый в ServiceDiscovery
UI_STORAGE_DISCOVERABLE_PORT int нет Порт, публикуемый в ServiceDiscovery
UI_STORAGE_DISCOVERABLE_LIVETIME duration string нет 2 minutes Период после отправки health check, в течение которого ServiceDiscovery считает сервис живым
UI_STORAGE_DISCOVERABLE_HEALTHPASS duration string нет 1 minute Периодичность отправки health check в ServiceDiscovery
UI_STORAGE_AKKA_HTTP_CLIENT_MAXCON int нет 512 Максимальное число одновременных исходящих HTTP-соединений
UI_STORAGE_AKKA_HTTP_CLIENT_MAXREQ int нет 1024 Максимальное число одновременных исходящих HTTP-запросов
UI_STORAGE_AKKA_HTTP_SERVER_MAXCON int нет 1024 Максимальное число одновременных входящих HTTP-соединений
UI_STORAGE_INTERNALCMD_ALLOW bool нет false Можно ли сервису отправлять внутрисистемные команды
UI_STORAGE_SENDERLIB_CONSIDER_ALL_COMMANDS_AS_INTERNAL boolean Нет false Флаг, определяющий будут ли все обращения в другие сервисы являться внутренними (т.е. не требовать авторизацию). Детальное описание механизма: Внутренние команды.
UI_STORAGE_SENDERLIB_COMMANDS_CACHE_UPDATEPERIOD duration string нет 10 minutes Время кэширования данных по командам из CommandDiscovery
UI_STORAGE_SENDERLIB_SERVICES_CACHE_UPDATEPERIOD duration string нет 30 seconds Время кэширования данных по сервисам из ServiceDiscovery
UI_STORAGE_DB_URL string если не указаны DB_HOST, DB_PORT и DB_NAME Адрес базы данных. Можно использовать вместо DB_HOST, DB_PORT и DB_NAME
UI_STORAGE_DB_HOST string если не указана DB_URL Хост сервера базы данных
UI_STORAGE_DB_PORT int если не указана DB_URL Порт сервера базы данных
UI_STORAGE_DB_NAME string если не указана DB_URL Название базы данных
UI_STORAGE_DB_USER string да Пользователь базы данных
UI_STORAGE_DB_PASSWORD string да Пароль для пользователя базы данных
UI_STORAGE_DB_THREADS int нет 10 Количество потоков в пуле потоков для соединения с БД
UI_STORAGE_DB_QUEUE_SIZE int нет 300 Размер очереди для действий базы данных, которые не могут быть выполнены немедленно, когда все потоки заняты. За пределами этого значения новые действия немедленно завершаются неудачей
UI_STORAGE_DB_CONN_MAX int нет 10 Максимальное количество одновременных подключений к БД
UI_STORAGE_DB_CONN_TIMEOUT duration string нет 20 second Максимальное время ожидания ответа для соединения к БД. Если это время превышено, а соединение не становится доступным, будет брошено исключение SQLException. 1000 мс — минимальное значение.
UI_STORAGE_DB_ISOLATION string нет "READ_COMMITTED" Уровень изоляции транзакций для новых подключений. Допустимые значения: NONE, READ_COMMITTED, READ_UNCOMMITTED, REPEATABLE_READ, SERIALIZABLE.
UI_STORAGE_DB_READONLY boolean нет false Read-only SQL транзакция может изменять только временные таблицы. Этот параметр управляет статусом «только для чтения» по умолчанию для каждой новой транзакции.
UI_STORAGE_DB_CONN_MIN int нет = DB_THREADS Минимальное количество одновременных подключений к БД
UI_STORAGE_DB_VALIDATION_TIMEOUT duration string нет 1 seconds Максимальное время, в течение которого соединение будет проверяться на работоспособность. 1000 мс — минимальное значение.
UI_STORAGE_DB_IDLE_TIMEOUT duration string нет 10 minutes Максимальное время, в течение которого соединению разрешено простаивать в пуле. Значение 0 означает, что простаивающие соединения никогда не удаляются из пула.
UI_STORAGE_DB_MAX_LIFETIME duration string нет 30 minutes Максимальное время жизни соединения в пуле. Когда простаивающее соединение достигает этого времени ожидания, даже если оно недавно использовалось, оно будет удалено из пула. Значение 0 указывает на отсутствие максимального срока службы.
UI_STORAGE_DB_INITIALIZATION_FAIL_FAST string нет false Deprecated, начиная с версии Slick 3.3.0. Определяет, будет ли пул «быстро выходить из строя», если пул не может быть успешно заполнен начальными соединениями. Если соединения не могут быть созданы во время запуска пула, будет выдано исключение RuntimeException. Это свойство не имеет никакого эффекта, если minConnections равно 0.
UI_STORAGE_DB_LEAK_DETECTION_THRESHOLD int нет 0 Время, в течение которого соединение может находиться вне пула, прежде чем будет зарегистрировано сообщение, указывающее на возможную утечку соединения. Значение 0 означает, что обнаружение утечек отключено. Наименьшее приемлемое значение для включения обнаружения утечек составляет 10 с.
UI_STORAGE_DB_CONNECTION_TEST_QUERY string нет "SELECT 1" Выражение, которое будет выполнено непосредственно перед получением соединения из пула для проверки того, что соединение с базой данных все еще активно. Оно зависит от базы данных и должно представлять собой запрос, требующий минимальной обработки базой данных (например, «VALUES 1»). Если этот параметр не установлен, вместо него используется метод JDBC4 Connection.isValid().
UI_STORAGE_DB_AUTO_COMMIT boolean нет true Это свойство определяет то, как будут вести себя по умолчанию возвращаемые соединения относительно autocommit-а.
UI_STORAGE_DB_SCHEMA string нет "public" Устанавливает schema по умолчанию
UI_STORAGE_DB_ISOLATE_INTERNAL_QUERIES boolean нет false Определяет то, изолируются ли с помощью транзакций внутренние запросы пула(например запрос connection alive test). Свойство применяется только если autoCommit выключен.
UI_STORAGE_DB_INITIALIZATION_FAIL_TIMEOUT int нет 1 Работает, начиная с версии Slick 3.3.0. Определяет, будет ли пул «быстро выходить из строя», если пул не может быть успешно заполнен начальными соединениями. Любое положительное число считается числом миллисекунд для попытки получить начальное соединение;поток приложения будет заблокирован в течение этого периода. Если соединение не может быть получено до истечения этого времени,будет брошено исключение. Данный таймаут применяется после периода connectionTimeout. Если значение равно нулю (0),HikariCP попытается получить и проверить подключение. Если соединение получено,но проверка не пройдена, будет брошено исключение, и пул не будет запущен. Однако,если соединение не может быть получено, пул запустится,но последующие попытки получить соединение могут потерпеть неудачу.Значение меньше нуля пройдет любую первоначальную попытку подключения, и пул немедленно запустится,пытаясь получить соединения в фоновом режиме.Следовательно, последующие попытки получить соединение могут потерпеть неудачу.
UI_STORAGE_DB_REGISTER_MBEANS boolean нет false Зарегистрированы ли JMX Management Beans («MBeans»)
UI_STORAGE_FS_URI string нет "http://localhost:9000" Адрес файлового хранилища
UI_STORAGE_FS_ACCESS_KEY_ID string нет "minioadmin" Идентификатор пользователя файлового хранилища
UI_STORAGE_FS_SECRET_ACCESS_KEY string нет "minioadmin" Пароль для пользователя файлового хранилища
UI_STORAGE_FS_UPLOAD_PARALLELISM int нет 4 Параллелизм для загрузки файлов
UI_STORAGE_FS_AUTH_MODE string нет "static" Режим аутентификации: static - одна учетная запись на все запросы, mapping - учетная запись зависит от запроса
UI_STORAGE_FS_AUTH_CONFIG string нет "" Настройки для аутентификации: если AuthMode = mapping, то необходим JSON с List[FSBucketConfig] соответствует полю authConfig FSConfigRep
UI_STORAGE_FS_CACHE_SIZE int нет 1 Максимальный размер кеша клиентов для хранилища файлов (количество активных соединений).
UI_STORAGE_FS_CACHE_TTL duration string нет Время жизни клиента в кеше
UI_STORAGE_FS_RETRY_ATTEMPTS int нет 5 Количество ретраев, которое будет произведено в случае Exception-а в операции FSClient-а и при вычитывании стрима в get операциях FSClient-а.
UI_STORAGE_FS_RETRY_DELAY duration string нет 10 millis Задержка между ретраями операций FSClient-а.
UI_STORAGE_FS_BUCKET_TEMP string нет "temp" Название бакета для временных файлов
UI_STORAGE_FS_BUCKET_PERMANENT string нет "uisettings" Название бакета для постоянных файлов
UI_STORAGE_FS_ZIO_SHORT_MESSAGE_MODE boolean нет false Флаг включения режима сохранения ошибок работы с файловым хранилищем в сервисе журналирования nestor. При включении режима ошибки в логах будут отображаться в сокращенном формате: Short zio message mode. ExceptionType: ТИП ОШИБКИ, Exception id: 'СГЕНЕРИРОВАННЫЙ UUID' added to journal. Указанный id будет фиксироваться в event записи nestor'а в поле data.id
UI_STORAGE_AUTHZFORCE_ADDR string нет "http://localhost:8080/authzforce-ce" Адрес сервиса authzforce
UI_STORAGE_AUTHZFORCE_DOMAIN string нет "not defined" Доступный DomainID в Authzforce server
UI_STORAGE_AUTHORIZER_KIND string нет "authzforce" Вид авторизатора, который используется в сервисе. Допустимые значения: "authzforce", "oberto". При указании неизвестного значения будет использовано значение по-умолчанию.
UI_STORAGE_SENDERLIB_COMMANDS_HTTP_RETRY_ATTEMPTS int нет 5 Поле attempts из RetrySettings
UI_STORAGE_SENDERLIB_COMMANDS_HTTP_RETRY_DELAY duration string нет "5 seconds" Поле delay из RetrySettings
UI_STORAGE_SENDERLIB_COMMANDS_HTTP_RETRY_KIND string нет "OnSomeExceptions(ConnectException)" CommandResultRetryConditionKind
UI_STORAGE_SENDERLIB_CONSUL_CONNECTION_RETRY_MAX int нет 5 Количество попыток переподключения к Consul
UI_STORAGE_SENDERLIB_CONSUL_CONNECTION_RETRY_DELAY duration string нет "1 second" Задержка при попытках переподключения к Consul
UI_STORAGE_ADDITIONAL_FORM_TYPES string нет "" Строка со списком дополнительных FormType, которые будут добавлены в БД при старте приложения, в формате "code1,title1;code2,title2,description2". Каждый добавляемый FormType описывается подстрокой вида "<значение поля code>,<значение поля title>[,<значение поля description>]". Значение поля description при этом указывается опционально. Подстроки с описанием FormType отделяются друг от друга ";".
UI_STORAGE_ADDITIONAL_FORM_TYPES_MODE string нет "add" Режим добавления дополнительных FormType, которые будут добавлены в БД при старте приложения. Есть два валидных значения: "add" - если при добавлении у двух FormType совпадает поле code, но отличаются другие поля, то сервис падает на старте с ошибкой; "override" - если при добавлении у двух FormType совпадает поле code, но отличаются другие поля, то FormType-ы из переменной перезапишут FormType-ы из БД. Если конфликты будут внутри самой переменной, то сервис упадет на старте в любом из режимов.
UI_STORAGE_JOURNAL_MODE string нет WriteToJournal Режим журналирования Nestor. Допустимые значения: WriteToJournal (Отправка в сервис журналирования), WriteToTopic (Отправка события в очередь)
UI_STORAGE_JOURNAL_TOPIC string да, если переменная UI_STORAGE_JOURNAL_MODE = WriteToTopic "" Название очереди журналирования. Для режима WriteToJournal значение игнорируется.

Команды сервиса хранения UI

Список реализованных в сервисе команд, моделей EntityType и действий Actions, которые можно использовать при настройке авторизации.
Не все поля EntityType доступны для использования в настройке авторизации.

Название команды EntityType Actions
ListFormTypes FormType UIStorage_ViewList
CreateForm - -
GetForm EntityFormSettings UIStorage_View
DeleteForm - -
UpdateForm - -
ListForms EntityFormSettingsDTO UIStorage_ViewList
ListFormsV2 EntityFormSettingsFullDTO UIStorage_ViewList
GetEntityForm EntityFormSettings UIStorage_View
GetFormsByType EntityFormSettings UIStorage_ViewList
ListKeys GlobalSetting UIStorage_ViewList
GetValue GlobalSetting UIStorage_View
CreateKey GlobalSetting UIStorage_CRUD
UpdateKey GlobalSetting UIStorage_CRUD
UpdateValue GlobalSetting UIStorage_UpdateValue
DeleteKey GlobalSetting UIStorage_CRUD
PersistFile GlobalSetting UIStorage_UpdateValue

Доступные для авторизации поля моделей сервиса хранения UI

EntityFormSettings (AuthzDTO, UI Storage)

Поле Тип Actions Описание
id EntityFormSettingsId UIStorage_View, UIStorage_ViewList ID формы
entityType String UIStorage_View, UIStorage_ViewList Тип сущности (127 символов)
formData Json UIStorage_ViewList Данные формы
formType FormTypeCode UIStorage_View Code типа формы

EntityFormSettingsDTO (AuthzDTO, UI Storage)

Поле Тип Actions Описание
id EntityFormSettingsId UIStorage_View, UIStorage_ViewList ID формы
entityType String UIStorage_View, UIStorage_ViewList Тип сущности
formType FormType UIStorage_View, UIStorage_ViewList Тип формы

FormType (AuthzDTO, UI Storage)

Поле Тип Actions Описание
code FormTypeCode UIStorage_View, UIStorage_ViewList Код типа формы
title String UIStorage_View, UIStorage_ViewList Заголовок типа формы

GlobalSettings (AuthzDTO, UI Storage)

Поле Тип Actions Описание
key GlobalSettingKey UIStorage_View, UIStorage_ViewList, UIStorage_CRUD, UIStorage_UpdateValue Ключ для идентификации настроек
title String UIStorage_ViewList Название настроек
value Json UIStorage_ViewList Данные описывающие настройки

ListFormTypes (UI Storage)

Получаем JSON со списком всех существующих типов форм

[
  {
    "code": "card",
    "title": "Карточка объекта",
    "description": "Карточка объекта"
  },
  {
    "code": "createForm",
    "title": "Форма создания",
    "description": "Форма создания"
  }
]

Возвращает список всех существующих типов форм.

Имя команды для вызова: UIStorage_http_ListFormTypes.
Поддерживается только синхронный вызов.
Результат выполнения команды не журналируется.

CreateForm (UI Storage)

Передаем JSON с данными формы

{
  "entityType": "document",
  "formType": "card",
  "formData": {
    "field1": "value1"
  }
}

Получаем Id формы

"0ccd05ac-50c0-4e7e-906b-6893eaa8d9de"

Создать новую форму из данных EntityFormSettingsCreateDTO. Гарантируется уникальность для набора полей: entityType, formType.

Имя команды для вызова: UIStorage_kafka_CreateForm.
Поддерживается асинхронный и синхронный вызов.
Результат выполнения команды журналируется.

GetForm (UI Storage)

Передаем Id формы

"63680617-1cda-40db-bd99-303fbfcbb736"

Получаем JSON с данными формы

{
  "id": "63680617-1cda-40db-bd99-303fbfcbb736",
  "entityType": "organization",
  "formType": "card",
  "formData": {
    "field1": "value1"
  },
  "version": 1
}

Возвращает форму EntityFormSettings по её Id.

Имя команды для вызова: UIStorage_http_GetForm.
Поддерживается только синхронный вызов.
Результат выполнения команды не журналируется.

DeleteForm (UI Storage)

Передаем Id формы

"0ccd05ac-50c0-4e7e-906b-6893eaa8d9de"

Получаем результат

1

Удалить существующую форму по её Id.

Имя команды для вызова: UIStorage_kafka_DeleteForm.
Поддерживается асинхронный и синхронный вызов.
Результат выполнения команды журналируется.

UpdateForm (UI Storage)

Передаем JSON данные для обновления

{
  "id": "0ccd05ac-50c0-4e7e-906b-6893eaa8d9de",
  "formData": {
    "field1": "newValue"
  },
  "version": "1"
}

Получаем результат

1

Обновить существующую форму данными из EntityFormSettingsForUpdate. При успешном обновлении version формы увеличивается на единицу.

Имя команды для вызова: UIStorage_kafka_UpdateForm.
Поддерживается асинхронный и синхронный вызов.
Результат выполнения команды журналируется.

ListForms (UI Storage)

Получаем JSON со списком всех форм с типом

[
  {
    "id": "b13971a2-5d00-4455-bd48-4e4256157353",
    "entityType": "document",
    "formType": {
      "code": "card",
      "title": "Карточка объекта",
      "description": "Карточка объекта"
    },
    "version": 1
  },
  {
    "id": "fd460be0-99f6-4cfc-95eb-2e3f6a847efe",
    "entityType": "employee",
    "formType": {
      "code": "list",
      "title": "Список",
      "description": "Список"
    },
    "version": 1
  }
]

Возвращает список всех форм с типом, отсортированный по entityType.

Имя команды для вызова: UIStorage_http_ListForms.
Поддерживается только синхронный вызов.
Результат выполнения команды не журналируется.

ListFormsV2 (UI Storage)

Передаем параметры поиска

{
  "query": "",
  "context": {}
}

Получаем JSON со списком форм с типом и с данными

{
  "items": [
    {
      "id": "b13971a2-5d00-4455-bd48-4e4256157353",
      "entityType": "document",
      "formType": {
        "code": "card",
        "title": "Карточка объекта",
        "description": "Карточка объекта"
      },
      "formData": {
        "key": "value"
      },
      "version": 1
    },
    {
      "id": "fd460be0-99f6-4cfc-95eb-2e3f6a847efe",
      "entityType": "employee",
      "formType": {
        "code": "list",
        "title": "Список",
        "description": "Список"
      },
      "formData": {
        "key": "value"
      },
      "version": 1
    }
  ],
  "total": 10
}

Возвращает пагинированный список всех форм с типом и с данными. Пагинация по-умолчанию не производится.

Сортировка и фильтрация применяется к полям модели EntityFormSettingsFullDTO.

Доступные поля для фильтрации и виды фильтров по ним:

Поле Виды фильтров
id InSetQuery, LikeQuery
entityType InSetQuery, LikeQuery
formType.code InSetQuery, LikeQuery
formType.title InSetQuery, LikeQuery, TsQuery
formType.description InSetQuery, LikeQuery, TsQuery
version InSetQuery, LikeQuery, RangeQuery
formData InSetQuery, LikeQuery

При фильтрации по formData можно указать путь до внутреннего json, например formData.someObject.someValue

Доступные поля для сортировки:

Поле
id
formType
version
formType.title
formType.description
entityType

По умолчанию сортировка производится по полю entityType.

Имя команды для вызова: UIStorage_http_ListFormsV2.
Поддерживается только синхронный вызов.
Результат выполнения команды не журналируется.

GetEntityForm (UI Storage)

Передаем JSON

{
  "entityType": "document",
  "formType": "card"
}

Получаем JSON с данными формы

{
  "id": "5fe0c0fc-f79a-4a0f-b741-7717c03ad5ed",
  "entityType": "document",
  "formType": "card",
  "formData": {
    "field1": "value1"
  },
  "version": 1
}

Возвращает форму EntityFormSettings по коду типа объекта entityType из EntityFormSettings и коду типа формы code из FormType из справочника.

Имя команды для вызова: UIStorage_http_GetEntityForm.
Поддерживается только синхронный вызов.
Результат выполнения команды не журналируется.

GetFormsByType (UI Storage)

Передаем JSON со списком типов форм

[
  "textSearchSnippet",
  "card"
]

Получаем JSON со списком форм

[
  {
    "id": "bb02daf9-5386-471e-93c0-04344c74272c",
    "entityType": "document",
    "formType": "card",
    "formData": {
      "field1": "value1"
    },
    "version": 1
  },
  {
    "id": "f755bbcd-7a67-4ad4-bcab-839323d54398",
    "entityType": "organization",
    "formType": "textSearchSnippet",
    "formData": {
      "field1": "value1"
    },
    "version": 1
  }
]

Возвращает список форм на основе списка их типов. Если список типов форм пустой, то возвращается список всех форм.

Имя команды для вызова: UIStorage_http_GetFormsByType.
Поддерживается только синхронный вызов.
Результат выполнения команды не журналируется.

ListKeys (UI Storage)

Получаем список всех существующих глобальных настроек

[
  {
    "key": "logo",
    "value": "<svg><circle cx=\"10\" cy=\"10\" r=\"10\"/></svg>",
    "title": "Логотип",
    "created": 1634644383273,
    "modified": 1634644383273,
    "lastUser": "d3f7d9c4-43aa-49ae-9d66-1d500f53cf3d",
    "version": 1
  },
  {
    "key": "color",
    "value": "#fcbe03",
    "title": "Цвет",
    "created": 1634644887499,
    "modified": 1634644887499,
    "lastUser": "d3f7d9c4-43aa-49ae-9d66-1d500f53cf3d",
    "version": 2
  }
]

Возвращает список всех существующих глобальных настроек.

Имя команды для вызова: UIStorage_http_ListKeys.
Поддерживается только синхронный вызов.
Результат выполнения команды не журналируется.

GetValue (UI Storage)

Передаем ключ глобальной настройки

"color"

Получаем значение глобальной настройки

"#fcbe03"

Возвращает JSON-значение глобальной настройки по ключу key.

Имя команды для вызова: UIStorage_http_GetValue.
Поддерживается только синхронный вызов.
Результат выполнения команды не журналируется.

CreateKey (UI Storage)

Передаем данные глобальной настройки

{
  "key": "color",
  "value": "#fcbe03",
  "title": "Цвет"
}

Получаем признак успешности

true

Создать новую глобальную настройку из данных CreateKeyDTO.
Гарантируется уникальность для поля key.

Имя команды для вызова: UIStorage_kafka_CreateKey.
Поддерживается асинхронный и синхронный вызов.
Результат выполнения команды журналируется.

UpdateKey (UI Storage)

Передаем данные глобальной настройки для обновления

{
  "key": "color",
  "value": "#fcbe04",
  "title": "Цвет фона",
  "version": 1
}

Получаем признак успешности

true

Обновить существующую глобальную настройку данными из UpdateKeyDTO.
При успешном обновлении version настройки увеличивается на единицу.

Имя команды для вызова: UIStorage_kafka_UpdateKey.
Поддерживается асинхронный и синхронный вызов.
Результат выполнения команды журналируется.

UpdateValue (UI Storage)

Передаем данные глобальной настройки для обновления

{
  "key": "color",
  "value": "#fcbe05",
  "version": 1
}

Получаем признак успешности

true

Обновить значение существующей глобальной настройки из UpdateValueDTO.
При успешном обновлении version настройки увеличивается на единицу.

Имя команды для вызова: UIStorage_kafka_UpdateValue.
Поддерживается асинхронный и синхронный вызов.
Результат выполнения команды журналируется.

DeleteKey (UI Storage)

Передаем ключ глобальной настройки

"color"

Получаем признак успешности

true

Удалить существующую глобальную настройку по её ключу key.

Имя команды для вызова: UIStorage_kafka_DeleteKey.
Поддерживается асинхронный и синхронный вызов.
Результат выполнения команды журналируется.

PersistFile (UI Storage)

Передаем список файлов и связанных ключей глобальных настроек

[
  {
    "path": "logo/background",
    "tempFileId": "ec476b5d-7cea-4138-b537-8f3032f33ac4"
  },
  {
    "path": "theme-color",
    "tempFileId": "f0e1f19a-c386-48aa-874f-d58ff9a147e3"
  }
]

Получаем список url для сохраненных файлов

[
  {
    "path": "logo/background",
    "fileUrl": "uisettings/logo/background/ec476b5d-7cea-4138-b537-8f3032f33ac4"
  },
  {
    "path": "theme-color",
    "fileUrl": "uisettings/theme-color/f0e1f19a-c386-48aa-874f-d58ff9a147e3"
  }
]

Сохранить файлы для указанных глобальных настроек по пути path.

Имя команды для вызова: UIStorage_kafka_PersistFile.
Поддерживается асинхронный и синхронный вызов.
Результат выполнения команды не журналируется.

Модели сервиса хранения UI

В сервисе использованы следующие модели:

FormTypeCode (UI Storage)

Соответствует типу String.

FormType (UI Storage)

Описание типа форм.

Поле Тип Обязательное Описание
code FormTypeCode Да Код типа формы
title String Да Заголовок типа формы
description String Нет Описание типа формы

Встроенный справочник:

code title description
card Карточка объекта Карточка объекта
createForm Форма создания Форма создания
editForm Форма редактирования Форма редактирования
list Список Элемент списка в реестре объектов
filterPanel Панель фильтров Панель фильтров

EntityFormSettingsId (UI Storage)

Соответствует типу UUID.

EntityFormSettingsCreateDTO (UI Storage)

Модель для создания формы.

Поле Тип Обязательное Описание Ограничения
entityType EntityTypeId Да Тип сущности - Не пустое
- Не длиннее 127 символов
formType FormTypeCode Да Код типа формы - Уникальное
- Не длиннее 127 символов
formData Json Да Данные формы

EntityFormSettings (UI Storage)

Модель формы.

Поле Тип Обязательное Описание
id EntityFormSettingsId Да ID формы
entityType EntityTypeId Да Тип сущности
formType FormTypeCode Да Код типа формы
formData Json Да Данные формы
version Int Да Версия

EntityFormSettingsForUpdate (UI Storage)

Модель для обновления формы.

Поле Тип Обязательное Описание Ограничения
id EntityFormSettingsId Да ID формы
formData Json Да Данные формы
version Int Да Версия

EntityTypeWithFormType (UI Storage)

Идентификатор конкретной формы конкретного типа объектов.

Поле Тип Обязательное Описание Ограничения
entityType EntityTypeId Да Код типа объекта
formType FormTypeCode Да Код типа формы

EntityFormSettingsDTO (UI Storage)

Сокращенная модель формы (используется для списков).

Поле Тип Обязательное Описание
id EntityFormSettingsId Да ID формы
entityType EntityTypeId Да Тип сущности
formType FormType Да Тип формы
version Int Да Версия

EntityFormSettingsFullDTO (UI Storage)

Развернутая модель формы с информацией о типе

Поле Тип Обязательное Описание
id EntityFormSettingsId Да ID формы
entityType EntityTypeId Да Тип сущности
formType FormType Да Тип формы
formData Json Да Данные формы
version Int Да Версия

GlobalSettingKey (UI Storage)

Соответствует типу String.

GlobalSetting (UI Storage)

Модель глобальной настройки.

Поле Тип Обязательное Описание
key GlobalSettingKey Да Ключ глобальной настройки
value Json Да Значение глобальной настройки
title String Да Название глобальной настройки
created TimeStamp Да Дата создания
modified TimeStamp Да Дата обновления
lastUser UUID Нет Пользователь, выполнивший последнее обновление
version Int Да Версия (optimistic lock)

CreateKeyDTO (UI Storage)

Модель для создания глобальной настройки.

Поле Тип Обязательное Описание Ограничения
key GlobalSettingKey Да Ключ глобальной настройки - Не пустое
- Не длиннее 64 символов
value Json Да Значение глобальной настройки
title String Да Название глобальной настройки Не длиннее 127 символов

UpdateKeyDTO (UI Storage)

Модель для обновления ключа глобальной настройки.

Поле Тип Обязательное Описание Ограничения
key GlobalSettingKey Да Ключ глобальной настройки - Не пустое
- Не длиннее 64 символов
value Json Да Значение глобальной настройки
title String Да Название глобальной настройки Не длиннее 127 символов
version Int Да Версия (optimistic lock)

UpdateValueDTO (UI Storage)

Модель для обновления значения глобальной настройки.

Поле Тип Обязательное Описание Ограничения
key GlobalSettingKey Да Ключ глобальной настройки - Не пустое
- Не длиннее 64 символов
value Json Да Значение глобальной настройки
version Int Да Версия (optimistic lock)

PersistFileDTO (UI Storage)

Модель для сохранения файлов глобальной настройки.

Поле Тип Обязательное Описание Ограничения
path String Да Полный путь, по которому надо сохранить временный файл - Не пустое
- Не длиннее 64 символов
tempFileId UUID Да ID временного файла

GlobalSettingFile (UI Storage)

Файл глобальной настройки.

Поле Тип Обязательное Описание
path String Да Полный путь, по которому сохранен файл
fileUrl String Да URL к сохраненному файлу

User-profile: сервис профилей пользователей

Сервис профилей пользователей выступает в роли прокси к модели данных. Предоставляет более удобный интерфейс для работы конкретно с профилями пользователей, чем модель данных.

В сервисе реализованы следующие команды (все команды начинаются с префикса "userProfile_"):

Также сервис слушает события из авторизации и создает профили при регистрации.

Конфигурирование сервиса профилей пользователей

Для работы сервису нужно стандартное окружение Verdi, а также сервис модели данных, работающий в этом окружении.

Список переменных окружения сервиса профилей пользователей

Переменная Тип Обяза-тельная Значение по умолчанию Описание
SERVER_PORT int нет 8080 Порт сервера
USER_PROFILE_CONSUMER_GROUP string нет user-profile-service Имя consumer-группы для чтения из кафка-топика команд. Не должна меняться и не должна быть пустой, иначе сервис перечитает свои команды при перезапуске.
USER_PROFILE_CONSUMER_TOPIC string нет user-profile-service-commands Имя кафка-топика с командами для этого сервиса
USER_PROFILE_COMMANDS_CONSUMER_PARALLELISM int нет 16 Параллелизм при обработке команд
USER_PROFILE_CONSUMER_POLL_TIMEOUT duration string нет 10 milliseconds timeout запроса poll для kafka consumer
USER_PROFILE_CONSUMER_POLL_INTERVAL duration string нет 100 milliseconds интервал между запросами poll для kafka consumer
USER_PROFILE_CONSUMER_PROPS string нет "max.poll.records=500;max.partition.fetch.bytes=524288" дополнительные параметры для kafka consumer в формате "key1=value1;key2=value2"
VERDI_CONSUL string нет http://localhost:8500 Адрес сервера consul
VERDI_CONSUL_AUTH_USER string нет нет Название учетной записи Сonsul. Если название не указано, то настройки авторизации не будут применены.
VERDI_CONSUL_AUTH_PASSWORD string нет нет Пароль учетной записи Сonsul.
VERDI_KAFKA_ADDRESS string нет localhost:9092 Адрес брокера Kafka.
VERDI_KAFKA_TOPIC string нет commandevents Название кафка-топика для отправки сообщений со статусами выполняемых команд. ОБЯЗАТЕЛЬНО должно соответствовать названию этого топика в сервисе статуса команд.
VERDI_KAFKA_AUTH_USER string нет нет Название учетной записи Kafka. Если название не указано, то настройки авторизации не будут применены.
VERDI_KAFKA_AUTH_PASSWORD string нет нет Пароль учетной записи Kafka.
VERDI_KAFKA_AUTH_TRUSTSTORE_LOCATION string нет нет Путь до хранилища сертификатов (Java key store). Если путь не указан, то сертификат применяться не будет.
VERDI_KAFKA_AUTH_TRUSTSTORE_PASSWORD string нет нет Пароль к хранилищу сертификатов.
VERDI_KAFKA_AUTH_MODE string нет "" Режим аутентификации: static - одна учетная запись на все запросы, mapping - учетная запись зависит от запроса
VERDI_KAFKA_AUTH_CONFIG string нет "" Настройки для аутентификации: если AuthMode = mapping, то необходим JSON с List[KafkaAuthConfig]. Переменная соответствует полю authConfig из KafkaAuthSettings.
VERDI_KAFKA_AUTH_PRINCIPAL string нет "" Principal учетной записи Kafka в Kerberos(в случае соединения с kafka через Kerberos).
VERDI_KAFKA_AUTH_KEYTAB_PATH string нет "" Путь до keytab-файла(в случае соединения с kafka через Kerberos).
VERDI_KAFKA_AUTH_CACHE_SIZE int нет Максимальный размер кеша для Kafka producer (количество активных соединений).
VERDI_KAFKA_AUTH_CACHE_TTL duration string нет Время жизни Kafka producer в кеше.
VERDI_KAFKA_CONNECTION_CHECK_TEST_MESSAGES_INTERVAL duration string нет 4 minutes Применяется только для producer-ов со способом аутентификации kerberos. Интервал отправки тестовых сообщений кафки в топик connectionCheck.testMessagesTopicName. Тестовые сообщения (null, service producer test) отправляются регулярно с этим интервалом.
VERDI_KAFKA_CONNECTION_CHECK_INTERVAL duration string нет 60 seconds Применяется только для producer-ов со способом аутентификации kerberos. Интервал проверки того, сколько тестовых сообщений было отправлено за данный период. Если количество сообщений за этот период равно количеству сообщений за прошлый период, то начинается отсчет периода без сообщений.
VERDI_KAFKA_CONNECTION_CHECK_FAILED_AFTER_INTERVAL duration string нет 5 minutes Применяется только для producer-ов со способом аутентификации kerberos. Максимальная продолжительность периода без успешно отправленных тестовых сообщений. По ее достижении сервис будет объявлен больным.
VERDI_HOST string нет localhost Адрес service discovery для Verdi
VERDI_TTL duration
string
нет 30 seconds Период после последней отправки health check, в течение которого ServiceDiscovery считает данный сервис живым.
VERDI_HEALTH_CHECK duration
string
нет 10 seconds Периодичность отправки health check в ServiceDiscovery
VERDI_COMMAND_STORAGE_UPDATE_PERIOD duration
string
нет 1 minutes Время кэширования данных по командам из CommandDiscovery
VERDI_SERVICE_DISCOVERY_UPDATE_PERIOD duration
string
нет 30 seconds Время кэширования данных по сервисам из ServiceDiscovery
VERDI_ALLOW_INTERNAL_COMMANDS bool нет true Можно ли сервису отправлять внутрисистемные команды
VERDI_CONSIDER_ALL_COMMANDS_AS_INTERNAL boolean Нет false Флаг, определяющий будут ли все обращения в другие сервисы являться внутренними (т.е. не требовать авторизацию). Детальное описание механизма: Внутренние команды.
VERDI_CONSUL_CONNECTION_MAX_RETRY int нет 5 Максимальное количество попыток подключений к Consul
VERDI_CONSUL_CONNECTION_RETRY_DELAY duration
string
нет 1 seconds Таймаут между неудачными попытками подключения к Consul
VERDI_KAFKA_SYNC_POLLING_PERIOD duration
string
нет 1 seconds
VERDI_KAFKA_SYNC_POLLING_TIMEOUT duration
string
нет 1 seconds
VERDI_NON_BLOCKING_PARALLELISM int нет 2 Количество потоков в асинхронном пуле для senderlib
USER_PROFILE_DATA_MODEL_COMMANDS_PREFIX string нет commands/userProfile Префикс по которому модель данных принимает команды
USER_PROFILE_USER_EVENTS_TOPIC string нет userEvents Топик с событиями из авторизации о регистрации пользователей
USER_PROFILE_USER_EVENTS_HANDLING_PARALLELISM int нет 16 Параллелизм при обработке событий о регистрациях пользователей
USER_PROFILE_DB_JDBC_URL string нет jdbc:postgresql://127.0.0.1:5432/userprofile Адрес Postgres
USER_PROFILE_DB_USER string нет postgres Имя пользователя в базе данных
USER_PROFILE_DB_PASSWORD string нет postgres Пароль к базе данных
USER_PROFILE_DB_THREADS int нет 10 Количество потоков в пуле потоков для соединения с БД
USER_PROFILE_DB_QUEUE_SIZE int нет 300 Размер очереди для действий базы данных, которые не могут быть выполнены немедленно, когда все потоки заняты. За пределами этого значения новые действия немедленно завершаются неудачей
USER_PROFILE_DB_CONN_MAX int нет 10 Максимальное количество одновременных подключений к БД
USER_PROFILE_DB_CONN_TIMEOUT duration string нет 20 second Максимальное время ожидания ответа для соединения к БД. Если это время превышено, а соединение не становится доступным, будет брошено исключение SQLException. 1000 мс — минимальное значение.
USER_PROFILE_DB_ISOLATION string нет "READ_COMMITTED" Уровень изоляции транзакций для новых подключений. Допустимые значения: NONE, READ_COMMITTED, READ_UNCOMMITTED, REPEATABLE_READ, SERIALIZABLE.
USER_PROFILE_DB_READONLY boolean нет false Read-only SQL транзакция может изменять только временные таблицы. Этот параметр управляет статусом «только для чтения» по умолчанию для каждой новой транзакции.
USER_PROFILE_DB_CONN_MIN int нет = DB_THREADS Минимальное количество одновременных подключений к БД
USER_PROFILE_DB_VALIDATION_TIMEOUT duration string нет 1 seconds Максимальное время, в течение которого соединение будет проверяться на работоспособность. 1000 мс — минимальное значение.
USER_PROFILE_DB_IDLE_TIMEOUT duration string нет 10 minutes Максимальное время, в течение которого соединению разрешено простаивать в пуле. Значение 0 означает, что простаивающие соединения никогда не удаляются из пула.
USER_PROFILE_DB_MAX_LIFETIME duration string нет 30 minutes Максимальное время жизни соединения в пуле. Когда простаивающее соединение достигает этого времени ожидания, даже если оно недавно использовалось, оно будет удалено из пула. Значение 0 указывает на отсутствие максимального срока службы.
USER_PROFILE_DB_INITIALIZATION_FAIL_FAST string нет false Deprecated, начиная с версии Slick 3.3.0. Определяет, будет ли пул «быстро выходить из строя», если пул не может быть успешно заполнен начальными соединениями. Если соединения не могут быть созданы во время запуска пула, будет выдано исключение RuntimeException. Это свойство не имеет никакого эффекта, если minConnections равно 0.
USER_PROFILE_DB_LEAK_DETECTION_THRESHOLD int нет 0 Время, в течение которого соединение может находиться вне пула, прежде чем будет зарегистрировано сообщение, указывающее на возможную утечку соединения. Значение 0 означает, что обнаружение утечек отключено. Наименьшее приемлемое значение для включения обнаружения утечек составляет 10 с.
USER_PROFILE_DB_CONNECTION_TEST_QUERY string нет "SELECT 1" Выражение, которое будет выполнено непосредственно перед получением соединения из пула для проверки того, что соединение с базой данных все еще активно. Оно зависит от базы данных и должно представлять собой запрос, требующий минимальной обработки базой данных (например, «VALUES 1»). Если этот параметр не установлен, вместо него используется метод JDBC4 Connection.isValid().
USER_PROFILE_DB_AUTO_COMMIT boolean нет true Это свойство определяет то, как будут вести себя по умолчанию возвращаемые соединения относительно autocommit-а.
USER_PROFILE_DB_SCHEMA string нет "public" Устанавливает schema по умолчанию
USER_PROFILE_DB_ISOLATE_INTERNAL_QUERIES boolean нет false Определяет то, изолируются ли с помощью транзакций внутренние запросы пула(например запрос connection alive test). Свойство применяется только если autoCommit выключен.
USER_PROFILE_DB_INITIALIZATION_FAIL_TIMEOUT int нет 1 Работает, начиная с версии Slick 3.3.0. Определяет, будет ли пул «быстро выходить из строя», если пул не может быть успешно заполнен начальными соединениями. Любое положительное число считается числом миллисекунд для попытки получить начальное соединение;поток приложения будет заблокирован в течение этого периода. Если соединение не может быть получено до истечения этого времени,будет брошено исключение. Данный таймаут применяется после периода connectionTimeout. Если значение равно нулю (0),HikariCP попытается получить и проверить подключение. Если соединение получено,но проверка не пройдена, будет брошено исключение, и пул не будет запущен. Однако,если соединение не может быть получено, пул запустится,но последующие попытки получить соединение могут потерпеть неудачу.Значение меньше нуля пройдет любую первоначальную попытку подключения, и пул немедленно запустится,пытаясь получить соединения в фоновом режиме.Следовательно, последующие попытки получить соединение могут потерпеть неудачу.
USER_PROFILE_DB_REGISTER_MBEANS boolean нет false Зарегистрированы ли JMX Management Beans («MBeans»)
VERDI_COMMANDS_HTTP_RETRY_ATTEMPTS int нет 5 Поле attempts из RetrySettings
VERDI_COMMANDS_HTTP_RETRY_DELAY duration string нет "5 seconds" Поле delay из RetrySettings
VERDI_COMMANDS_HTTP_RETRY_KIND string нет "OnSomeExceptions(ConnectException)" CommandResultRetryConditionKind

Команды сервиса профилей пользователей

createProfileSection (User-profile)

На входе объект с секцией

{
  "title": "test section"
}

На выходе Id созданной секции

"test_section"

Создает секцию в профиле пользователя. Если явный Id не указан, генерирует его автоматически, заменяя " " на "_" и транслитерируя символы кириллицы в латиницу.

Имя команды для вызова: userProfile_createProfileSection.
Поддерживается асинхронный и синхронный вызов.
Результат выполнения команды не журналируется.

deleteProfileSection (User-profile)

На входе Id секции

"test_section"

На выходе ничего

{}

Удаляет секцию в профиле пользователя по ее Id.

Имя команды для вызова: userProfile_deleteProfileSection.
Поддерживается асинхронный и синхронный вызов.
Результат выполнения команды не журналируется.

updateProfileSection (User-profile)

Объект для изменения секции

{
  "id": "test_section",
  "title": "new test title",
  "description": "test description"
}

На выходе ничего

{}

Меняет название и описание секции.

Имя команды для вызова: userProfile_updateProfileSection.
Поддерживается асинхронный и синхронный вызов.
Результат выполнения команды не журналируется.

getProfileSections (User-profile)

На входе ничего

{}

На выходе список информаций о секции

[
  {
    "title": "Профиль пользователя",
    "id": "userProfile",
    "description": ""
  },
  {
    "title": "Основные данные",
    "id": "basicData",
    "description": ""
  },
  {
    "title": "Test title",
    "id": "test_title",
    "description": "Test title"
  }
]

Возвращает список секций в структуре профиля.

Имя команды для вызова: userProfile_getProfileSections.
Поддерживается только синхронный вызов.
Результат выполнения команды не журналируется.

addProfileField (User-profile)

На входе объект с информацией о поле

{
  "sectionId": "test_section",
  "title": "Тестовое поле",
  "type": "string",
  "multiple": false,
  "settings": {
    "maxLength": 100
  }
}   

На выходе Id нового поля

"Testovoye_pole"

Создает поле в секции профиля. Если явный Id поля не указан, генерирует его автоматически, заменяя " " на "_" и транслитерируя символы кириллицы в латиницу.

Имя команды для вызова: userProfile_addProfileField.
Поддерживается асинхронный и синхронный вызов.
Результат выполнения команды не журналируется.

deleteProfileField (User-profile)

На входе Id секции и Id поля

{
  "sectionId": "test_section",
  "fieldId": "Testovoye_pole"
}

На выходе ничего

{}

Удаляет поле в секции.

Имя команды для вызова: userProfile_deleteProfileField.
Поддерживается асинхронный и синхронный вызов.
Результат выполнения команды не журналируется.

updateProfileField (User-profile)

На входе новые параметры поля

{
  "sectionId": "test_section",
  "fieldId": "Testovoye_pole",
  "title": "new test title",
  "description": "updated description",
  "settings": {
    "maxLength": 150
  }
}

На выходе ничего

{}

Изменяет некоторые параметры поля.

Имя команды для вызова: userProfile_updateProfileField.
Поддерживается асинхронный и синхронный вызов.
Результат выполнения команды не журналируется.

getProfileSectionFields (User-profile)

На входе Id секции

"basicData"

На выходе список полей в секции

[
  {
    "sectionId": "basicData",
    "fieldId": "secondName",
    "type": "string",
    "title": "Фамилия",
    "description": "",
    "multiple": false,
    "nullable": false,
    "settings": {
      "maxLength": 64
    }
  },
  {
    "sectionId": "basicData",
    "fieldId": "name",
    "type": "string",
    "title": "Имя",
    "description": "",
    "multiple": false,
    "nullable": false,
    "settings": {
      "maxLength": 64
    }
  },
  {
    "sectionId": "basicData",
    "fieldId": "email",
    "type": "string",
    "title": "Email",
    "description": "",
    "multiple": false,
    "nullable": false,
    "settings": {
      "maxLength": 64
    }
  },
  {
    "sectionId": "basicData",
    "fieldId": "middleName",
    "type": "string",
    "title": "Отчество",
    "description": "",
    "multiple": false,
    "nullable": true,
    "settings": {
      "maxLength": 64
    }
  }
]

Возвращает список полей в секции.

Имя команды для вызова: userProfile_getProfileSectionFields.
Поддерживается только синхронный вызов.
Результат выполнения команды не журналируется.

getUserProfile (User-profile)

На входе Id пользователя и список секций, которые нужно получить

{
  "userId": "5dfbbda7-b340-4a04-aae2-da4379f89eb9",
  "sections": [
    "basicData"
  ]
}

На выходе полная информация о пользователя

{
  "id": "5dfbbda7-b340-4a04-aae2-da4379f89eb9",
  "created": 1654608945300,
  "modified": 1654609126388,
  "version": 1,
  "sections": {
    "basicData": {
      "name": "John",
      "email": "emailname@mail.io9",
      "middleName": "Jovonovich",
      "secondName": "Week"
    }
  }
}

Возвращает информацию о пользователе. Если передать список секций, то возвращает не всю информацию, а только запрошенные секции.

Имя команды для вызова: userProfile_getUserProfile.
Поддерживается синхронный и асинхронный вызов.
Результат выполнения команды не журналируется.

setUserProfileField (User-profile)

На входе информация для обновления поля профиля

{
  "userId": "5dfbbda7-b340-4a04-aae2-da4379f89eb9",
  "section": "basicData",
  "field": "name",
  "value": "JohnJohn",
  "version": 3
}

На выходе новая версия

4

Меняет указанное поле в профиле пользователя, если совпадает версия.

Имя команды для вызова: userProfile_setUserProfileField.
Поддерживается синхронный и асинхронный вызов.
Результат выполнения команды не журналируется.

Обрабатываемые события сервиса профилей пользователей

События слушаются в USER_PROFILE_USER_EVENTS_TOPIC

Источник событий eventType payloadType Описание
mon registration user Создает профиль пользователя при авторизации

Объекты сервиса профилей пользователей

Типы данных, которые принимают или возвращают команды сервиса.

AddSectionField (User-profile)

Поле Тип Обязательное Описание Ограничения
sectionId String Да Id секции, в которую поместить поле - Не пустое
- Не больше 64 символов
fieldId String Нет Id поля - Не больше 64 символов
title String Да Название поля - Не больше 256 символов
type String Да Тип поля доступный для сущностей модели данных
description String Нет Описание поля
multiple Boolean Да Множественное ли поле
settings Json Нет Дополнительные настройки для указанного типа поля

CreateSection (User-profile)

Поле Тип Обязательное Описание Ограничения
title String Да Название секции - Не больше 256 символов
id String Нет Id секции - Не пустое
- Не больше 64 символов
description String Нет Описание секции

DeleteSectionField (User-profile)

Поле Тип Обязательное Описание Ограничения
sectionId String Да Id секции с полем
fieldId String Да Id поля

Section (User-profile)

Поле Тип Обязательное Описание Ограничения
title String Да Название секции - Не больше 256 символов
id String Да Id секции
description String Нет Описание секции

SectionField (User-profile)

Поле Тип Обязательное Описание
sectionId String Да Id секции с полем
fieldId String Да Id поля в секции
title String Да Название поля
type String Да Тип поля доступный для сущностей модели данных
description String Да Описание поля
multiple Boolean Да Множественное ли поле
nullable Boolean Да Обязательное ли поле
settings Json Да Дополнительные настройки для указанного типа поля

UpdateSectionField (User-profile)

Поле Тип Обязательное Описание Ограничения
sectionId String Да Id секции с полем
fieldId String Да Id поля
title String Да Новое название поля
description String Нет Новое описание поля
settings Json Да Новые дополнительные настройки для указанного типа поля

UserProfileDTO (User-profile)

Поле Тип Обязательное Описание
id String Да Id пользователя
created Long Да Время создания
modified Long Да Время последнего изменения
version Int Да Версия для борьбы с потерями обновлений
sections Map[String, Json] Да Данные из секций профиля

GetUserProfileDTO (User-profile)

Поле Тип Обязательное Описание Ограничения
userId UUID Да Id пользователя
sections List[String] Нет Список секций, которые нужно вернуть

SetProfileFieldDTO (User-profile)

Поле Тип Обязательное Описание Ограничения
userId UUID Да Id пользователя
section String Да Секция, в которой находится поле для изменения
field String Да Название поля, которое нужно поменять
value Json Да Новое значение для этого поля
version Int Да Версия, полученная в составе UserProfile

Verdi-cache: библиотека для кэширования

Предоставляет интерфейс и реализацию кеша.

Loggers config

<logger name="com.embedika.verdi.cache.CacheApi" level="INFO"/>
<logger name="scalacache.caffeine.CaffeineCache" level="INFO"/>

Структуры Verdi-cache

VerdiCacheConfig (Verdi-cache)

Настройки кеширования.

Поле Тип Обязательное Описание Ограничения
maxSize int Нет Максимальное количество элементов в кеше, при превышении которого элементы начнут удаляться (LRU).
elementTTL duration string Нет Максимальное время жизни элемента.

Xacmldsl: библиотека для работы с XACML

Библиотека предоставляет DSL для создания и разбора XACML формата (XML).

Ключевые сущности: - TBD