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

Управление процессами

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

Глобальная переменная process всегда доступна — она не требует require() и не должна быть указана в modules:.

Получить текущий frame ID или process ID:

local frame_id = process.id() -- Идентификатор цепочки вызовов
local pid = process.pid() -- ID процесса

Отправить сообщение(я) процессу по PID или зарегистрированному имени:

local ok, err = process.send(destination, topic, ...)
ПараметрТипОписание
destinationstringPID или зарегистрированное имя
topicstringИмя топика (не может начинаться с @)
...anyЗначения payload

Разрешение: process.send на целевой PID

-- Базовый spawn
local pid, err = process.spawn(id, host, ...)
-- С мониторингом (получать события EXIT)
local pid, err = process.spawn_monitored(id, host, ...)
-- Со связыванием (получать LINK_DOWN при аварийном завершении)
local pid, err = process.spawn_linked(id, host, ...)
-- И связанный, и мониторящий
local pid, err = process.spawn_linked_monitored(id, host, ...)
ПараметрТипОписание
idstringID источника процесса (например, "app.workers:handler")
hoststringID хоста (например, "app:processes")
...anyАргументы, передаваемые процессу

Разрешения:

  • process.spawn на id процесса
  • process.host на id хоста
  • process.spawn.monitored на id процесса (для вариантов с мониторингом)
  • process.spawn.linked на id процесса (для связанных вариантов)
-- Принудительно завершить процесс
local ok, err = process.terminate(destination)
-- Запросить корректную отмену с опциональной причиной
local ok, err = process.cancel(destination, "shutting down")
ПараметрТипОписание
destinationstringPID или зарегистрированное имя
reasonstringОпциональная причина, доставляемая цели

Разрешения: process.terminate, process.cancel на целевой PID

Мониторинг или связывание с существующим процессом:

-- Мониторинг: получать события EXIT при завершении цели
local ok, err = process.monitor(destination)
local ok, err = process.unmonitor(destination)
-- Связывание: двунаправленное, получать LINK_DOWN при аварийном завершении
local ok, err = process.link(destination)
local ok, err = process.unlink(destination)

Разрешения: process.monitor, process.unmonitor, process.link, process.unlink на целевой PID

local options = process.get_options()
local ok, err = process.set_options({trap_links = true})
ПолеТипОписание
trap_linksbooleanДоставлять ли события LINK_DOWN в канал events

Получить каналы для приёма сообщений и событий жизненного цикла:

local inbox = process.inbox() -- Объекты Message из топика @inbox
local events = process.events() -- События жизненного цикла из топика @events
КонстантаОписание
process.event.CANCELЗапрошена отмена
process.event.EXITМониторящий процесс завершился
process.event.LINK_DOWNСвязанный процесс завершился аварийно
ПолеТипОписание
kindstringКонстанта типа события
fromstringИсходный PID
resultanyДля EXIT: возвращённое значение (присутствует при нормальном завершении)
erroranyДля EXIT: ошибка (присутствует при аварийном завершении)
reasonstringДля CANCEL: причина отмены процесса

Подписка на пользовательские топики:

local ch = process.listen(topic, options)
process.unlisten(ch)
ПараметрТипОписание
topicstringИмя топика (не может начинаться с @)
options.messagebooleanЕсли true, получать объекты Message; если false, сырые payload

При получении из inbox или с {message = true}:

local msg = inbox:receive()
msg:topic() -- string: имя топика
msg:from() -- string|nil: PID отправителя
msg:payload() -- Payload: обёртка (вызовите :data() для извлечения)
msg:payload():data() -- any: фактическое значение payload

Создать процесс, дождаться результата и вернуть:

local result, err = process.exec(id, host, ...)

Разрешения: process.exec на id процесса, process.host на id хоста

Обновить текущий процесс на новое определение с сохранением PID:

-- Обновить на новую версию, передать состояние
process.upgrade(id, ...)
-- Оставить то же определение, перезапустить с новым состоянием
process.upgrade(nil, preserved_state)

Создать spawner с пользовательским контекстом для дочерних процессов:

local spawner = process.with_context({request_id = "123"})

Разрешение: process.context на “context”

process.with_options(options) создаёт spawner, который несёт опции времени spawn (например, селектор сети) вместо значений контекста:

local spawner = process.with_options({network = "app:tor_proxy"})
ОпцияТипОписание
networkstringRegistry ID записи network.*, используемой для исходящих соединений дочернего процесса

Разрешение: process.context на “context”; выбор сети дополнительно требует network.select на этом ID сети.

SpawnBuilder иммутабелен — каждый метод возвращает новый экземпляр:

spawner:with_context(values) -- Добавить значения контекста
spawner:with_actor(actor) -- Установить актора безопасности
spawner:with_scope(scope) -- Установить область безопасности
spawner:with_name(name) -- Установить имя процесса
spawner:with_message(topic, ...) -- Поставить в очередь сообщение для отправки после spawn
spawner:with_options(options) -- Объединить опции времени spawn (например, network)

Разрешение: process.security на “security” для :with_actor() и :with_scope()

spawner:spawn(id, host, ...)
spawner:spawn_monitored(id, host, ...)
spawner:spawn_linked(id, host, ...)
spawner:spawn_linked_monitored(id, host, ...)

Те же разрешения, что и у функций spawn на уровне модуля.

Регистрация процесса под именем и достижение его по имени вместо raw PID. Любая функция, принимающая destination (send, terminate, cancel, monitor, link, …), принимает зарегистрированное имя вместо PID.

local ok, err = process.registry.register(name) -- self, local scope
local pid, err = process.registry.lookup(name)
local ok, err = process.registry.unregister(name)

Опциональный аргумент scope выбирает гарантию согласованности имени. По умолчанию LOCAL. Четыре области и их гарантии описаны в Руководстве по кластеру; кратко:

КонстантаВидимостьГарантия
process.registry.LOCALтолько эта нодаМгновенно, локально
process.registry.EVENTUALкластерEventually consistent (gossip)
process.registry.CONSISTENTкластерЛинеаризуемый синглтон (Raft)
process.registry.STRONGкластерConsistent плюс подтверждение каждой живой нодой

На автономной ноде значим только LOCAL; кластерные области требуют кластеризации.

local ok, err = process.registry.register(name, pid, scope)
ПараметрТипОбязательноПо умолчаниюОписание
namestringдаИмя для регистрации
pidstringнетselfPID для регистрации; по умолчанию вызывающий процесс
scopenumberнетLOCALОдна из констант области выше

Возвращает true при успехе, или nil, error при ошибке. Конфликты (имя уже зарегистрировано на другой PID в кластерной области) возвращают errors.ALREADY_EXISTS. Регистрация того же имени на тот же PID идемпотентна. Регистрация STRONG блокируется до подтверждения каждой живой нодой или истечения дедлайна; при таймауте возвращает ошибку.

Регистрация от имени другого PID дополнительно требует разрешения process.registry.foreign на целевой PID.

local pid, err = process.registry.lookup(name)

Возвращает строку зарегистрированного PID или nil, error с kind errors.NOT_FOUND, если имя не зарегистрировано.

local ok, err = process.registry.unregister(name, scope)

scope по умолчанию LOCAL и должен совпадать с областью, под которой имя было зарегистрировано. Для CONSISTENT и STRONG снятие регистрации разрешено только владеющему процессу; попытка снять регистрацию имени другого PID возвращает false. Имена также освобождаются автоматически при выходе владеющего процесса (и, для кластерных областей, при уходе его ноды), поэтому явное unregister нужно только для досрочного освобождения.

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

Политики могут разрешать/запрещать на основе:

  • Actor: Принципал безопасности, делающий запрос
  • Action: Выполняемая операция (например, process.send)
  • Resource: Цель (PID, id процесса, id хоста или имя)
  • Attributes: Дополнительный контекст, включая pid (ID процесса вызывающего)
РазрешениеФункцииРесурс
process.spawnspawn*()id процесса
process.spawn.monitoredspawn_monitored(), spawn_linked_monitored()id процесса
process.spawn.linkedspawn_linked(), spawn_linked_monitored()id процесса
process.hostspawn*(), exec()id хоста
process.sendsend()целевой PID
process.execexec()id процесса
process.terminateterminate()целевой PID
process.cancelcancel()целевой PID
process.monitormonitor()целевой PID
process.unmonitorunmonitor()целевой PID
process.linklink()целевой PID
process.unlinkunlink()целевой PID
process.contextwith_context()”context”
process.security:with_actor(), :with_scope()”security”
process.registry.registerregistry.register()имя
process.registry.unregisterregistry.unregister()имя
process.registry.foreignregistry.register()целевой PID

Кластерные области имён авторизуются суффиксными вариантами этих действий (process.registry.register.eventual, .consistent, .strong и соответствующими unregister), поэтому политика может разрешать локальное именование отдельно от кластерного.

Некоторые операции требуют нескольких разрешений:

ОперацияТребуемые разрешения
spawn()process.spawn + process.host
spawn_monitored()process.spawn + process.spawn.monitored + process.host
spawn_linked()process.spawn + process.spawn.linked + process.host
spawn_linked_monitored()process.spawn + process.spawn.monitored + process.spawn.linked + process.host
exec()process.exec + process.host
spawn с пользовательским actor/scopeразрешения spawn + process.security
УсловиеKind
Контекст не найденerrors.INVALID
Контекст фрейма не найденerrors.INVALID
Отсутствуют обязательные аргументыerrors.INVALID
Зарезервированный префикс топика (@)errors.INVALID
Неверный формат длительностиerrors.INVALID
Имя не зарегистрированоerrors.NOT_FOUND
Разрешение отклоненоerrors.PERMISSION_DENIED
Имя уже зарегистрированоerrors.ALREADY_EXISTS

См. Обработка ошибок для работы с ошибками.