13 KiB
Проверка членства в СРО: эксплуатация
Источник sro_membership_check, группа/тип sro_membership, карточка
sro-membership-check. Upstream — сайт reestr-sro.ru; внутренний справочник
организаций используется для точной привязки UID и ОКПО. Другие внешние реестры
загрузчик не опрашивает.
Доступ и пределы запросов
По умолчанию сбор закрыт. Для открытия необходимы одновременно
SRO_UPSTREAM_ACCESS_APPROVED=true и непустой
SRO_UPSTREAM_APPROVAL_REFERENCE — ссылка/номер документированного разрешения
владельца сайта на автоматизированные query/search запросы. Согласование разработки
внутри проекта не заменяет разрешение владельца upstream. Условия разрешения
должны быть совместимы с настройками загрузчика; более строгие пределы задаются
перед включением. Секреты в approval reference хранить нельзя.
Оба ручных entrypoint проверяют этот gate до enqueue; task и HTTP клиент повторяют
проверку перед внешним IO. Закрытый gate возвращает typed
409 upstream_access_not_approved. Если разрешение отозвано после постановки,
job завершается с ошибкой, без успешной пустой публикации.
| Настройка | По умолчанию | Значение |
|---|---|---|
SRO_REQUEST_INTERVAL_SECONDS |
3 |
Минимум 3 секунды между запросами, включая redirects/retries; можно увеличить. |
SRO_HTTP_MAX_RESPONSE_BYTES |
2097152 |
Предел распакованного тела одного ответа. |
SRO_HTTP_TIMEOUT_SECONDS |
30 |
Read timeout; connect timeout 10 секунд. |
SRO_MAX_REQUESTS_PER_RUN |
10000 |
Общий предел запросов одного запуска, включая redirects/retries/sitemaps. |
HTTP клиент делает не более трёх попыток при транспортной ошибке и ответах
429/500/502/503/504. Retry-After учитывается как секунды или HTTP date, ожидание
свыше 300 секунд завершает запуск ошибкой. Цепочка redirects ограничена пятью
ответами; каждый адрес проверяется до обращения. Разрешён только HTTPS без
credentials/нестандартного порта, на reestr-sro.ru и его поддоменах. Переменные
окружения HTTP proxy автоматически не используются. HTML/query с идентификаторами
не выводится в application logs.
Публикация и обновление
Celery task: parsers.sro_membership_check.refresh;
Python entrypoint: apps.parsers.tasks_registry_snapshots.parse_sro_membership,
keyword args requested_by_id=None, mode="incremental"|"full".
Проверяются только организации текущего канонического справочника. Инкрементальный
запуск выбирает новые организации и те, у которых изменились name/full_name,
ИНН/ОГРН/ОКПО. Изменение определяется fingerprint; у модели Organization нет
универсального updated_at. Полный запуск проверяет весь справочник.
Lookup использует точный ОГРН, при его отсутствии/неподходящем формате — ИНН
с проверкой нормализованного имени. Если нет пригодного идентификатора, запуск
отклоняется с sro_candidate_identifier_missing, без удаления прежних записей.
Ответ дополнительно сопоставляется по ИНН+ОГРН через внутренний индекс. Отсутствие
ОКПО, конфликт идентификаторов, неоднозначная организация, неизвестный статус,
неполные обязательные поля или missing/unsafe SRO URL отправляют строку в quarantine.
Новые организации из внешнего ответа не создаются.
Одна запись соответствует паре canonical organization UID + SRO ID. Record UID
стабилен между загрузками, включая переход active → excluded. SRO ID/URL
берётся из same-site ссылки или точного ID, разрешённого по same-site sitemap;
по одному похожему названию URL не угадывается. Для даты допуска читается same-site
страница members по ИНН. Неизвестная дата остаётся null с причиной
not_found, sro_page_unresolved или parse_error. Наблюдаемая дата реестра
не подменяется датой загрузки.
Raw ответы сохраняются в приватном ZIP artifact с manifest URL→файл; отдельные
staged rows содержат source fields, нормализованный payload и причину quarantine.
Для SRO используется отдельный FileSystemStorage: PARSER_PRIVATE_ARTIFACT_ROOT
по умолчанию равен <repository-root>/private-parser-artifacts, вне MEDIA_ROOT.
Путь обязан быть абсолютным и не находиться внутри MEDIA_ROOT, в том числе после
разрешения symlink. Ошибка конфигурации запрещает файловую операцию. Приватный storage
не выдаёт публичный URL; файлы создаются с правами 0600, каталоги 0700.
Остальные источники сохраняют прежний default_storage.
В контейнерном окружении задайте PARSER_PRIVATE_ARTIFACT_ROOT=/app/private-parser-artifacts
и подключите к web/worker один постоянный volume по этому пути. Каталог должен быть
доступен пользователю приложения для записи и не должен монтироваться в public media,
static или reverse-proxy document root. Существующая retention-команда удаляет private
файлы через тот же artifact.file.delete(); удаление/пересоздание контейнера не должно
удалять volume. Миграция 0037 меняет storage в состоянии модели без перемещения данных.
До этой версии живой SRO сбор не запускался. Если оператор ранее создал SRO artifacts
в старом MEDIA_ROOT вручную, их требуется отдельно перенести в private root с сохранением
относительных имён и убрать публичные копии до открытия источника; автоматического
fallback на public raw нет.
Публикация записей, checkpoint организаций, load log и terminal job выполняется
в одной транзакции. Инкрементальная публикация заменяет данные только успешно
проверенного набора организаций; записи остальных организаций сохраняются.
Transport/schema failure или отменённая job откатывает публикацию и checkpoints.
Допустимый пустой ответ удаляет старые членства проверенной организации.
Любая семантически некорректная строка остаётся в quarantine и отклоняет весь
запуск с sro_incomplete_membership_scan. Это сохраняет прежние членства и
checkpoints: неизвестный статус или неразрешённая ссылка не доказывают, что
членство исчезло. Организация остаётся кандидатом следующего incremental запуска.
Если incremental не нашёл изменившихся организаций, batch имеет нулевую дельту
и наследует source registry date/version последней успешной публикации; ссылка
на неё сохраняется в metadata.base_snapshot_artifact_id. Данные не переписываются.
После commit безопасно ставится существующая задача обновления общих export artifacts. Ошибка брокера после commit не превращает успешную публикацию в failure; готовность выгрузки отражает собственный контракт export service.
Счётчики и диагностика
artifact.published_count, result.published_records_count и load_log.records_count
содержат размер текущего опубликованного набора источника. Для incremental это
общий результат, включая неизменённые организации. metadata.snapshot_records_count
и snapshot_organizations_count дают такие же общие record/distinct organization
counts; batch_published_records_count и updated_records_count — число опубликованных
строк текущей дельты. parsed_count, quarantine и candidate/queried counts относятся
к текущей проверке; складывать их с общим published count нельзя.
Источник публикует весь собственный справочник; карточка/list/dashboard для трёх
новых источников используют весь published scope. Coverage ОПК показывается
отдельно. МСП и бюджет продолжают полную замену: новый scoped аргумент публикации
по умолчанию None сохраняет их поведение.
Для расследования используют job status/error, artifact status,
metadata.rejection_reason, rejection_reasons и staged disposition/reason.
Они содержат ограниченные коды ошибок, не raw HTML. Partial raw ZIP сохраняется
при ошибке уже начатого сбора; предыдущая публикация остаётся доступна.
Приватные raw artifacts удерживаются минимум 90 дней и минимум 10 последних
успешных SRO batches; неуспешные batches не вытесняют эти десять успешных.
Расписания и граница проверки
Миграция parsers.0036_sro_disabled_schedules создаёт выключенные schedules:
daily incremental в 04:00 Europe/Moscow; monthly full 16-го числа в 04:00
Europe/Moscow — после наблюдаемого обновления реестра 15-го. Перед включением
нужно подтвердить фактическую периодичность/условия разрешения. Расписание само
не открывает gate; оба механизма по умолчанию выключены.
На 14.09.2026 query/search и живой SRO snapshot не запускались. Основная страница
без query доступна через read-only web; свежий robots.txt получить не удалось.
Указанные в source-first спецификации Crawl-delay: 3 и query/search disallow
учтены консервативно. DOM selector/mapping проверены синтетическими fixtures формы
из docs/source-integration/sources/sro-membership-check/backend-api.md, а не
полным live scan. После разрешения владельца обязательна ограниченная проверка
фактической разметки перед первой полной загрузкой.