fix(bookings): добавлено явное ограничение генератора на jobs=1

- Зачем:
  - исключить нестабильные режимы генератора, в которых bookings может перестать пополняться.
  - сделать причину ошибки понятной студенту сразу при запуске команд и SQL-скриптов.
- Что:
  - добавлен precheck `bookings-check-jobs` в Makefile и подключён к `bookings-init` и `bookings-generate-day`.
  - добавлены явные проверки `bookings.jobs = 1` в `bookings/generate_next_day.sql` и `sql/src/bookings_generate_day_if_missing.sql`.
  - обновлена документация и `.env.example`: зафиксировано, что в стенде поддерживается только `BOOKINGS_JOBS=1`.
- Проверка:
  - uv run make fmt.
  - uv run make test.
  - env BOOKINGS_JOBS=2 make bookings-init.
  - env BOOKINGS_JOBS=2 make bookings-generate-day.
  - make bookings-init.
  - make bookings-generate-day.
This commit is contained in:
2026-02-28 22:00:27 +03:00
parent a10cbff906
commit ffd9585ef4
8 changed files with 28 additions and 6 deletions
+1 -1
View File
@@ -24,7 +24,7 @@ BOOKINGS_DB_PORT=5434
BOOKINGS_START_DATE=2017-01-01 BOOKINGS_START_DATE=2017-01-01
# Количество дней для первой генерации (держим малым, чтобы быстрее увидеть данные) # Количество дней для первой генерации (держим малым, чтобы быстрее увидеть данные)
BOOKINGS_INIT_DAYS=1 BOOKINGS_INIT_DAYS=1
# Количество параллельных джобов генератора (по умолчанию 1; при 1 работаем синхронно без dblink) # Количество джобов генератора. В учебном стенде поддерживается только значение 1.
BOOKINGS_JOBS=1 BOOKINGS_JOBS=1
# Greenplum Configuration # Greenplum Configuration
+9 -3
View File
@@ -8,7 +8,7 @@ BOOKINGS_START_DATE ?= 2017-01-01
BOOKINGS_INIT_DAYS ?= 1 BOOKINGS_INIT_DAYS ?= 1
.PHONY: up stop down clean airflow-init logs gp-psql ddl-gp \ .PHONY: up stop down clean airflow-init logs gp-psql ddl-gp \
bookings-clone-demodb bookings-init bookings-psql bookings-generate-day \ bookings-check-jobs bookings-clone-demodb bookings-init bookings-psql bookings-generate-day \
dev-setup dev-sync dev-lock test lint fmt clean-venv build dev-setup dev-sync dev-lock test lint fmt clean-venv build
SHELL := /bin/bash SHELL := /bin/bash
@@ -61,7 +61,13 @@ bookings-clone-demodb:
fi; \ fi; \
fi fi
bookings-init: bookings-clone-demodb bookings-check-jobs:
@if [ "$(BOOKINGS_JOBS)" != "1" ]; then \
echo "Поддерживается только BOOKINGS_JOBS=1. Измените .env и повторите команду." >&2; \
exit 1; \
fi
bookings-init: bookings-check-jobs bookings-clone-demodb
docker compose -f docker-compose.yml up -d bookings-db docker compose -f docker-compose.yml up -d bookings-db
docker compose -f docker-compose.yml exec bookings-db bash -lc '\ docker compose -f docker-compose.yml exec bookings-db bash -lc '\
until PGPASSWORD="$$POSTGRES_PASSWORD" pg_isready -U "$$POSTGRES_USER" -d "$$POSTGRES_DB" -h localhost; do \ until PGPASSWORD="$$POSTGRES_PASSWORD" pg_isready -U "$$POSTGRES_USER" -d "$$POSTGRES_DB" -h localhost; do \
@@ -88,7 +94,7 @@ bookings-init: bookings-clone-demodb
bookings-psql: bookings-psql:
docker compose -f docker-compose.yml exec bookings-db bash -lc 'PGPASSWORD="$$POSTGRES_PASSWORD" psql -U "$$POSTGRES_USER" -d demo' docker compose -f docker-compose.yml exec bookings-db bash -lc 'PGPASSWORD="$$POSTGRES_PASSWORD" psql -U "$$POSTGRES_USER" -d demo'
bookings-generate-day: bookings-generate-day: bookings-check-jobs
docker compose -f docker-compose.yml up -d bookings-db docker compose -f docker-compose.yml up -d bookings-db
docker compose -f docker-compose.yml exec bookings-db bash -lc '\ docker compose -f docker-compose.yml exec bookings-db bash -lc '\
until PGPASSWORD="$$POSTGRES_PASSWORD" pg_isready -U "$$POSTGRES_USER" -d "$$POSTGRES_DB" -h localhost; do \ until PGPASSWORD="$$POSTGRES_PASSWORD" pg_isready -U "$$POSTGRES_USER" -d "$$POSTGRES_DB" -h localhost; do \
+3
View File
@@ -65,6 +65,8 @@ make up
make bookings-init make bookings-init
``` ```
Важно: генератор `bookings` в этом стенде поддерживается только в режиме `BOOKINGS_JOBS=1`.
4) Подготовьте STG‑объекты в Greenplum (выберите один вариант): 4) Подготовьте STG‑объекты в Greenplum (выберите один вариант):
- Учебный вариант: в Airflow UI запустите DAG `bookings_stg_ddl`; - Учебный вариант: в Airflow UI запустите DAG `bookings_stg_ddl`;
@@ -141,6 +143,7 @@ make clean # полный reset: удалить контейнер
|----------|---------| |----------|---------|
| Airflow UI не открывается | Дождитесь сообщения `Listening at: http://0.0.0.0:8080` в логах (`make logs`) | | Airflow UI не открывается | Дождитесь сообщения `Listening at: http://0.0.0.0:8080` в логах (`make logs`) |
| `database "demo" does not exist` в bookingsDAG | Вы сделали reset с удалением volumes (`make clean` / `docker compose down -v`). Запустите `make bookings-init` и повторите DAG. | | `database "demo" does not exist` в bookingsDAG | Вы сделали reset с удалением volumes (`make clean` / `docker compose down -v`). Запустите `make bookings-init` и повторите DAG. |
| `Поддерживается только bookings.jobs=1` или `BOOKINGS_JOBS=1` | В этом учебном стенде поддерживается только синхронный режим генерации. Установите `BOOKINGS_JOBS=1` и выполните `make bookings-init`. |
| Ошибка подключения к Greenplum | Убедитесь, что контейнер `greenplum` имеет статус `healthy` (`docker compose ps`) | | Ошибка подключения к Greenplum | Убедитесь, что контейнер `greenplum` имеет статус `healthy` (`docker compose ps`) |
| `protocol "pxf" does not exist` | Перезапустите `greenplum` и повторите `bookings_stg_ddl`/`make ddl-gp` — расширение `pxf` создаётся автоматически при старте контейнера. | | `protocol "pxf" does not exist` | Перезапустите `greenplum` и повторите `bookings_stg_ddl`/`make ddl-gp` — расширение `pxf` создаётся автоматически при старте контейнера. |
| DAG `bookings_to_gp_stage` ругается на отсутствующие таблицы stg | Запустите `bookings_stg_ddl` (или выполните `make ddl-gp`), затем повторите запуск | | DAG `bookings_to_gp_stage` ругается на отсутствующие таблицы stg | Запустите `bookings_stg_ddl` (или выполните `make ddl-gp`), затем повторите запуск |
+2 -1
View File
@@ -18,6 +18,7 @@
- `engine.sql`: два изменения в `engine_jobs1_sync.patch`: - `engine.sql`: два изменения в `engine_jobs1_sync.patch`:
- `busy()` игнорирует свой `pid`, чтобы не считать собственное подключение занятым; - `busy()` игнорирует свой `pid`, чтобы не считать собственное подключение занятым;
- `continue()` при `jobs=1` вызывает `process_queue` синхронно (без `dblink`), иначе генерация обрывается при выходе из `psql` и данных не появляется. - `continue()` при `jobs=1` вызывает `process_queue` синхронно (без `dblink`), иначе генерация обрывается при выходе из `psql` и данных не появляется.
- Режим эксплуатации в этом стенде: только `jobs=1` (`BOOKINGS_JOBS=1`).
- Патчи применяются автоматически в `make bookings-init`. Если что-то пошло не так, их можно накатить вручную: - Патчи применяются автоматически в `make bookings-init`. Если что-то пошло не так, их можно накатить вручную:
``` ```
patch -d bookings/demodb -p1 --forward < bookings/patches/install_drop_if_exists.patch patch -d bookings/demodb -p1 --forward < bookings/patches/install_drop_if_exists.patch
@@ -36,6 +37,6 @@
SELECT date_trunc('day', max(book_date)) + interval '1 day' SELECT date_trunc('day', max(book_date)) + interval '1 day'
INTO v_next_day INTO v_next_day
FROM bookings.bookings; FROM bookings.bookings;
CALL continue(v_next_day); -- или CALL continue(v_next_day, 4) CALL continue(v_next_day, 1);
END $$; END $$;
``` ```
+5
View File
@@ -14,6 +14,11 @@ BEGIN
RAISE EXCEPTION 'Таблица bookings.bookings не найдена. Сначала выполните make bookings-init.'; RAISE EXCEPTION 'Таблица bookings.bookings не найдена. Сначала выполните make bookings-init.';
END IF; END IF;
-- В учебном стенде поддерживается только jobs=1, иначе генерация нестабильна.
IF v_jobs <> 1 THEN
RAISE EXCEPTION 'Поддерживается только bookings.jobs=1. Текущее значение: %. Установите BOOKINGS_JOBS=1 и выполните make bookings-init.', v_jobs;
END IF;
-- Ищем последнюю сгенерированную дату -- Ищем последнюю сгенерированную дату
SELECT max(book_date) INTO v_max_book_date FROM bookings.bookings; SELECT max(book_date) INTO v_max_book_date FROM bookings.bookings;
+2
View File
@@ -25,6 +25,8 @@ make up
make bookings-init make bookings-init
``` ```
Важно: генератор `bookings` в этом стенде поддерживается только в режиме `BOOKINGS_JOBS=1`.
3) В Greenplum созданы `stg.bookings_ext` и `stg.bookings` (выберите один вариант): 3) В Greenplum созданы `stg.bookings_ext` и `stg.bookings` (выберите один вариант):
- учебный вариант: запустить DAG `bookings_stg_ddl` в Airflow UI; - учебный вариант: запустить DAG `bookings_stg_ddl` в Airflow UI;
+1 -1
View File
@@ -132,7 +132,7 @@ make fmt
- `BOOKINGS_DB_PORT` — внешний порт (по умолчанию `5434`) - `BOOKINGS_DB_PORT` — внешний порт (по умолчанию `5434`)
- `BOOKINGS_START_DATE` — стартовая дата модельного времени - `BOOKINGS_START_DATE` — стартовая дата модельного времени
- `BOOKINGS_INIT_DAYS` — сколько дней генерировать при первом `make bookings-init` - `BOOKINGS_INIT_DAYS` — сколько дней генерировать при первом `make bookings-init`
- `BOOKINGS_JOBS` — число джобов генератора (по умолчанию `1`) - `BOOKINGS_JOBS` — число джобов генератора; в учебном стенде поддерживается только `1`
### CSV pipeline (побочный пример) ### CSV pipeline (побочный пример)
@@ -17,6 +17,11 @@ BEGIN
RAISE EXCEPTION 'Таблица bookings.bookings не найдена. Сначала выполните make bookings-init.'; RAISE EXCEPTION 'Таблица bookings.bookings не найдена. Сначала выполните make bookings-init.';
END IF; END IF;
-- В учебном стенде поддерживается только jobs=1, иначе генерация нестабильна.
IF v_jobs <> 1 THEN
RAISE EXCEPTION 'Поддерживается только bookings.jobs=1. Текущее значение: %. Установите BOOKINGS_JOBS=1 и выполните make bookings-init.', v_jobs;
END IF;
-- Ищем последнюю сгенерированную дату -- Ищем последнюю сгенерированную дату
SELECT max(book_date) INTO v_max_book_date FROM bookings.bookings; SELECT max(book_date) INTO v_max_book_date FROM bookings.bookings;