fix(superset): стабилизирована проверка рабочего контура #176

Merged
ddmitry merged 1 commits from 172-superset-cold-check into main 2026-08-28 12:41:27 +03:00
2 changed files with 78 additions and 28 deletions

No files matched your search

+27 -5
View File
@@ -34,17 +34,18 @@
спрашивают его отдельно.
Стенд нужен трём целям из восьми. Цена — замер, см. «Что проверено».
`make config-test`, `make smoke` и `make check-services` перемерены 21 августа
2026 года, `make check-clickhouse` — 19 августа, корневой `make lint` —
9 августа, `make test` — 7 августа; остальные стоят с замера 6 августа.
`make smoke` и `make check-services` перемерены 28 августа 2026 года,
`make config-test` — 21 августа, `make check-clickhouse` — 19 августа,
корневой `make lint` — 9 августа, `make test` — 7 августа; остальные стоят с
замера 6 августа.
| Цель | Откуда | Что утверждает | Стенд | Цена |
|---|---|---|---|---|
| `make config-test` | корень | Compose разбирается, файлы DAG и дашборды Grafana синтаксически целы, в diff нет пробельных ошибок. О работоспособности не говорит ничего | не нужен | 1 с |
| `make lint` | корень | Код стенда — `dags/` и `infra/superset/` — отформатирован и проходит ruff | не нужен | 0,4 с |
| `make smoke` | корень | Стенд **собран**: службы живы, порты отвечают, подключения настроены друг на друга. Вширь и по касательной к каждой службе. Единственная цель, которая здесь правда смоук | нужен | 17 с |
| `make smoke` | корень | Стенд **собран**: службы живы, порты отвечают, подключения настроены друг на друга. Вширь и по касательной к каждой службе. Единственная цель, которая здесь правда смоук | нужен | 25 с |
| `make check-clickhouse` | корень | Всё, что спрашивают **у ClickHouse** и он отвечает сам: макросы, шарды, реплики, путь в keeper, ключ шардирования, очередь распределённых DDL, ответ словаря товаров, счёт событий стартового мира против описи | нужен | 24 с |
| `make check-services` | корень | **Службы работают**: DAG запускается и доходит, топик создаётся и удаляется, Superset логинится и ходит в базу | нужен | 93 с |
| `make check-services` | корень | **Службы работают**: DAG запускается и доходит, топик создаётся и удаляется, Superset логинится и ходит в базу | нужен | 71 с |
| `make lint` | `generator/` | Код генератора отформатирован и проходит ruff | не нужен | 0,4 с |
| `make typecheck` | `generator/` | Типы генератора сходятся (ty) | не нужен | 0,5 с |
| `make test` | `generator/` | Генератор делает то, что обещает; схема события остаётся объявленным контрактом, а собранные из кода [описание выгрузки](../formats/clickstream-event.md) и [опись мира](../../data/world-inventory.json) — свежими | не нужен | 71 с |
@@ -237,6 +238,27 @@ Kafka → STG → ODS, и живёт он в `make check-clickhouse`.
## Что проверено
**Приемка #172 28 августа 2026 года.** Холодный `create_app()` занимал
28,3-28,4 секунды, а чтение подключения после запуска - 0,07 секунды. Предел
30 секунд почти целиком уходил на запуск второго приложения. Увеличивать его
не стали: Superset не обещает постоянного времени `create_app()`.
После входа проверка делает три GET-запроса к уже работающему Superset: находит
`ClickHouse`, сверяет UUID и безопасный URI, затем требует схему `dm`. Так без
второго запуска проверяются сохраненное подключение и хранилище пароля. Форму
API сверили через Context7 и с исходным кодом Superset 6.1.0. `superset test-db`
отклонен, потому что тоже запускает приложение; прямой SQL к `dbs` не проверяет
соединение.
Проверка больше не подтверждает, что сам Superset использует Postgres для
метаданных. Короткий запрос к Postgres показывает лишь готовность базы, а REST
API - подключение к ClickHouse. Для `check-services` этого достаточно.
После перезапуска Superset три прогона прошли 7/7 за 71, 67 и 70 секунд.
`make config-test` прошел. `make smoke` дал 21/21 за 25 секунд; его код не
менялся, прежний замер был 17 секунд. Неверный UUID дал 5/1: красной стала
только проверка метаданных, пароль в вывод не попал.
**Приемка #156 27 августа 2026 года.** `make rebuild-storage` занял 7 минут.
На чистом прикладном мире `world_initialize` сам довел позицию до `8`, дождался
`etl_pipeline` и оставил заполненными DDS и обе витрины. После пересборки прошли
+51 -23
View File
@@ -237,35 +237,42 @@ check_airflow_probes() {
}
check_superset() {
local clickhouse_password
local access_token
local available_schemas
local clickhouse_databases
local config
local connection_count
local connection_details
local connection_id
local database_list
local login
local metadata_tables
local password
local port
local metadata_engine
local stored_config
local stored_uri
local schemas
local stored_safe_uri
local stored_uuid
local superset_password
local superset_user
local superset_url
local user
config="$(compose config --format json 2>/dev/null || true)"
user="$(jq -r '.services.superset.environment.SUPERSET_ADMIN_USER // empty' <<<"$config")"
password="$(jq -r '.services.superset.environment.SUPERSET_ADMIN_PASSWORD // empty' <<<"$config")"
clickhouse_password="$(jq -r '.services.superset.environment.CLICKHOUSE_BI_PASSWORD // empty' <<<"$config")"
superset_user="$(jq -r '.services["postgres-metadata"].environment.SUPERSET_METADATA_USER // empty' <<<"$config")"
superset_password="$(jq -r '.services["postgres-metadata"].environment.SUPERSET_METADATA_PASSWORD // empty' <<<"$config")"
port="$(published_port superset 8088)"
superset_url="http://127.0.0.1:${port}"
login="$(curl -sf --max-time 10 -X POST \
-H 'Content-Type: application/json' \
-d "$(jq -cn --arg username "$user" --arg password "$password" \
'{username: $username, password: $password, provider: "db", refresh: true}')" \
"http://127.0.0.1:${port}/api/v1/security/login" 2>/dev/null || true)"
if curl -sf --max-time 10 "http://127.0.0.1:${port}/health" >/dev/null 2>&1 && \
jq -e '.access_token | length > 0' >/dev/null 2>&1 <<<"$login"; then
"${superset_url}/api/v1/security/login" 2>/dev/null || true)"
access_token="$(jq -r '.access_token // empty' <<<"$login")"
if curl -sf --max-time 10 "${superset_url}/health" >/dev/null 2>&1 && \
[[ -n "$access_token" ]]; then
pass 'интерфейс Superset отвечает и принимает подготовленные учётные данные администратора'
else
fail 'интерфейс Superset не отвечает или не принимает учётные данные администратора'
@@ -276,28 +283,49 @@ check_superset() {
psql -U "$superset_user" -d superset -tAc \
"SELECT count(*) FROM information_schema.tables WHERE table_schema = 'public' AND table_name = 'ab_user';" \
2>/dev/null || true)"
stored_config="$(timeout 30s "${COMPOSE_CMD[@]}" --project-directory "$ROOT_DIR" \
exec -T superset python -c \
"from superset.app import create_app; app = create_app(); app.app_context().push(); from superset.extensions import db; from superset.models.core import Database; url = db.engine.url; database = db.session.query(Database).filter_by(database_name='ClickHouse').one(); print('SMOKE_METADATA=' + '|'.join([url.get_backend_name(), url.username or '', url.host or '', str(url.port or ''), url.database or ''])); print('SMOKE_UUID=' + str(database.uuid)); print('SMOKE_URI=' + database.sqlalchemy_uri_decrypted)" \
2>/dev/null)"
metadata_engine="$(sed -n 's/^SMOKE_METADATA=//p' <<<"$stored_config" | tail -n 1)"
stored_uuid="$(sed -n 's/^SMOKE_UUID=//p' <<<"$stored_config" | tail -n 1)"
stored_uri="$(sed -n 's/^SMOKE_URI=//p' <<<"$stored_config" | tail -n 1)"
# Superset уже собрал приложение. Его REST API читает ту же сохранённую
# модель Database без второго тяжёлого запуска Python.
database_list="$(curl -sf --max-time 10 \
-H "Authorization: Bearer ${access_token}" \
"${superset_url}/api/v1/database/" 2>/dev/null || true)"
clickhouse_databases="$(jq -c \
'[.result[]? | select(.database_name == "ClickHouse")]' \
<<<"$database_list")"
connection_count="$(jq -r 'length' <<<"$clickhouse_databases")"
connection_id="$(jq -r 'if length == 1 then .[0].id else empty end' \
<<<"$clickhouse_databases")"
stored_uuid="$(jq -r 'if length == 1 then .[0].uuid else empty end' \
<<<"$clickhouse_databases")"
connection_details=''
if [[ -n "$connection_id" ]]; then
connection_details="$(curl -sf --max-time 10 \
-H "Authorization: Bearer ${access_token}" \
"${superset_url}/api/v1/database/${connection_id}/connection" \
2>/dev/null || true)"
fi
stored_safe_uri="$(jq -r '.result.sqlalchemy_uri // empty' \
<<<"$connection_details")"
if [[ "$metadata_tables" == '1' ]] && \
[[ "$metadata_engine" == "postgresql|${superset_user}|postgres-metadata|5432|superset" ]] && \
[[ "$stored_uuid" == '4b8f2c6e-1d3a-4f5b-9c7d-2e8a1f0b3c5d' ]] && \
[[ "$stored_uri" == "clickhousedb://bi:${clickhouse_password}@clickhouse-02:8123/default" ]]; then
pass 'метаданные Superset живут в Postgres, подготовленное подключение указывает на clickhouse-02'
[[ "$stored_safe_uri" == 'clickhousedb://bi@clickhouse-02:8123/default' ]]; then
pass 'Postgres для метаданных Superset подготовлен, подключение указывает на clickhouse-02'
else
fail "Superset не подтвердил Postgres и подготовленное подключение bi к ноде 2: таблицы=${metadata_tables:-нет}, движок=${metadata_engine:-нет}, UUID=${stored_uuid:-нет}"
fail "Postgres или подключение Superset не подготовлены: таблицы=${metadata_tables:-нет}, подключений=${connection_count:-нет}, UUID=${stored_uuid:-нет}, URI=${stored_safe_uri:-нет}"
return
fi
if printf 'n\n' | timeout 60s "${COMPOSE_CMD[@]}" --project-directory "$ROOT_DIR" \
exec -T superset superset test-db "$stored_uri" >/dev/null 2>&1; then
pass 'Superset успешно проверил извлечённое из метаданных подключение ClickHouse'
schemas="$(curl -sf --max-time 10 \
-H "Authorization: Bearer ${access_token}" \
"${superset_url}/api/v1/database/${connection_id}/schemas/" \
2>/dev/null || true)"
available_schemas="$(jq -r '[.result[]?] | join(", ")' <<<"$schemas")"
if jq -e '.result | index("dm") != null' >/dev/null 2>&1 <<<"$schemas"; then
pass 'сохранённое подключение Superset видит схему витрин dm'
else
fail 'Superset не смог проверить извлечённое из метаданных подключение ClickHouse'
fail "сохранённое подключение Superset не видит схему витрин dm: схемы=${available_schemas:-нет}"
fi
}