Написание функций

Узел Function позволяет выполнять код JavaScript для сообщений, которые проходят через него.

Сообщение передается узлу как объект с именем msg.

Написание функции#

Код в узле Function представляет собой тело функции. Самая простая функция, возвращающая полученное сообщение как есть:

return msg;

Если функция возвращает null, тогда сообщение не передается следующим узлам, и поток завершается.

Функция всегда должна возвращать объект msg. Возврат числа или строки приведет к ошибке.

Возвращаемый объект сообщения не обязательно должен быть тем же объектом, что был получен узлом; функция может создать совершенно новый объект перед его возвращением. Например:

const newMsg = { payload: msg.payload.length };
return newMsg;
Примечание

Создание нового объекта сообщения приведет к потере свойств полученного сообщения. В некоторых случаях это нарушит выполнение потока. Например, поток, состоящий из узлов HTTP In и HTTP Response требует, чтобы свойства msg.req и msg.res были переданы от одного узла - другому. Как правило, узлы Function должны вносить необходимые изменения в переданный им объект сообщения и возвращать его.

Несколько выходов#

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

Это позволяет писать функции, отправляющие сообщения на разные выходы в зависимости от каких-то условий. Например, эта функция будет отправлять все сообщения, у которых значение points больше 100 на второй выход, а все остальные - на первый:

if (msg.points > 100) {
return [null, msg];
} else {
return [msg, null];
}

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

const newMsg = { id: msg.user.id };
return [msg, newMsg];

Несколько сообщений#

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

В следующем примере msg1, msg2, msg3 будут отправлены на первый выход, а msg4 будет отправлен на второй выход.

const msg1 = { payload: "первое для выхода 1" };
const msg2 = { payload: "второе для выхода 1" };
const msg3 = { payload: "третье для выхода 1" };
const msg4 = { payload: "единственное сообщение для выхода 2" };
return [[msg1, msg2, msg3], msg4];

В следующем примере текст из свойства msg.text разбивается на отдельные слова, и для каждого слова возвращается сообщение, в котором свойству msg.word присвоено это слово.

const outputMsgs = [];
const words = msg.text.split(" ");
for (const word of words) {
outputMsgs.push({ word });
}
return [outputMsgs];

Асинхронная отправка сообщений#

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

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

Например:

doSomeAsyncProcess(msg, (result) => {
msg.payload = result;
node.send(msg); // отправка сообщения
node.done(); // завершение обработки
});
return;

Узел Function клонирует каждый объект сообщения, который вы передаете в node.send, чтобы гарантировать отсутствие непреднамеренной модификации объектов сообщения, которые продолжают использоваться внутри функции.

Функция может запросить среду выполнения не клонировать первое сообщение переданное в node.send, установив false в качестве второго аргумента функции. Это полезно, если сообщение содержит что-то, что не может быть клонировано, или из соображений производительности, чтобы минимизировать накладные расходы на отправку сообщений:

node.send(msg, false);

Завершение обработки сообщения#

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

Чтобы помочь ей в этом, узел Function должен вызывать node.done() после завершения обработки сообщения. Это позволит среде выполнения правильно отслеживать сообщения в системе.

Выполнение кода на старте#

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

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

if (context.get("counter") === undefined) {
context.set("counter", 0);
}

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

Чистка#

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

Либо добавлением обработчика события close:

node.on("close", () => {
// здесь делается очистка асинхронных процессов - закрытие подключений и тому подобное
});

Или вы можете добавить код на вкладке Закрытие в окне редактирования узла.

Ведение журнала событий#

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

node.log("Что-то произошло");
node.warn("Произошло что-то, о чем вы должны знать");
node.error("О нет, произошло что-то плохое");

Сообщения, отправляемые функциями warn и error, также отправляются на боковую панель отладки.

Для более подробных сведений в журнале событий, есть также node.trace() и node.debug().

Обработка ошибок#

Если функция обнаруживает ошибку, которая должна прервать текущий поток, она ничего не должна возвращать. Чтобы запустить узел Catch на той же вкладке, функция должна вызвать node.error с исходным сообщением в качестве второго аргумента:

node.error("произошла ошибка", msg);

Хранение данных#

Помимо msg объекта, функция также может хранить данные в хранилище контекста.

Более подробную информацию о контексте в Ботодроме можно найти на странице «работа с контекстом».

В узле Function есть три предопределенные переменные, которые могут использоваться для доступа к контексту:

  • context - локальный контекст узла
  • flow - контекст с потоковой областью видимости
  • global - контекст с глобальной областью видимости

В следующих примерах используется flow контекст, но они также применимы к context и global.

Чтобы получить значение из контекста:

let myCount = flow.get("count");

Чтобы установить значение:

flow.set("count", 123);

В следующем примере ведется подсчет количества запусков функции:

// взять значение счетчика или 0, если значения нет
let count = context.get("count") || 0;
count += 1;
// записать значение обратно в контекст
context.set("count", count);
// поместить его в возвращаемое сообщение
msg.count = count;
return msg;

Получение / установка нескольких значений#

Также можно получить или установить несколько значений одним обращением:

const values = flow.get(["count", "color", "points"]);
// values[0] для значения 'count'
// values[1] для значения 'color'
// values[2] для значения 'points'
flow.set(["count", "color", "points"], [12, "blue", 150]);

В этом случае любые отсутствующие значения будут устанавлены в null.

Несколько хранилищ контекста#

По умолчанию функции контекста get/set используют хранилище file. Последним аргументом функции можно указать другое хранилище для получения/установки значения, например, memory:

// Получить значение
var myCount = flow.get("count", "memory");
// Установить значение
flow.set("count", 123, "memory");

Добавление статуса#

Узел Function может показывать свое состояние (статус) так же, как и другие узлы. Чтобы установить статус, вызовите функцию node.status. Например:

node.status({ fill: "red", shape: "ring", text: "отключен" });
node.status({ fill: "green", shape: "dot", text: "подключен" });
node.status({ text: "Простой текст в статусе" });
node.status({}); // чтобы очистить статус

Любые изменения статуса можно будет затем также перехватывать узлом Status.

Параметры объекта статуса#

У объекта статуса могут быть три свойства: fill, shape и text.

Первые два определяют внешний вид значка состояния, а третий - необязательный короткий текст (менее 20 символов), отображаемый рядом со значком.

Свойство shape (форма) может быть: ring (кольцо) или dot (точка).

Свойство fill (заливка) может быть: red (красный), green (зеленый), yellow (желтый), blue (синий) или grey (серый).

Если объект статуса - пустой объект {}, тогда статус узла будет удален.

Справочник API#

В узле Function доступны следующие объекты.

node#

context#

  • context.get(..) - получить значение свойства локального контекста узла
  • context.set(..) - установить значение для свойства локального контекста узла
  • context.keys() - получить список всех свойств локального контекста узла
  • context.flow - то же самое, что и flow
  • context.global - то же самое, что и global

flow#

  • flow.get(..) - получить свойство контекста с потоковой областью видимости
  • flow.set(..) - установить свойство контекста с потоковой областью видимости
  • flow.keys() - получить список всех свойств контекста с потоковой областью видимости

global#

  • global.get(..) - получить свойство контекста с глобальной областью видимости
  • global.set(..) - установить свойство контекста с глобальной областью видимости
  • global.keys() - получить список всех свойств контекста с глобальной областью видимости

env#

  • env.get(..) - получить значение переменной среды

Другие модули и функции#

В узле Function также доступны следующие модули и функции:

  • Buffer - Node.js-модуль Buffer
  • console- Node.js-модуль console (node.log более предпочтительный метод для ведения журнала)
  • util - Node.js-модуль util
  • setTimeout/clearTimeout - функции тайм-аута javascript.
  • setInterval/clearInterval - функции интервального таймера javascript.
Примечание

Узел Function автоматически очищает все незавершенные тайм-ауты (setTimeout) или интервальные таймеры (setInterval) при остановке или повторном развертывании.

Также в узле Function есть опциональный Node.js-модуль crypto, который можно подключить при необходимости с помощью функции require в глобальном контексте: global.get("require")(..). Пример кода для подключения модуля crypto:

const crypto = global.get("require")("crypto");
// теперь можно обращаться к модулю crypto