Перейти к основному содержимому

Данные проекта

Нода Данные проекта читает, сохраняет и удаляет записи, занимает ключи, обрабатывает списки и запрашивает данные проекта. Что такое хранилище, коллекции и срок хранения -- в разделе Данные.

Назначение​

  • Хранить состояние между запусками: статусы, настройки, курсоры выгрузки.
  • Кэшировать ответы внешних API.
  • Читать и сохранять списки записей.
  • Выбирать записи по условиям и отсекать повторную обработку событий с помощью «Занять ключ».

Операции​

ОперацияЧто делает
«Прочитать»Читает запись по ключу; если её нет, ветка «Ошибка».
«Сохранить»Сохраняет или заменяет запись по ключу.
«Занять ключ»Проверяет и занимает ключ одним действием, сохраняя значение.
«Удалить»Удаляет запись по ключу.
«Список записей»Возвращает страницу записей, ключей или количество.
«Запрос»Возвращает результат выборки по условиям.
«Прочитать несколько»Читает записи по списку ключей.
«Сохранить несколько»Сохраняет список элементов как записи.
«Занять несколько ключей»Занимает ключи из списка и отделяет новые от уже занятых.

Первые четыре операции работают с одной записью; остальные обрабатывают список или страницу и не используются внутри ForEach.

Общие поля​

Коллекция​

Обязательное имя набора записей: буквы (в том числе кириллица), цифры, _ и -, без пробелов, не более 255 символов. Допускается переменная, например {{input.tenant}}_orders; после подстановки действуют те же правила.

Ключ​

Ключ обязателен для операций с одной записью. Он может содержать не более 512 символов; пробелы в начале и конце отбрасываются, регистр учитывается. Каждая переменная должна разрешаться в текст или число, иначе нода перейдёт в ветку «Ошибка». Для объекта или списка используйте поле-идентификатор ({{input.order.id}}) или фильтр | string.

Значение​

Используется в операциях сохранения и занятия ключа.

СодержимоеЧто сохраняется
Одна переменная, например {{node_2.data}}Значение без преобразования: объект, список, число и строка остаются своими типами.
JSON, например {"status":"new","attempts":0}Значение JSON. В JSON-шаблоне текстовые переменные заключайте в кавычки, а объекты, списки, числа, true/false и null подставляйте как JSON.
Обычный текстСтрока; если результат подстановки является корректным JSON, он сохраняется как значение JSON.
Пустое полеПустая строка.

Если поле состоит из переменной с отсутствующим значением или null, нода перейдёт в ветку «Ошибка». Отсутствующая переменная также приводит к ошибке внутри текста; null внутри текста подставляется как None, а в JSON -- как null. Чтобы число, записанное в переменную-строку, осталось строкой, используйте только переменную ({{input.phone}}), а не текст с ней.

Размер значения ограничен -- см. Ограничения.

Срок хранения, дней​

Поле операций, сохраняющих данные. Допустимо целое число от 1 до 365 дней, по умолчанию -- 180. Срок отсчитывается от последнего сохранения: сохранение продлевает его, чтение -- нет. Истёкшая запись сразу недоступна для чтения, а её ключ можно занять снова.

Прочитать​

Читает запись по коллекции и ключу. Поля: «Коллекция», «Ключ».

Основные поля результата:

{
"found": true,
"value": { "status": "paid" },
"claimedBy": "exec_a3B9kLm2:node_2",
"createdAt": "2026-09-28T10:15:04.512000+00:00",
"expiresAt": "2027-03-27T10:15:04.512000+00:00"
}

Если записи нет или срок истёк, нода переходит в ветку «Ошибка» с errorType: "NotFound" и found: false. Отличайте это от других ошибок по errorType.

Сохранить​

Сохраняет значение по ключу и заменяет прежнюю запись целиком. Поля: «Коллекция», «Ключ», «Значение», «Срок хранения, дней».

Результат (основные поля):

{"key":"order-1042","value":{"status":"paid"},"claimedBy":"exec_a3B9kLm2:node_5"}

«Сохранить» также становится владельцем ключа (claimedBy); последующая попытка «Занять ключ» другим владельцем вернёт claimed = false.

Занять ключ​

«Занять ключ» атомарно проверяет наличие записи и, если ключ свободен или запись истекла, создаёт запись с указанным значением. Проверка и создание происходят как одно действие: при одновременном занятии ключа только один вызов получит claimed = true.

Поля: «Коллекция», «Ключ», «Значение», «Срок хранения, дней».

СитуацияРезультат
Записи нет или её срок истёкclaimed = true; сохраняются заданное значение и срок.
Ключ занят другим запуском того же или другого процесса, другой нодой в том же запуске, другой итерацией ForEach или агентомclaimed = false; существующая запись не меняется и возвращается в результате.
Та же нода повторно выполняется в том же запускеclaimed = true; значение и срок перезаписываются.

Запись, созданная «Сохранить», «Сохранить несколько» или инструментом агента, тоже занимает ключ. При claimed = false результат содержит существующие value, claimedBy, createdAt и expiresAt; claimedBy для процесса имеет вид ID запуска:ID ноды, для агента -- ID его запуска. Срок хранения этой записи не продлевается.

{"claimed":false,"value":{"status":"processing"},"claimedBy":"exec_Zq81xYt0:node_2","createdAt":"2026-09-28T09:58:40Z","expiresAt":"2027-03-27T09:58:40Z"}

Оба значения claimed ведут в выход «Успех». После ноды проверяйте node_2.claimed == true в If/Else и обрабатывайте событие только при true.

Выбирайте стабильный идентификатор события во внешней системе, а не время, случайное значение или ID запуска. Если идентификаторы из разных источников могут совпасть, добавьте префикс источника; для разных действий над одним событием используйте разные коллекции или префиксы (invoice-…, sms-…). Срок хранения выбирайте больше периода, в течение которого отправитель может повторить событие. Ключи сравниваются точно; переменная ключа не должна быть пустой или null, иначе нода перейдёт в ветку «Ошибка», а не займёт общий ключ None.

Пример обработки вебхука:

Если обработка завершается ошибкой после занятия, ключ остаётся занят. Освобождайте его «Удалить» только если внешнее действие ещё не произошло; ошибку процесса можно обработать через обработчик ошибок. Рекомендуемый вариант -- сохранить при занятии {"status":"processing"}, а после обработки заменить на {"status":"done"}; в ветке claimed = false проверяйте node_2.value.status.

При TimeoutError или DatastoreUnavailable ключ мог успеть заняться, поэтому в ветке «Ошибка» событие не обрабатывайте. При очень плотной одновременной доставке также возможен DatastoreConflict.

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

Удалить​

Удаляет запись по ключу. Поля: «Коллекция», «Ключ». Операция завершается через «Успех», даже если записи нет:

{"deleted":false}

Если запись существовала, deleted: true; если записи не было или срок истёк, deleted: false. После удаления ключ можно занять снова.

Список записей​

Читает страницу коллекции, упорядоченную по ключам как по строкам: например, order-10 идёт раньше order-9. Для числового порядка дополняйте номера нулями.

Поля​

ПолеЗначение
«Начало ключа»Необязательный префикс ключей.
«Что вернуть»«Записи», «Только ключи» или «Только количество».
«Записей на странице»От 1 до 1000, по умолчанию 100.
«Курсор страницы»Пустой курсор начинает чтение с первой страницы; для следующей передайте nextCursor.
«Если страница не поместилась»Ошибка или возврат записей, которые поместились.

В «Начале ключа» и «Курсоре страницы» допускаются переменные. Если префикс состоит только из переменной без значения или равной null, читается вся коллекция; пустая переменная внутри текста приводит к «Ошибке».

Основные поля результата: items содержит записи или ключи, returned -- число элементов на странице, nextCursor -- курсор следующей страницы или null. В режиме «Только количество» возвращается count; complete: false означает, что число приблизительное.

Передавайте nextCursor в следующий вызов и продолжайте, пока он не станет null. Пустая или null переменная-курсор начинает чтение с первой страницы, поэтому проверяйте nextCursor != null; курсор от другой коллекции даёт InvalidCursor. Записи, добавленные во время обхода, попадут в выдачу, если их ключ больше последнего прочитанного.

Результат ограничен примерно 1 000 000 символов; записи никогда не обрезаются. Поле «Если страница не поместилась» задаёт, что делать при превышении: перейти в ветку «Ошибка» с ResultTooLarge (записи страницы не возвращаются -- уменьшите «Записей на странице» и прочитайте ту же страницу заново) или вернуть поместившиеся записи с complete: false и nextCursor.

Запрос​

«Запрос» проверяет наличие, считает, выбирает записи по условиям или подводит итоги по группам. Конструктор и типы условий описаны в разделе Запросы к коллекции.

В значениях условий можно использовать переменные; также переменные допускаются в «Начале ключа», «Курсоре страницы» и «Записей на странице». Если переменная в префиксе или курсоре отсутствует, пуста или равна null, нода переходит в ветку «Ошибка» (в отличие от «Списка записей»). Если коллекция задана переменной, конструктор показывает поля всех коллекций проекта; отсутствие заданного поля в выбранной коллекции приводит к ошибке. Запрос должен завершиться за 5 секунд (QueryTimeout); запрос, которому пришлось бы прочитать слишком много записей, не выполняется (ScanTooLarge).

РежимПоля результата
«Проверка наличия»exists
«Количество»count
«Ключи»keys, nextCursor
«Записи»items, nextCursor
«Итоги по группам»groups с key, count и metrics (fn, field, value)

Ключи в результате запроса находятся в keys, а не в items.

Прочитать несколько​

Читает до 500 ключей за вызов. Поля: «Коллекция», «Ключи».

В «Ключах» можно задать переменную со списком строк или чисел, JSON-массив либо указать по одному ключу в строке. Список ключей из «Списка записей» в режиме «Только ключи» находится в items. Повторы читаются один раз; пустой элемент, null, объект или более 500 ключей приводят к «Ошибке».

Результат содержит items с найденными записями, found с их количеством и missing с отсутствующими или истёкшими ключами. Отсутствующие записи не переводят операцию в ветку «Ошибка»; если весь ответ не помещается, возвращается ResultTooLarge.

Сохранить несколько​

Сохраняет до 1000 элементов за вызов. Поля: «Коллекция», «Элементы», «Шаблон ключа», «Шаблон значения», «Срок хранения, дней», «Продолжать при ошибках».

«Элементы» задаются переменной со списком или JSON-массивом; пустой список допустим. В шаблоне ключа _item -- текущий элемент, _index -- его номер с нуля. Если «Шаблон значения» пуст, сохраняется сам элемент; иначе шаблон понимается по тем же правилам, что поле «Значение».

Все элементы проверяются до записи. Если ключи повторяются, весь вызов завершается с InvalidKey и ничего не сохраняется. При выключенном «Продолжать при ошибках» вызов останавливается на первой ошибке с BulkWriteFailed, но записи, сохранённые до неё, остаются сохранёнными. При включённом параметре операция завершается через «Успех»: written -- сохранённые записи, failed и failures -- неудачи, complete -- сохранены ли все записи.

Занять несколько ключей​

Занимает ключ для каждого элемента списка по тем же правилам, что и «Занять ключ». Поля: «Коллекция», «Элементы», «Шаблон ключа», «Шаблон значения», «Срок хранения, дней», «Продолжать при ошибках».

Результат содержит claimed -- ключи, занятые этим вызовом, и duplicates -- уже занятые ключи с claimedBy и createdAt. Если в списке есть повторяющиеся ключи, весь вызов завершается с InvalidKey, и ни один ключ не занимается. При выключенном «Продолжать при ошибках» вызов останавливается на первой ошибке с BulkClaimFailed; ключи, занятые до неё, остаются занятыми и перечислены в claimed. При включённом параметре операция продолжается и возвращает «Успех» с claimed, duplicates, failed и failures.

Например, после получения массива HTTP-событий можно занять их ключи одной операцией, а затем передать claimed в ForEach для обработки новых событий.

Ошибки​

Для ветвления используйте errorType, а не текст error.

errorTypeЗначение
NotFoundЗапись отсутствует или истекла (операция «Прочитать»).
UnresolvedVariableПеременная не найдена, пуста или равна null.
InvalidKeyНедопустимы коллекция, ключ (в том числе пустой после подстановки), шаблон или элементы ключей; повтор ключа в пакетной операции.
ConfigurationError, InvalidTtlНе заполнены обязательные поля, неверна настройка операции или срок хранения.
ValueTooLarge, TooManyItems, QuotaExceededПревышен лимит значения, списка или хранилища проекта; см. Ограничения.
ResultTooLarge, PageTooLargeРезультат или страница не помещается в ответ.
InvalidCursorКурсор повреждён или относится к другой коллекции.
BulkWriteFailed, BulkClaimFailedПакетная операция остановилась на ошибке при выключенном «Продолжать при ошибках».
TimeoutErrorОперация не завершилась за отведённое время.
DatastoreUnavailable, DatastoreConflict, DatastoreErrorОшибка или конфликт хранилища.
DatastoreReadOnly, DatastoreDisabledСохранение для проекта отключено или хранилище не подключено в этой установке.
QueryTimeout, ScanTooLarge, UnknownField, InvalidFilterОшибка выполнения или настройки «Запроса».
подсказка

Подключайте выход «Ошибка»: иначе при ошибке процесс остановится на этой ноде. Автоматические повторы для ноды по умолчанию отключены -- что делать при ошибке, решает эта ветка.

Как использовать результат​

Результат доступен по ID ноды, например node_2:

ВыражениеЗначение
{{node_2.value}}, {{node_2.value.status}}Значение записи и его поля.
{{node_2.claimed}}Результат «Занять ключ» или список занятых ключей в «Занять несколько ключей».
{{node_2.items}}Записи или ключи страницы («Список записей», «Запрос» в режиме «Записи») или найденные записи «Прочитать несколько».
{{node_2.missing}}Ненайденные ключи «Прочитать несколько».
{{node_2.nextCursor}}Курсор следующей страницы.
{{node_2.errorType}}Тип ошибки в ветке «Ошибка».

В условиях If/Else фигурные скобки не нужны, например node_2.claimed == true.

Внутри ForEach​

В ForEach доступны только операции с одной записью: «Прочитать», «Сохранить», «Занять ключ» и «Удалить». Ключ «Сохранить» и «Занять ключ» должен зависеть от элемента -- ссылаться на {{_loop_item...}} или {{_loop_index}}, например order-{{_loop_item.id}}, иначе все элементы попадут в одну запись. Каждая итерация -- отдельный владелец ключа: если два элемента дают один ключ, claimed = true получит только одна из итераций. Ошибка отдельной итерации даёт null в results и сведения об ошибке в errors.

Подключения​

  • Вход: один вход.
  • Выход «Успех»: операция выполнена. Сюда же относятся claimed = false, deleted = false и ненайденные ключи в «Прочитать несколько» -- это не ошибки.
  • Выход «Ошибка»: операция завершилась с ошибкой.

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

Кэш ответа API на сутки​

Прочитать: коллекция weather_cache, ключ {{input.city}}
Успех → использовать node_2.value
Ошибка → HTTP-запрос → Сохранить ответ с тем же ключом, срок 1 день

Выгрузка коллекции страницами​

В первый запуск курсора нет: «Прочитать» уходит в ветку «Ошибка», курсор без значения -- и читается первая страница.

Сохранение массива из API​

Сохранить несколько: элементы {{node_2.data.items}}
Шаблон ключа: sku-{{_item.sku}}
Шаблон значения: пусто (сохранить элемент целиком)