Разработка решений на платформе ELMA365 / Переносимые сервисы в модулях

Переносимые сервисы в модулях

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

До этого момента мы рекомендовали устанавливать сервисы независимо от платформы и поддерживать их самостоятельно. У этого решения есть важные недостатки — сложность установки и поддержки такого решения для конечного разработчика и администраторов.

Решение

Для упрощения и ускорения разработки своих микросервисов мы добавили в пользовательские Модули новую функциональную возможность — Сервисы.

portable-microservices_2

Сервис — это docker контейнер, который выполняет определенную функцию на сервере. Этот контейнер платформа обернёт и разместит в отдельном пространстве в среде исполнения kubernetes.

Начало внимание

Переносимые сервисы доступны только в ELMA365 On-Premises.

Конец внимание

В ELMА365 On-Premises версии 2021.11 опция Переносимые сервисы закрыта под фича-флагом enableModuleServices. Чтобы включить флаг, выполните команду на сервере ELMA365 On-Premises:

elma365ctl featureflag enableModuleServices enable

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

  1. К таким контейнерам нельзя присоединить постоянное хранилище. То есть все операции с файловой системой будут утрачены при перезапуске сервиса. Это означает, что платформа поддерживает только stateless сервисы, которые, тем не менее, могут общаться с внешними надёжными хранилищами.
  2. Поддерживается только указание url-адреса контейнера. Это означает, что вы должны предварительно разместить образ своего сервиса в публичном или приватном репозитории. Также это означает, что сам образ сервиса не упаковывается при экспорте модуля и не переносится с пакетом .e365. На данный момент при установке готового модуля с сервисами системе требуется доступ до указанного адреса репозитория для скачивания docker образа.
  3. У таких сервисов нет лимитов на ресурсы выполнения.
  1. Взаимодействие с сервисом возможно только из серверных сценариев модуля (виджеты, процессы, действия бп, методы api, обработчики событий) и только через HTTP запросы. Однако сам сервис может взаимодействовать с любым другим внешним сервисом по любому каналу связи и протоколу взаимодействия.

Пример использования

Предположим, что в одном из решений для вузов нам понадобилось генерировать и показывать математические формулы. Мы знаем, что наши пользователи хорошо владеют языком описания формул LaTeX. В итоге задачу сформулируем так: Генерировать изображение из формулы LaTeX.

Для решения задачи поиском находим готовый контейнер с сервисом генерации картинки по формуле: https://github.com/chialab/math-api.

Этот контейнер можно собрать самостоятельно из исходного кода и разместить в своём приватном репозитории или использовать готовый из публичного репозитория docker-hub: https://hub.docker.com/r/chialab/math-api.

Создание сервиса

portable-microservices_3

По умолчанию адрес образа указывает на docker-hub репозиторий, однако для приватного репозитория вы можете указать любой полный адрес, а также указать логин и токен для безопасного подключения. Обратите внимание, что логин и токен при экспорте модуля передаются в открытом виде.

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

Далее мы можем использовать этот сервис в серверном сценарии виджета для генерации картинки. Для генерации картинки можно использовать http метод GET /render, об этом, о чём говорится в описании сервиса. Соответственно в виджете мы будем запрашивать у пользователя формулу (Строка) и желаемую ширину картинки (Число).

Вот пример готового сценария:

async function renderImage(): Promise<void> {
    let source = encodeURIComponent(Context.data.formula!);
    let width = encodeURIComponent((Context.data.shirina_kartinki || 400).toString());
    let imgResp = await Namespace.services.math.fetch(`/render?input=latex&inline=1&output=png&source=${source}&width=${width}`, {
        headers: {
            "Accept" : "image/png"
        }
    });
 
    let buff = await imgResp.arrayBuffer();
 
    Context.data.kartinka = await Context.fields.kartinka.create(`render-${Date.now()}.png`, buff);
}

В этом примере мы используем Namespace.services.math для доступа к сервису — это позволяет вызывать HTTP методы сервиса в серверных сценариях TSSDK. Для вызова мы указываем относительный адрес метода, остальное реализует платформа.

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

portable-microservices_4

При этом результат рендера картинки будет выглядеть следующим образом:

portable-microservices_1