fix(ptica): job_settings не отравляет чужую сессию при сбое БД (#2464 кластер A) #2937
No reviewers
Labels
No labels
Fable 5 ревью
GG-форсайт
admin
analytics
auth
automation
bug
business
chore
ci
compliance
data
data-moat
docs
duplicate
dx
enhancement
feedback/max
generative
needs-discussion
needs-human
observability
pause-bots
performance
priority/p0
priority/p1
priority/p2
priority/p3
scope/backend
scope/db
scope/devops
scope/frontend
scope/qa
scrapers
security
site-finder
stage/1
stage/2
status/blocked
status/done
status/needs-analysis
status/needs-fix
status/qa
status/ready
status/review
status/wip
tech-debt
tradein
ux
week ревью 1
wontfix
ИРД
вторичка
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference: lekss361/gendesign#2937
Loading…
Add table
Reference in a new issue
No description provided.
Delete branch "fix/2464a-job-settings-savepoint"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Дефект
get_all/get_oneглотают ошибкуdb.executeи возвращают fallback — поведение задумано как graceful. Но сессию им отдаёт вызывающий: admin-ручки (admin_jobs.py),beat_schedule.py:71, иget_setting_valueизcadastre_fetch.py/nspd_geo.py.На Postgres упавший запрос оставляет транзакцию в aborted-состоянии. Все последующие запросы этой же сессии падают с
current transaction is aborted, commands ignored until end of transaction block— то есть падает не тот, кто виноват, а следующий блок кода.Голый
db.rollback()здесь запрещён: он снёс бы незакоммиченную работу вызывающего. Средство — SAVEPOINT вокруг самогоexecute, ровно как в уже закрытом пункте того же кластера (developer_attribution.py:152, где это записано в комментарии).Мок воспроизводит Postgres — и это не педантизм
Тест моделирует настоящую семантику: упавший запрос переводит сессию в
aborted, дальнейшие падают, откат SAVEPOINT восстанавливает.Пришлось так, потому что существующий образец в репозитории проверки не даёт. В
tests/test_saturation.pyмокbegin_nested— пустой контекст-менеджер, aborted-состояния у него нет, поэтому второйexecuteпроходит независимо от того, есть SAVEPOINT в коде или нет.Проверил экспериментом, а не рассуждением: временно снял
with db.begin_nested():изsaturation.py:247—Все тесты файла зелёные при снятой защите. Тест, который не может покраснеть, когда убираешь то, что он охраняет, охраны не проверяет.
Поэтому здесь добавлен ещё и контроль на сам мок —
test_mock_actually_poisons_without_a_savepoint. Без него две главные проверки были бы зелёными по построению.Проверка
origin/maintest_get_all_leaves_the_caller_session_usableAbortedTransactionError: current transaction is aborted, commands ignored until end of transaction blocktest_get_one_leaves_the_caller_session_usabletest_mock_actually_poisons_without_a_savepointtest_healthy_session_is_not_disturbedПоследний контроль важен отдельно: он требует, чтобы при исправной БД возвращались данные из неё, а не fallback — иначе «починка» могла бы свестись к тому, что fallback отдаётся всегда.
pytest tests/services: 3063 passed, 14 skipped, rc=0pytest tests/api/v1/test_admin_jobs_settings.py tests/test_saturation.py: 21 passed, rc=0Побочно: беззубые тесты кластера A
Находка про
test_saturation.pyкасается не только его. Пять пунктов кластера A отмечены закрытыми, и если их проверяли моками того же устройства, отметки говорят о наличии кода, а не о работе защиты. Это стоит перепроверить тем же приёмом — снять SAVEPOINT и посмотреть, покраснеет ли тест. Отдельной задачей заводить не стал, напишу в эпик.Refs #2464