Ресурсы компаньона: краткий дизайн
Ресурс компаньона — это тяжёлый объект, которым управляет Flow, но который живёт в
процессе-компаньоне и доступен пользовательским process function. Например, это может быть
распакованный словарь, модель или пул соединений. Ресурс общий для всего процесса-компаньона,
а не для отдельного джоба, поэтому он не должен хранить изменяемое состояние джоба и обязан
поддерживать параллельное использование.
Компоненты
- Контроллер ресурса определяет желаемую ревизию и публикует её в Flow.
TCompanionResourceна воркере является прокси: готовит ревизию, управляет жизненным циклом
и отправляет команды в компаньон.TResourceStoreв C++-компаньоне хранит ресурсы поresource_id. Хранилище принадлежит
процессу и переживает создание и удаление джобов.- Process function получает только ресурсы, перечисленные в
required_resource_ids, с учётом
алиасов и транзитивных зависимостей.
Доставка и ссылки
Воркер вызывает RPC ResourceExecute(resource_id, command, argument). Команда задаётся enum и
имеет два значения: init и unload. Результат содержит отдельный статус команды ресурса и
структурированную ошибку TError.
Основной путь использует идемпотентный init. В аргумент входят статическая и динамическая
спеки, подготовленная ревизия, идентификатор и поколение инкарнации, поколение конфигурации и
точные ссылки на зависимости. Зависимости инициализируются раньше зависимого ресурса. В TJobInfo
передаются те же точные ссылки: resource_id, incarnation_id,
configuration_generation и необязательный алиас. Перед запуском пользовательского кода
компаньон проверяет каждую ссылку и выдаёт process function ссылки только на совпавшие
экземпляры.
Реконфигурация и восстановление
- Новая целевая ревизия сначала асинхронно готовится на воркере через
PrepareResourceRevision; неуспешный результат не публикуется в компаньон. - Успешная подготовка увеличивает поколение конфигурации и запускает сходящийся
init. - Компаньон публикует новое поколение только после того, как ресурс применил целевую ревизию:
Reconfigureпо контракту может лишь передать цель асинхронному переключению. Пока
GetRevisionStateсообщает отстающую применённую ревизию,initвозвращает временный
resource_not_initialized, а повторы сходятся без пересоздания экземпляра. - Монотонное поколение инкарнации не позволяет запоздалой команде оживить старый экземпляр или
удалить новый. - Воркер периодически повторяет
init, а каждый компьютейшен доставляет требуемые ресурсы по
своему каналу. Это восстанавливает состояние после перезапуска процесса-компаньона. - Если
ProcessBatchвозвращаетRESOURCE_NOT_INITIALIZED, воркер повторно инициализирует граф
ресурсов, обновляет ссылки и сведения о джобе и повторяет запрос с ограниченным числом попыток. unloadвыполняется по возможности. Уже работающие джобы удерживают ссылки на старый объект,
но новые джобы его больше не получают.
Полная серверная реализация сейчас есть у C++-компаньона. Java, Go и Python пока возвращают из
ResourceExecute статус Unsupported.