# Многопроцессный Beanstalkd Статус: постановка на реализацию, код не реализован. Дата фиксации: 2026-10-15. База: исходники Beanstalkd 1.13 в этом каталоге. ## Цель Позволить одному логическому серверу использовать несколько CPU-ядер для обработки независимых tubes, сохранив модель заданий Beanstalkd и динамический жизненный цикл очередей. Принятое решение: процессы-владельцы групп tubes. У каждого владельца собственный event loop, задания, очереди, таймеры и WAL; сетевые frontend-процессы направляют операции владельцам через IPC. Supervisor обеспечивает эксклюзивность owner slots и управление жизненным циклом процессов. ```text +-- owner slot 0: tubes, jobs, WAL clients --> frontend(s) --IPC--+-- owner slot 1: tubes, jobs, WAL +-- owner slot N: tubes, jobs, WAL supervisor: topology, process generations, startup, shutdown, restart ``` ## Границы Первого Этапа - Один хост, статическая карта распределения, отдельный WAL каждого владельца. - Каждый `reserve` / `reserve-with-timeout` работает с одной наблюдаемой tube. Настройка `watch target`, `ignore default` допускается. - Связь tube с владельцем определяется по имени через фиксированные логические разделы. Постоянного каталога дескрипторов всех tubes нет. - Consumer может держать несколько заданий. Его `use`, текущий watch list и ранее полученные резервации не обязаны относиться к одной tube или одному владельцу. - Политика перехода от существующего однопроцессного сервера определяется в эпике 01. Рекомендуется opt-in с сохранением legacy, но обязательная поддержка двух режимов пока не утверждена. - Полный end-to-end путь команд, восстановление, диагностика и проверки отказов входят в результат, а не откладываются после демонстрации `put`/`reserve`. ## Вне Объёма - Межшардовый выбор задания из нескольких наблюдаемых tubes. - Распараллеливание одной tube, глобальный FIFO между tubes. - Динамическая миграция, автоматическая балансировка и изменение карты при работе сервера. - Кластер между хостами, репликация и автоматическое назначение данных упавшего владельца другому slot. - Shared-memory allocator, zero-copy и io_uring как предварительное условие реализации. - Exactly-once выполнение пользовательского кода. ## Основные Инварианты 1. Имя tube всегда имеет одного владельца в пределах версии топологии, даже когда объект tube не существует. 2. Объект создаётся только владельцем и только по операции, которая предполагает создание по протоколу. 3. Два процесса не изменяют данные одного owner slot одновременно. 4. Переходы состояний job последовательны у владельца; права на reserved job принадлежат логической клиентской сессии. 5. Один reserve имеет не более одного результата; job имеет не более одной действующей резервации. 6. Очерёдность команд и ответов одного TCP-соединения сохраняется. 7. Сбой, недоступность и неизвестный результат не маскируются под успешную операцию или отсутствие задания. 8. Накопление IPC-запросов, ответов и тел ограничено памятью; медленный клиент не блокирует чужие очереди неограниченно. 9. Перезапуск с WAL использует ту же топологию и корректное пространство ID; несовпадение конфигурации обнаруживается до записи данных. ## Эпики И Зависимости | ID | Постановка | Зависимости | Результат | | --- | --- | --- | --- | | 01 | [Контракты и baseline](01-contract.md) | Нет | Решения по внешнему поведению, отказам, ID и конфигурации | | 02 | [Владение tubes](02-ownership.md) | 01 | Детерминированная маршрутизация и локальное создание | | 03 | [IPC и сессии](03-ipc-sessions.md) | 01; интерфейсы 02 | Межпроцессный транспорт и безопасный жизненный цикл сессий | | 04 | [Queue engine и протокол](04-queue-engine.md) | 02, 03 | Все операции над очередями через владельцев | | 05 | [WAL и ID](05-persistence.md) | 01, 02; интеграция 03, 04 | Восстановление, уникальные ID, изоляция журналов | | 06 | [Supervisor и эксплуатация](06-supervisor.md) | 02, 03; интеграция 04, 05 | Управляемый запуск, отказ и остановка процессов | | 07 | [Приёмка и производительность](07-validation.md) | Baseline после 01; итог после 02-06 | Воспроизводимые функциональные и нагрузочные доказательства | Порядок не запрещает совместную разработку согласованных интерфейсов. Минимальный запуск дочернего процесса для тестов можно сделать раньше эпика 06; это не означает готовность supervisor. Тесты пишутся в каждом эпике, а не только в конце. ## Общая Приёмка - Все обязательные решения эпика 01 закрыты и документированы до реализации зависящего от них контракта. - Исходные тесты используются как регрессионная база; отклонения допустимы только по согласованной матрице совместимости. Если выбран отдельный legacy-режим, он проходит прежний набор без ограничения multi-watch. - Успешно проверены минимум два owner slots и несколько frontend-процессов, в том числе гонка создания одной tube через разные frontend. - Протестированы job lifecycle, права сессий, таймеры, slow clients, аварии и WAL при одинаковых с baseline настройках durability. - На независимых tubes подтверждён рост пропускной способности и реальная работа нескольких owner CPU; точный порог фиксируется после baseline, до финальных замеров. - Для одной горячей tube ограничение последовательности явно показано в отчёте, а не скрыто агрегированной нагрузкой. - Обновлены `README.md`, `doc/protocol.txt`, исходник руководства и эксплуатационные инструкции при реализации. Внешние ограничения и совместимость старых данных описаны явно. ## Основание Текущий сервер последовательно выполняет `prottick`, `socknext` и callback в `serv.c:srvserve`. Реестры jobs/tubes и генератор ID глобальны. `process_queue` связывает job с `Conn*`, а WAL защищён от второго владельца. Поэтому разделение только listening socket или вызов `fork()` не дают корректного общего сервера. Критический краткий контекст для последующей работы: [../AGENTS.md](../AGENTS.md).