Протоколы и режимы обработки данных
Далее, рассматривается архитектура и принципы работы пользовательских блоков, реализованных на языке Python. Ниже разберём протоколы обмена данными между системой и пользовательским кодом, а также режимы выполнения: от получения метаданных до обработки данных и завершения сессии.
Старт модуля блоков на Python
Модуль запускается после старта контейнера. Если Proceset уже работает, модуль отправляет ему уведомление о своём запуске, после чего Proceset с помощью команды --get-info
запрашивает информацию о доступных пользовательских блоках, реализованных на Python. В случае, если модуль был запущен раньше Proceset, последний при старте самостоятельно запрашивает у модуля данные о реализованных блоках.
При старте модуля все entrypoint.py
, указанные в конфигурационном файле com.infomaximum.subsystem.automationagentextpy.json, запускаются с аргументом --get-info
. Запуск скрипта подтверждается появлением команды в выходном потоке stdout.
{"cmd":"start"}
Пример ожидаемого ответа в stdout:
{
"uuid":"<uuid>",
"data": {
"mode" : "isolated",
"protocol_version": 2,
"groups" : [{
"uuid": "test_group_17d80e527c6eb4cb9b9cc4031378ae176",
"name": {
"en": "Testing group info",
"ru": "Тестовая группа"
},
"category": "tools",
"icon":"icons/test_group_17d80e527c6eb4cb9b9cc4031378ae176.png",
"blocks" : [{
"uuid" : "test_block_7914294fbc6042e180c40ea276ad041b",
"type" : "action",
"name" : {
"en" : "Testing block info",
"ru" : "Тестовый блок",
},
"description" : {
"en" : "Testing block description",
"ru" : "Описание тестового блока",
},
"compatible_connections" : [],
"optionals" : {
"is_save_data_on_fail_block_type" : False,
"is_system_block_type" : False
},
"fields" : """[{
key: 'var_1',
type: 'text',
label: 'Введи 1 число',
hint: "Поле для ввода первого числа",
required: true
}, {
key: 'var_2',
type: 'text',
label: 'Введи 2 число',
hint: "Поле для ввода второго числа",
required: true
}]"""
},{
"uuid" : "test_block_9ceab1276c364fa981e765d4b51d90a0",
"type" : "action",
"name" : {
"en" : "Testing block info",
"ru" : "Тестовый блок",
},
"description" : {
"en" : "Testing block description",
"ru" : "Описание тестового блока",
},
"compatible_connections" : ["test_connection_422178d485924ee89121d4e7b992f918"],
"optionals" : {
"is_save_data_on_fail_block_type" : False,
"is_system_block_type" : False
},
"fields" : """[{
key: 'f_1',
type: 'text',
label: 'Поле1',
hint: "Первое поле",
required: true
}, {
key: 'f_2',
type: 'text',
label: 'Поле2',
hint: "Второе необязательное поле",
required: false
}]"""
}],
"connections" : [{
"uuid" : "test_connection_422178d485924ee89121d4e7b992f918",
"name" : {
"en" : "Testing connection info",
"ru" : "Тестовое подключение",
},
"description" : {
"en" : "Testing connection description",
"ru" : "Описание тестового подключения",
},
"fields" :"""[{
key: 'var_1',
type: 'text',
label: 'Введи число',
hint: 'Поле для ввода 1',
required: true
},{
key: 'var_2',
type: 'text',
label: 'Введите что-нибудь',
hint: 'Поле для ввода 2',
required: true
}]"""
}]
}]
}
}
Где:
data
— основные данные, которые содержат информацию о группе, блоках и подключенияхmode
— режим запуска блоков (interactive
/isolated
)protocol_version
— версия протоколаgroups
— массив группuuid
— уникальный идентификатор группы. Для уникальности идентификаторов используйте сгенерированный UUIDname
— локализованное название группыen
— на английскомru
— на русском
icon
— путь к файлу иконки группы относительно папки скриптаcategory
— категория верхнего уровня, в которую попадают блоки. Доступны следующие значения:"databases"
,"storages"
,"services"
,"tools"
blocks
— массив блоковuuid
— уникальный идентификатор блокаtype
— тип блока (action
/trigger
)name
— локализованное название блокаen
— на английскомru
— на русском
description
— локализованное описание блокаen
— на английскомru
— на русском
compatible_connections
— список UUID-подключений, которые совместимы с блокомfields
— строка с описанием полей блока. Представляет собой JS-код, который описывает поля для ввода данных и прочие элементы управления профиля блока. Соответсвует описанию пользовательских интеграций
connections
— массив подключенийuuid
— уникальный идентификатор подключенияname
— локализованное название подключенияen
— на английскомru
— на русском
description
— локализованное описание подключенияen
— на английскомru
— на русском
compatible_connections
— список UUID-подключений, которые совместимы с блокомfields
— строка с описанием полей подключения. Представляет собой JS-код, который описывает поля для ввода данных, и прочие элементы управления профиля блока. Соответсвует описанию пользовательских интеграций
Если возникает ошибка (например, InvalidBlockDefinitionException или ValidationError), проверьте, что структура данных, возвращаемая скриптом, соответствует ожидаемому формату: каждая группа должна содержать корректно описанные блоки, подключения и обязательные поля, такие как uuid, name, fields и другие.
Режим изолированных запусков
Каждая сессия обработки данных запускает точку входа — entrypoint.py
. Особенности работы системы Request-Response:
- Для каждого запроса генерируется уникальный идентификатор.
- Каждый запрос отправляется в отдельном потоке.
- Запрос и ответ — однострочные, переводы строк экранируются.
Старт сессии
При запуске блока запускается скрипт. Также, запуск блока обозначает старт сессии обработки данных.
Имена и значения константных полей, а также список имен переменных полей, передаются один раз вместе с первой пачкой (batch) данных. Последовательность значений переменных полей определяется порядком их имен в списке.
Аргументы запуска:
--start
--block-uuid "some_block_4345f5709cbb4a8486d800b2908168bf"
--input-data {
"data": {
"static_fields": [{
"name": "field1",
"value": "value1"
},{
"name": "field3",
"value": 3
}],
"dynamic_field_names": ["StringField1", "FrequencyDoubleField", "ObjectField3", "LongArrayField4", "FileContentField5"],
"execution_mode": "DEBUG_BLOCK",
"connection_fields": [{
"name": "host",
"value": "115.151.51.1"
},{
"name": "port",
"value": 1088
},{
"name": "token",
"value": "TIh3YEFigvdF1DiDdmASZNPD8tJjYvFOhqtW6TWirKKdLBBlL75TXnO5jr4Z577aTsf1MLLJDPTpeMk4uJt5MGVz3jARBznWaZVtaEQXL0YWvAng5f8K"
}]
},
"uuid": "a1db9946-2454-423f-a76e-fd8a6e815f97"
}
Где:
--start
— команда запуска сессии обработки данных--block-uuid
— идентификатор блока--input-data
— входные данные в формате JSONuuid
— уникальный идентификатор запросаstatic_fields
— поля, значения которых не меняются между записями входящих данных, т. е. не содержат маппингdynamic_field_names
— список имен полей, значения которых меняются между записями входящих данных, т. е. содержат маппингexecution_mode
— режим выполненияSIMPLE_EXECUTION
— обычное выполнение опубликованного скриптаDEBUG_FULL
— полное тестирование скриптаDEBUG_BLOCK
— режим тестирования блока
connection_fields
— значения полей подключения
Пример ответа:
{
"uuid": "a1db9946-2454-423f-a76e-fd8a6e815f97",
"data": {
"batch_size": 10,
}
}
Где:
uuid
— идентификатор запросаbatch_size
— количество записей в запросе разработки итераций
Обработка итераций
При обработке итераций входные данные приходят в виде набора входных полей с учетом примененного маппинга. Типы входных полей должны быть заранее известны на стороне Python — на их основе формируется описание, возвращаемое в ответ на команду --get-info
.
Конвертация типов значений определяется соглашением о типах данных. Значения переменных входных полей передаются в виде вложенных массивов. В последующих пачках данных приходят только значения переменных входных полей.
Пример передаваемой пачки данных:
{
"uuid": "e3128e7c-26f5-494c-8beb-3ad96c470310",
"cmd": "insert",
"data": {
"dynamic_field_values": [[
"Строка1",
9.99,
{"Name":"Иван","Values":[1723717500,1725971582,1599741185]},
[1, 2],
"file_contents/4xXmZtu0zjuYxVQOnIZH.tmp"
],[
"Строка2",
8.88,
{"Name":"Анна","Values":[1747678746,1724876374,1587798799]},
[3, 4],
"file_contents/vyquY2sx7mfTw2omCzk0oLB.tmp"
]],
"end_of_data": true
}
}
Где:
uuid
— уникальный идентификатор запросаcmd
— команда вставки данныхdata
— объект с вставляемыми даннымиdynamic_field_values
— массив записей для вставкиend_of_data
— флаг (true
), указывающий на последнюю пачку данных для вставки
Ответ на первую пачку данных:
{
"uuid": "dcbce17f-3606-4f0a-bba3-26f196512b2d",
"data": {
"aggregate_mode": true,
"output_variables": [{
"type": "FileContent",
"name":"File1"
},{
"type": "Long",
"name":"Long1"
} ,{
"type": "Object",
"name":"var_2",
"struct": [{
"name": "field1",
"type": "UnixTime"
},{
"name": "field2",
"type": "Long"
}]
},{
"type": "ObjectArray",
"name": "var3",
"struct": [{
"name": "field1",
"type": "Object",
"struct": [{
"name": "field1_1",
"type": "BigIntegerArray"
}]
},{
"name": "field2",
"type": "String"
}]
}],
"records": [[ #ответ на первую запись [
"/file_contents/77YRlI4CB6u2mj4ARVuB.tmp",
101,
{
"field1":1735035524,
"Field2":1234512
},
[{
"field1":{
"field1_1": [3243243254324324323, 87568758758657865765]
},
"field2": "StringValue1"
}]
],[
"/file_contents/77YRlI4CB6u2mj4ARVuB.tmp",
102,
{
"field1":1735035524,
"Field2":1234512
},
[]
]],[#ответ на вторую запись
],[#две пустых записи - агрегация
],[#результат агрегации
"/file_contents/BC2ZD1n8EZ29XrOtjhUq.tmp",
951,
{
"field1":1735031111,
"Field2":9876541
},
[{
"field1":{
"field1_1": [44444444444444444, 55555555555555555555]
},
"field2": "StringValue2"
}]
]]
}
}
Где:
uuid
— уникальный идентификатор запросаdata
— объект с данными ответаaggregate_mode
— режим агрегации. В значенииtrue
будет прервана связь с вышестоящими блоками, так как у одной записи несколько источников и невозможно определить корректную ссылку на родительский блокoutput_variables
— описание выходных переменныхname
— имя поляtype
— тип поля
records
— возвращаемые записи. Представляет собой массив трех уровней вложенности:- 1-й уровень — каждый элемент соответствует одной входящей записи
- 2-ой уровень — каждый элемент соответствует одной исходящей записи. Набор элементов представляет собой ответ на входящую запись
- 3-й уровень — каждый элемент соответствует значению поля исходящей записи. Порядок и типы полей соответствуют описанию в
output_variables
Ответ на последующие пачки данных:
{
"uuid": "9beb4eef-832f-47dd-b828-ebb3edefbae6",
"data": {
"records": [[#ответ на первую запись - две выходных записи [
"file:file_contents/77YRlI4CB6u2mj4ARVuB.tmp",
101,
{
"field1":1735035524,
"Field2":1234512
},
[{
"field1":{
"field1_1": [3243243254324324323, 87568758758657865765]
},
"field2": "StringValue1"
}]
],[
"file:file_contents/77YRlI4CB6u2mj4ARVuB.tmp",
102,
{
"field1":1735035524,
"Field2":1234512
},
[]
]],[#ответ на вторую запись - пусто
],[#две пустых записи - агрегация или фильтрация
],[[
"base64:5W2Jipw4e4kvyquY2sx7mfTw2omCzk0oLBs0F2Z7LF2nDI3wwF6ggbAYRVA5fPKtS0tHdsce9i7aZ73VcWGt2MzLHQTueQ6QYbacrwAoXR0SlKEbR5Tx",
951,
{
"field1":1735031111,
"Field2":9876541
},
[{
"field1":{
"field1_1": [44444444444444444, 55555555555555555555]
},
"field2": "StringValue2"
}]
]]]
}
}
Где:
uuid
— уникальный идентификатор запросаdata
— объект с данными ответаrecords
— возвращаемые записи. Представляет собой массив трех уровней вложенности:- 1-й уровень — каждый элемент соответствует одной входящей записи
- 2-ой уровень — каждый элемент соответствует одной исходящей записи. Набор элементов представляет собой ответ на входящую запись
- 3-й уровень — каждый элемент соответствует значению поля исходящей записи. Порядок и типы полей соответствуют описанию в
output_variables
Чтобы избежать ошибки в результате выполнения запроса, данные должны соответствовать формату output_variables
.
Ответ может поддерживать следующие типы данных:
- Long
- LongArray
- Double
- DoubleArray
- Boolean
- BooleanArray
- String
- StringArray
- BigInteger
- BigIntegerArray
- BigDecimal
- BigDecimalArray
- DateTime
- DateTimeArray
- Object
- ObjectArray
- FileContent
По умолчанию используются числовые типы максимального размера: BigInteger и BigDecimal. Если известно, что передаваемые значения не превышают допустимые границы для меньших типов, можно использовать типы Long и Double — это улучшит производительность.
ObjectArray и Object — сложные типы. Элемент метаданных должен содержать поле "struct"
, описывающее структуру объекта. ObjectArray — всегда массив объектов, поэтому для описания типа его элементов также достаточно поля "struct"
, описывающего структуру его элемента.
Закрытие сессии
Пример закрытия сессии:
{
"uuid":"731d5558-f474-4a27-94e0-4008b60ca48d",
"cmd":"close",
"data":{}
}
Где:
uuid
— уникальный идентификатор сессииcmd
— команда закрытия данныхdata
— пустой объект данных
Пример ответа:
{
"uuid":"731d5558-f474-4a27-94e0-4008b60ca48d"
}
Где uuid
— уникальный идентификатор запроса.
Логирование
{
"cmd": "log",
"data": {
"level": "INFO",
"text": "Received value var_1=123"
}
}
Где:
cmd
— команда закрытия сессииdata
— пустой объект данных
Идентификатор запроса не требуется — ответ не ожидается и не обрабатывается (по принципу fire-and-forget).
Список уровней логирования:
ERROR
WARN
INFO
DEBUG
TRACE
Обработка ошибок
В ответ на любой запрос можно вернуть ошибку.
{
"uuid":"f6a820f5-34c4-4c23-bb51-2bffa26d9898",
"cmd": "error",
"data": {
"code": "unknown_error",
"text": "Непредвиденная ошибка",
"params": [{
"name": "file",
"value": "vkK8Og2BNyPnJ15wp5Mc.tmp"
}]
}
}
Где:
uuid
— уникальный идентификатор запросаcmd
— команда ошибкиdata
— объект данныхcode
— код ошибкиtext
— текст сообщенияparams
— параметры ошибкиname
— имя параметраvalue
— значение параметра
Была ли статья полезна?