Files
install b9bcb01322
Continous integration / Tests (push) Canceled after 0s
Testing clients / Build beanstalkd (push) Canceled after 0s
Continous integration / Docker build (push) Canceled after 0s
Testing clients / Test Pheanstalk PHP (push) Canceled after 0s
Testing clients / Test Greenstalk Python (3.9) (push) Canceled after 0s
Testing clients / Test Pystalk Python (3.10) (push) Canceled after 0s
Initialize
2026-10-15 10:52:58 +05:00

64 lines
10 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Критический Контекст
## Статус И Источники
- Здесь находится исходный Beanstalkd 1.13 на C99. Многопроцессная архитектура ниже принята как направление доработки, но ещё не реализована.
- Постановка: [epics/00-overview.md](epics/00-overview.md). Открытые решения перечислены в [epics/01-contract.md](epics/01-contract.md); не считать их уже утверждёнными.
- Исходные контракты: `README.md`, `doc/protocol.txt`, `doc/beanstalkd.ronn`, `doc/beanstalkd.1`. Каталог называется `doc`, не `docs`.
- `doc/beanstalkd.1` и HTML генерируются из `doc/beanstalkd.ronn`. При изменении CLI обновлять исходник руководства и производные документы штатным способом.
- Сохранять приоритеты проекта: стабильность, исправление ошибок, ясность, затем производительность; см. `CONTRIBUTING.md`.
## Принятое Решение
- Архитектура: процессы-владельцы групп tubes на одном хосте, frontend для TCP/протокола, IPC между frontend и владельцами, supervisor для управления процессами.
- Каждая tube имеет одного владельца; один владелец обслуживает несколько tubes. Все изменения её заданий и планирование выполняются последовательно в event loop владельца.
- У каждого owner slot отдельные состояние в памяти и WAL. Owner slot является стабильным логическим идентификатором, а не PID.
- На первом этапе consumers не резервируют задания одновременно из нескольких наблюдаемых tubes. Допускается временный watch list из нескольких tubes при настройке, например `watch target`, `ignore default`. На момент `reserve` / `reserve-with-timeout` наблюдаемая tube должна быть одна.
- Реакция на неподдерживаемый multi-watch reserve требует явного протокольного решения. Нельзя молча выбрать одну tube или выдать выдуманный стандартный ответ.
- Одна наблюдаемая tube не означает один job, одну резервацию или одного владельца на всё время TCP-сессии. Переключение watch list и `reserve-job` могут оставить у сессии резервации разных владельцев. Не вводить дополнительные ограничения без согласования.
- Одна горячая tube остаётся последовательной. Масштабируется совокупность независимых tubes, а не выполнение пользовательских задач внешними consumers.
## Владение Динамическими Tubes
- Постоянный дескриптор каждой tube не нужен. Объект появляется при `use`, `watch`, инициализации `default` или восстановлении заданий и удаляется после исчезновения удерживающих ссылок.
- Задание в любом живом состоянии, включая reserved, удерживает tube. Ссылки от удалённых сессий должны учитываться у владельца; авария frontend должна их освобождать.
- Владение определяется до создания объекта: `partition = stable_hash(tube_name) % PARTITION_COUNT`, затем `owner_slot = partition_map[partition]`.
- Алгоритм hash, параметры, число разделов и карта одинаковы у всех процессов и стабильны между перезапусками с данными. Их точный формат задаётся в эпиках 01 и 02.
- Конкурентный claim отдельной tube не нужен: все обращения с одним именем попадают одному владельцу; он локально выполняет find-or-create.
- Маршрутизация сама по себе ничего не создаёт. Например, `stats-tube` и `pause-tube` неизвестного имени должны сохранить `NOT_FOUND`.
- Жизненный цикл объекта tube не меняет принадлежность имени. Повторное создание использует того же владельца.
- Одновременно активен не более одного процесса на owner slot. При падении перезапускается тот же slot; нельзя направлять его имена к другому живому владельцу как обычный failover.
- Карта распределения фиксирована на первом этапе. `hash(name) % live_process_count`, автоматический rebalance и переназначение при сбое запрещены. Миграция требует отдельной процедуры.
## Инварианты Реализации
- Не передавать `Job*`, `Tube*`, `Conn*`, `File*` через IPC. Использовать сериализуемые ID, поколения процессов/сессий и явное владение данными.
- Сохранять последовательность команд и ответов на TCP-соединении, текущие проверки владения резервацией, priority/FIFO внутри tube, delay, TTR, timeout, `DEADLINE_SOON` и освобождение резерваций при disconnect.
- У задания не может быть двух действующих резерваций; один запрос reserve даёт не более одного результата. Повторное выполнение внешним consumer после TTR допустимо: exactly-once не обещается.
- ID должны быть уникальны в логическом сервере, маршрутизируемы и безопасны при частичном перезапуске. `job_pri_less()` использует ID для FIFO; новый формат ID не должен нарушать порядок внутри tube.
- IPC обязан иметь framing, лимиты памяти, backpressure, отмену ожиданий и защиту от устаревших сообщений. Не повторять автоматически `put` или другую мутацию с неизвестным результатом.
- Смерть владельца, frontend и supervisor является частью контракта, а не только эксплуатационной деталью. Недоступность владельца не равна `NOT_FOUND`.
- Не делить существующий WAL между независимыми writers и не снимать блокировку каталога ради многопроцессности. Изменение `Jobrec` требует следовать правилам `Walver` в `dat.h`.
- Не обещать более сильную durability, чем реализует выбранный режим `-b`, `-f`, `-F`. Успешный IPC-ответ сам по себе не означает fsync.
- Политика сохранения отдельного legacy-режима, включения новой архитектуры и переноса старого WAL согласуется в эпике 01 до изменения запуска и форматов. Не считать поддержку двух режимов уже утверждённым объёмом и не ломать существующее поведение/данные без явного решения.
## Карта Кода
| Область | Файлы и точки |
| --- | --- |
| Запуск и event loop | `main.c`, `serv.c:srvserve`, платформенные `linux.c`, `darwin.c`, `freebsd.c`, `sunos.c` |
| Протокол, scheduler, timers | `prot.c:dispatch_cmd`, `process_queue`, `prottick`, `conn_timeout` |
| Сессии и резервации | `conn.c:conn_reserve_job`, `connclose`, `dat.h:Conn` |
| ID и jobs | `job.c:next_id`, `all_jobs`, `job_pri_less`; `dat.h:Job`, `Jobrec` |
| Динамические tubes | `tube.c:tube_find_or_make`, `tube_iref`, `tube_dref` |
| WAL и восстановление | `walg.c`, `file.c`, `serv.c:srv_acquire_wal`, `prot.c:prot_replay` |
| Тесты | `testserv.c`, `testjobs.c`, `testheap.c`, `testms.c`, `testutil.c`, `ct/` |
## Проверки
- Сборка: `make`; регрессии: `make check`; существующие микробенчмарки: `make bench`.
- Команды требуют поддерживаемого Unix-окружения и toolchain. Нативный Windows не заявлен как поддерживаемая платформа; наличие WSL/контейнеров проверять, а не предполагать.
- `make bench` не заменяет end-to-end нагрузочный тест многопроцессного сервера.
- Для каждой реализации проверять один и несколько owner slots, ошибки IPC, disconnect, TTR, аварии и восстановление WAL. Критерии: `epics/07-validation.md`.
- Не выдавать статический анализ за измеренный выигрыш и не отмечать эпики завершёнными без проверок.