fix(tradein/scrapers): не путать rows_inserted/processed с честным результатным ключом
All checks were successful
CI / changes (pull_request) Successful in 9s
CI Trade-In / browser-tests (pull_request) Has been skipped
CI Trade-In / changes (pull_request) Successful in 9s
CI Trade-In / frontend-checks (pull_request) Has been skipped
CI / backend-tests (pull_request) Has been skipped
CI / frontend-tests (pull_request) Has been skipped
CI / openapi-codegen-check (pull_request) Has been skipped
CI Trade-In / backend-tests (pull_request) Successful in 5m4s
All checks were successful
CI / changes (pull_request) Successful in 9s
CI Trade-In / browser-tests (pull_request) Has been skipped
CI Trade-In / changes (pull_request) Successful in 9s
CI Trade-In / frontend-checks (pull_request) Has been skipped
CI / backend-tests (pull_request) Has been skipped
CI / frontend-tests (pull_request) Has been skipped
CI / openapi-codegen-check (pull_request) Has been skipped
CI Trade-In / backend-tests (pull_request) Successful in 5m4s
Ревью честного run-status нашло, что _RESULT_COUNTER_KEYS ловил не только целевой yandex_newbuilding_sweep, но и rosreestr_dkp_import (rows_inserted, 66 из 67 прод- прогонов = здоровый ноль догнавшего инкрементального импорта) и newbuilding_enrich (processed — счётчик попыток, ==limit даже при частичном провале). Первое завело бы практически непрерываемый ложный zero-стрик у здорового источника, второе маскировало бы реальные отказы под measured-N. Проверено по прод-БД (2026-08-15): "succeeded" пишут ТОЛЬКО yandex_newbuilding_sweep (42 прогона/90д) и newbuilding_enrich (65/90д) — ни разу rosreestr_dkp_import; у yandex_newbuilding_sweep succeeded численно совпадает с rows_inserted на всех 42/42 прогонах. Заменил "rows_inserted"+"processed" на "succeeded" в _RESULT_COUNTER_KEYS (app-копия и byte-эквивалентная kit-копия) — цель (b) исходной правки сохранена, ложный стрик у rosreestr_dkp_import снят, попутно newbuilding_enrich получает честное измерение вместо счётчика попыток. Также поправлены докстринги test_backfill_honest_status.py — два кейса (76%/72% отказов -> 'done') проверяют только выбор финализатора mark_backfill_finished (mark_done там замокан); реальный mark_done с honest-run-status переквалифицирует их в 'failed' через _failed_ratio_too_high — это не документировалось явно.
This commit is contained in:
parent
885031420e
commit
e9ca744e85
4 changed files with 155 additions and 48 deletions
|
|
@ -143,18 +143,28 @@ def _pick_int(counters: Mapping[str, Any], *keys: str) -> int | None:
|
|||
# unique_fetched — full-load'ы avito/cian/yandex (4 источника, 133 прогона) — раньше
|
||||
# сторож их не видел, хотя у cian_full_load 6 из 38 успешных прогонов
|
||||
# реально дали ноль.
|
||||
# rows_inserted — yandex_newbuilding_sweep (единственный писатель ключа с таким
|
||||
# именем на верхнем уровне counters): проверено на проде 26.07-10.08 —
|
||||
# десять прогонов подряд, все 'done', processed=5 succeeded=0
|
||||
# rows_inserted=0 failed_resolve=4-5. Ни total_seen/lots_fetched/
|
||||
# unique_fetched у него нет, поэтому раньше _run_result_count всегда
|
||||
# возвращал None ("не измерено") и стрик у сторожа не копился никогда
|
||||
# (honest-run-status).
|
||||
# processed — тот же sweep: сколько домов взял в работу. НАМЕРЕННО стоит ПОСЛЕ
|
||||
# rows_inserted в кортеже — processed это счётчик ПОПЫТОК (аналог
|
||||
# attempted), а не результата: у него ненулевое значение (=limit) даже
|
||||
# когда rows_inserted=0, и если бы он читался первым, «5 обработано,
|
||||
# 0 записано» замаскировалось бы под measured-5, а не measured-0.
|
||||
# succeeded — yandex_newbuilding_sweep (42 прогона/90д) и newbuilding_enrich
|
||||
# (65 прогонов/90д, единственные два писателя ключа на проде,
|
||||
# проверено 2026-08-15). НЕ 'rows_inserted': тот ключ пишет ЕЩЁ и
|
||||
# rosreestr_dkp_import (67 прогонов/90д) — у него rows_inserted=0 в
|
||||
# 66 из 67 это ЗДОРОВЫЙ ответ догнавшего инкрементального импорта
|
||||
# (rows_fetched=rows_skipped=96974, last_id не двигается неделями),
|
||||
# а не отказ; если бы 'rows_inserted' попал в этот список, сторож
|
||||
# зачитывал бы этот здоровый ноль как измеренный провал и копил бы
|
||||
# практически непрерываемый стрик (rosreestr_dkp_import не
|
||||
# прерывается другим статусом — импорт либо 'done', либо не бежал).
|
||||
# НЕ 'processed' по той же причине с другой стороны: это счётчик
|
||||
# ПОПЫТОК (у newbuilding_enrich processed==attempted==limit даже
|
||||
# когда succeeded меньше — прод-факт 09.08: processed=25 succeeded=14,
|
||||
# 44% отказов замаскировались бы под measured-25) — сторож нулевого
|
||||
# результата на нём молчал бы ровно там, где должен сработать, а на
|
||||
# будущем опустении очереди домов (cian_houses_pending) создал бы
|
||||
# свой вечный ложный zero-стрик. 'succeeded' у yandex_newbuilding_sweep
|
||||
# численно совпадает с 'rows_inserted' на всех 42/42 прод-прогонах —
|
||||
# замена не теряет исходную цель (десять прогонов подряд 26.07-10.08,
|
||||
# все 'done', succeeded=0 rows_inserted=0 failed_resolve=4-5 — раньше
|
||||
# ни total_seen/lots_fetched/unique_fetched не было, и
|
||||
# _run_result_count всегда возвращал None (honest-run-status)).
|
||||
# Сводить сюда счётчики ОСТАЛЬНЫХ задач бессмысленно: на проде 28 источников (2650
|
||||
# прогонов) не имеют общего результатного ключа вовсе — у каждого свой словарь
|
||||
# (deactivated / rows_written / poi_loaded / snapshotted / upserted / listings_matched
|
||||
|
|
@ -166,8 +176,7 @@ _RESULT_COUNTER_KEYS = (
|
|||
"total_seen",
|
||||
"lots_fetched",
|
||||
"unique_fetched",
|
||||
"rows_inserted",
|
||||
"processed",
|
||||
"succeeded",
|
||||
)
|
||||
|
||||
|
||||
|
|
@ -368,14 +377,16 @@ def _column_counts(counters: dict[str, int]) -> tuple[int | None, int | None]:
|
|||
|
||||
Приоритет ключей:
|
||||
- total_seen ← _RESULT_COUNTER_KEYS (total_seen / lots_fetched / unique_fetched /
|
||||
rows_inserted / processed)
|
||||
succeeded)
|
||||
- new_count ← 'new_count' / 'lots_inserted' / 'saved_inserted' / 'rows_inserted'
|
||||
(первый присутствующий). 'saved_inserted' — full-load'ы (cian/avito/yandex,
|
||||
CianFullLoadCounters и аналоги в pipeline.py): на проде витрина показывала
|
||||
new_count=0 у трёх подряд cian_full_load при реально сохранённых
|
||||
saved_inserted=482/214/239 (honest-run-status) — ключ 'new_count'/'lots_inserted'
|
||||
у full-load'ов в counters не пишется вовсе. 'rows_inserted' — тот же ключ,
|
||||
которым yandex_newbuilding_sweep сообщает число upsert'ов.
|
||||
которым yandex_newbuilding_sweep и rosreestr_dkp_import сообщают число upsert'ов;
|
||||
здесь (для витринной колонки new_count) это безопасно — в отличие от
|
||||
_RESULT_COUNTER_KEYS этот список не участвует в подсчёте zero-result-стрика.
|
||||
|
||||
Возвращает (total_seen, new_count); None для ключа, которого нет в counters —
|
||||
тогда соответствующая колонка не перезаписывается (COALESCE-семантика в UPDATE).
|
||||
|
|
|
|||
|
|
@ -5,7 +5,17 @@
|
|||
1500-1600 попыток без единого обогащения), yandex 31/52, domclick 24/30
|
||||
(494 попытки → 0 обогащено, 63 блока, 431 fail — и все 30 'done').
|
||||
|
||||
Проверяем ровно ветвление mark_backfill_finished — БД замокана.
|
||||
Проверяем ровно ветвление mark_backfill_finished — БД замокана (mark_done/mark_failed/
|
||||
mark_banned здесь fake-заглушки, регистрирующие ТОЛЬКО факт вызова). Это значит: кейсы
|
||||
ниже с высокой долей отказов (attempted=50, failed=38 или 36 — 76%/72%), ожидающие
|
||||
'done', проверяют лишь то, КАКОЙ финализатор ВЫБРАЛ mark_backfill_finished (#2674:
|
||||
"обогатили хоть что-то — успех"), а НЕ то, что реально запишет в БД mark_done. С
|
||||
honest-run-status (2026-08-15) mark_done САМ переквалифицирует такой прогон в 'failed'
|
||||
через _failed_ratio_too_high (доля отказов >= 0.5) — реальный терминальный статус
|
||||
для этих двух кейсов на проде теперь 'failed', не 'done'. Это намеренно проверяется
|
||||
отдельно, БЕЗ мока mark_done, в tests/test_honest_run_status_failed_ratio.py
|
||||
(test_prod_fact_avito_15_08_no_longer_done и соседние) — не читай эти два кейса как
|
||||
"76%/72% отказов = 'done' в проде".
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
|
@ -59,9 +69,15 @@ def _finish(counters: dict[str, int], *, aborted: bool = False) -> tuple[str, st
|
|||
({"attempted": 5, "enriched": 0, "failed": 5}, False, "failed"),
|
||||
# Кандидатов не было — честная пустота, это успех.
|
||||
({"attempted": 0, "enriched": 0, "blocked": 0, "failed": 0}, False, "done"),
|
||||
# Частичный прогон: обогатили хоть что-то → успех.
|
||||
# Частичный прогон: обогатили хоть что-то → mark_backfill_finished ВЫБИРАЕТ
|
||||
# mark_done как финализатор (#2674). 76% отказов (38 из 50) — здесь mark_done
|
||||
# замокан, поэтому статус остаётся 'done'; в реальном mark_done с
|
||||
# honest-run-status (2026-08-15) это переквалифицируется в 'failed'
|
||||
# (_failed_ratio_too_high, доля >= 0.5) — см. докстринг модуля.
|
||||
({"attempted": 50, "enriched": 12, "blocked": 0, "failed": 38}, False, "done"),
|
||||
# Блоки были, но прогон доработал и обогатил — не бан.
|
||||
# Блоки были, но прогон доработал и обогатил — mark_backfill_finished выбирает
|
||||
# НЕ 'banned'. 72% отказов (36 из 50) — та же оговорка: реальный mark_done
|
||||
# переквалифицирует в 'failed', см. докстринг модуля выше.
|
||||
({"attempted": 50, "enriched": 12, "blocked": 2, "failed": 36}, False, "done"),
|
||||
# Блок оборвал прогон, хотя часть успели обогатить — работа не доделана.
|
||||
({"attempted": 50, "enriched": 12, "blocked": 5, "failed": 33}, True, "banned"),
|
||||
|
|
|
|||
|
|
@ -12,8 +12,15 @@
|
|||
processed=5, succeeded=0, rows_inserted=0, failed_resolve=4-5 — сторож нулевого
|
||||
результата (_alert_if_consecutive_zero_results) слеп, т.к. _RESULT_COUNTER_KEYS
|
||||
не знал ни одного ключа этого sweep'а (total_seen/lots_fetched/unique_fetched).
|
||||
Фикс: _RESULT_COUNTER_KEYS дополнен rows_inserted/processed (в этом порядке —
|
||||
rows_inserted это РЕЗУЛЬТАТ, processed это ПОПЫТКИ).
|
||||
Фикс: _RESULT_COUNTER_KEYS дополнен 'succeeded'. Первая версия правки добавляла
|
||||
голые 'rows_inserted'/'processed' — ревью нашло, что 'rows_inserted' пишет ЕЩЁ
|
||||
rosreestr_dkp_import (66/67 прод-прогонов, здоровый ноль догнавшего импорта, а не
|
||||
отказ) и завёл бы непрерываемый ложный zero-стрик, а 'processed' — счётчик
|
||||
попыток (==limit даже при частичном провале у newbuilding_enrich) и маскирует
|
||||
реальные отказы. 'succeeded' пишут только yandex_newbuilding_sweep и
|
||||
newbuilding_enrich, численно совпадает с прежним 'rows_inserted' на всех
|
||||
прод-прогонах sweep'а — см. test_rosreestr_dkp_import_healthy_zero_stays_unmeasured
|
||||
и test_newbuilding_enrich_partial_failure_not_masked_by_processed ниже.
|
||||
|
||||
(c) admin-витрина показывала new_count=0 у трёх подряд cian_full_load, хотя реально
|
||||
сохранено saved_inserted=482/214/239 — full-load'ы не пишут ни 'new_count', ни
|
||||
|
|
@ -180,7 +187,8 @@ def test_honest_empty_sweep_unaffected_by_failed_ratio(name: str) -> None:
|
|||
|
||||
def test_prod_fact_yandex_newbuilding_sweep_measured_as_zero() -> None:
|
||||
"""processed=5, succeeded=0, rows_inserted=0, failed_resolve=4 — раньше
|
||||
_run_result_count возвращал None ("не измерено"); теперь — измеренный 0."""
|
||||
_run_result_count возвращал None ("не измерено"); теперь — измеренный 0 (через
|
||||
'succeeded', не 'rows_inserted' — см. ниже, почему ключ переигран ревью)."""
|
||||
counters = {
|
||||
"total": 309,
|
||||
"fetchable": 200,
|
||||
|
|
@ -198,23 +206,61 @@ def test_prod_fact_yandex_newbuilding_sweep_measured_as_zero() -> None:
|
|||
assert kit_runs._run_result_count(counters) == 0
|
||||
|
||||
|
||||
def test_rows_inserted_takes_priority_over_processed() -> None:
|
||||
"""rows_inserted (результат) читается ПЕРЕД processed (попытки) — иначе "5
|
||||
обработано, 0 записано" замаскировалось бы под measured-5."""
|
||||
def test_succeeded_is_the_measured_key_not_rows_inserted_or_processed() -> None:
|
||||
"""'succeeded' читается как результат; голые 'rows_inserted'/'processed' в
|
||||
_RESULT_COUNTER_KEYS больше не участвуют (были в первой версии правки, снято
|
||||
ревью — см. test_rosreestr_dkp_import_healthy_zero_stays_unmeasured и
|
||||
test_newbuilding_enrich_partial_failure_not_masked_by_processed ниже)."""
|
||||
counters = {"processed": 5, "rows_inserted": 0}
|
||||
assert app_runs._run_result_count(counters) == 0
|
||||
assert app_runs._run_result_count(counters) is None
|
||||
assert kit_runs._run_result_count(counters) is None
|
||||
|
||||
|
||||
def test_processed_is_fallback_when_rows_inserted_absent() -> None:
|
||||
counters = {"processed": 3}
|
||||
assert app_runs._run_result_count(counters) == 3
|
||||
def test_rosreestr_dkp_import_healthy_zero_stays_unmeasured() -> None:
|
||||
"""Прод-факт rosreestr_dkp_import (2026-08-15, 66 из 67 прогонов за 90д): инкрементальный
|
||||
импорт догнал источник — rows_fetched==rows_skipped, rows_inserted=0. Это ЗДОРОВЫЙ
|
||||
ответ (нечего вставлять), а не отказ; словарь не содержит 'succeeded' вовсе.
|
||||
|
||||
Первая версия правки добавляла голый 'rows_inserted' в _RESULT_COUNTER_KEYS — тогда
|
||||
этот прод-факт читался бы как "измеренный провал" и копил бы практически
|
||||
непрерываемый zero-стрик (rosreestr_dkp_import не прерывается другим статусом:
|
||||
он либо 'done' с этим же нулём, либо не бежал). Ревью поймало это до деплоя —
|
||||
правильный ответ: "не измерено" (None), стрик не копится."""
|
||||
counters = {
|
||||
"last_id": 6829903,
|
||||
"batches_done": 49,
|
||||
"rows_errored": 0,
|
||||
"rows_fetched": 96974,
|
||||
"rows_skipped": 96974,
|
||||
"rows_updated": 0,
|
||||
"rows_inserted": 0,
|
||||
}
|
||||
assert app_runs._run_result_count(counters) is None
|
||||
assert kit_runs._run_result_count(counters) is None
|
||||
|
||||
|
||||
def test_newbuilding_enrich_partial_failure_not_masked_by_processed() -> None:
|
||||
"""Прод-факт newbuilding_enrich (09.08): processed=25 (счётчик ПОПЫТОК, ==limit),
|
||||
succeeded=14 — 44% отказов. Если бы сторож читал 'processed' как результат, партиальный
|
||||
провал замаскировался бы под measured-25 (сторож нулевого результата промолчал бы
|
||||
ровно там, где должен был сработать при полном провале). 'succeeded' даёт честные 14."""
|
||||
counters = {
|
||||
"failed": 11,
|
||||
"enriched": 14,
|
||||
"attempted": 25,
|
||||
"processed": 25,
|
||||
"succeeded": 14,
|
||||
"failed_fetch": 11,
|
||||
}
|
||||
assert app_runs._run_result_count(counters) == 14
|
||||
assert kit_runs._run_result_count(counters) == 14
|
||||
|
||||
|
||||
@pytest.mark.parametrize("name", list(_MODULES))
|
||||
def test_zero_result_watchdog_now_fires_for_newbuilding_sweep_streak(name: str) -> None:
|
||||
"""(b) integration: 3 подряд yandex_newbuilding_sweep-подобных 'done' с
|
||||
rows_inserted=0 -> алерт срабатывает. До фикса _RESULT_COUNTER_KEYS сторож считал
|
||||
результат "не измеренным" и молчал бы вечно (см. #2703 в docstring модуля)."""
|
||||
"""(b) integration: 3 подряд yandex_newbuilding_sweep-подобных 'done' с succeeded=0
|
||||
-> алерт срабатывает. До фикса _RESULT_COUNTER_KEYS сторож считал результат "не
|
||||
измеренным" и молчал бы вечно (см. #2703 в docstring модуля)."""
|
||||
mod = _MODULES[name]
|
||||
row = MagicMock()
|
||||
row.status = "done"
|
||||
|
|
@ -228,6 +274,29 @@ def test_zero_result_watchdog_now_fires_for_newbuilding_sweep_streak(name: str)
|
|||
mock_sentry.capture_message.assert_called_once()
|
||||
|
||||
|
||||
@pytest.mark.parametrize("name", list(_MODULES))
|
||||
def test_zero_result_watchdog_silent_on_rosreestr_dkp_import_streak(name: str) -> None:
|
||||
"""Негативный аналог теста выше: та же лестница из 3 подряд 'done', но словарь
|
||||
rosreestr_dkp_import (нет 'succeeded') -> сторож не считает результат измеренным
|
||||
и НЕ шлёт алерт — регрессионный тест на замечание ревью (HIGH #1)."""
|
||||
mod = _MODULES[name]
|
||||
row = MagicMock()
|
||||
row.status = "done"
|
||||
row.counters = {
|
||||
"last_id": 6829903,
|
||||
"rows_fetched": 96974,
|
||||
"rows_skipped": 96974,
|
||||
"rows_inserted": 0,
|
||||
}
|
||||
db = MagicMock()
|
||||
result = MagicMock()
|
||||
result.fetchall.return_value = [row, row, row]
|
||||
db.execute.return_value = result
|
||||
with patch.object(mod, "sentry_sdk") as mock_sentry:
|
||||
mod._alert_if_consecutive_zero_results(db, "rosreestr_dkp_import")
|
||||
mock_sentry.capture_message.assert_not_called()
|
||||
|
||||
|
||||
# ── (c) _column_counts: прод-факт cian_full_load new_count=0 при saved_inserted>0 ───
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -138,18 +138,28 @@ def _pick_int(counters: Mapping[str, Any], *keys: str) -> int | None:
|
|||
# unique_fetched — full-load'ы avito/cian/yandex (4 источника, 133 прогона) — раньше
|
||||
# сторож их не видел, хотя у cian_full_load 6 из 38 успешных прогонов
|
||||
# реально дали ноль.
|
||||
# rows_inserted — yandex_newbuilding_sweep (единственный писатель ключа с таким
|
||||
# именем на верхнем уровне counters): проверено на проде 26.07-10.08 —
|
||||
# десять прогонов подряд, все 'done', processed=5 succeeded=0
|
||||
# rows_inserted=0 failed_resolve=4-5. Ни total_seen/lots_fetched/
|
||||
# unique_fetched у него нет, поэтому раньше _run_result_count всегда
|
||||
# возвращал None ("не измерено") и стрик у сторожа не копился никогда
|
||||
# (honest-run-status).
|
||||
# processed — тот же sweep: сколько домов взял в работу. НАМЕРЕННО стоит ПОСЛЕ
|
||||
# rows_inserted в кортеже — processed это счётчик ПОПЫТОК (аналог
|
||||
# attempted), а не результата: у него ненулевое значение (=limit) даже
|
||||
# когда rows_inserted=0, и если бы он читался первым, «5 обработано,
|
||||
# 0 записано» замаскировалось бы под measured-5, а не measured-0.
|
||||
# succeeded — yandex_newbuilding_sweep (42 прогона/90д) и newbuilding_enrich
|
||||
# (65 прогонов/90д, единственные два писателя ключа на проде,
|
||||
# проверено 2026-08-15). НЕ 'rows_inserted': тот ключ пишет ЕЩЁ и
|
||||
# rosreestr_dkp_import (67 прогонов/90д) — у него rows_inserted=0 в
|
||||
# 66 из 67 это ЗДОРОВЫЙ ответ догнавшего инкрементального импорта
|
||||
# (rows_fetched=rows_skipped=96974, last_id не двигается неделями),
|
||||
# а не отказ; если бы 'rows_inserted' попал в этот список, сторож
|
||||
# зачитывал бы этот здоровый ноль как измеренный провал и копил бы
|
||||
# практически непрерываемый стрик (rosreestr_dkp_import не
|
||||
# прерывается другим статусом — импорт либо 'done', либо не бежал).
|
||||
# НЕ 'processed' по той же причине с другой стороны: это счётчик
|
||||
# ПОПЫТОК (у newbuilding_enrich processed==attempted==limit даже
|
||||
# когда succeeded меньше — прод-факт 09.08: processed=25 succeeded=14,
|
||||
# 44% отказов замаскировались бы под measured-25) — сторож нулевого
|
||||
# результата на нём молчал бы ровно там, где должен сработать, а на
|
||||
# будущем опустении очереди домов (cian_houses_pending) создал бы
|
||||
# свой вечный ложный zero-стрик. 'succeeded' у yandex_newbuilding_sweep
|
||||
# численно совпадает с 'rows_inserted' на всех 42/42 прод-прогонах —
|
||||
# замена не теряет исходную цель (десять прогонов подряд 26.07-10.08,
|
||||
# все 'done', succeeded=0 rows_inserted=0 failed_resolve=4-5 — раньше
|
||||
# ни total_seen/lots_fetched/unique_fetched не было, и
|
||||
# _run_result_count всегда возвращал None (honest-run-status)).
|
||||
# Сводить сюда счётчики ОСТАЛЬНЫХ задач бессмысленно: на проде 28 источников (2650
|
||||
# прогонов) не имеют общего результатного ключа вовсе — у каждого свой словарь
|
||||
# (deactivated / rows_written / poi_loaded / snapshotted / upserted / listings_matched
|
||||
|
|
@ -161,8 +171,7 @@ _RESULT_COUNTER_KEYS = (
|
|||
"total_seen",
|
||||
"lots_fetched",
|
||||
"unique_fetched",
|
||||
"rows_inserted",
|
||||
"processed",
|
||||
"succeeded",
|
||||
)
|
||||
|
||||
|
||||
|
|
@ -368,14 +377,16 @@ def _column_counts(counters: dict[str, int]) -> tuple[int | None, int | None]:
|
|||
|
||||
Приоритет ключей:
|
||||
- total_seen ← _RESULT_COUNTER_KEYS (total_seen / lots_fetched / unique_fetched /
|
||||
rows_inserted / processed)
|
||||
succeeded)
|
||||
- new_count ← 'new_count' / 'lots_inserted' / 'saved_inserted' / 'rows_inserted'
|
||||
(первый присутствующий). 'saved_inserted' — full-load'ы (cian/avito/yandex,
|
||||
CianFullLoadCounters и аналоги в pipeline.py): на проде витрина показывала
|
||||
new_count=0 у трёх подряд cian_full_load при реально сохранённых
|
||||
saved_inserted=482/214/239 (honest-run-status) — ключ 'new_count'/'lots_inserted'
|
||||
у full-load'ов в counters не пишется вовсе. 'rows_inserted' — тот же ключ,
|
||||
которым yandex_newbuilding_sweep сообщает число upsert'ов.
|
||||
которым yandex_newbuilding_sweep и rosreestr_dkp_import сообщают число upsert'ов;
|
||||
здесь (для витринной колонки new_count) это безопасно — в отличие от
|
||||
_RESULT_COUNTER_KEYS этот список не участвует в подсчёте zero-result-стрика.
|
||||
|
||||
Возвращает (total_seen, new_count); None для ключа, которого нет в counters —
|
||||
тогда соответствующая колонка не перезаписывается (COALESCE-семантика в UPDATE).
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue