Панель Наблюдаемости: news-overview (эксплуатация)
Operational-борд контекста news (лента новостей PIN): здоровье лент, публикаций, комментариев,
консюмеров identity, embed-интеграции selections и outbox/детач-механик. Не dev-stats: метрики —
OTel-инструменты приложения + PostgreSQL-counters (ClickHouse не используется, ADR-0056/0057). Дом полей —
../domain/post.md, ../domain/comment.md; контракты событий —
../events/post-published.md, ../events/comment-added.md.
Назначение
Отвечает на operational-вопрос: держит ли news свои SLO и не деградируют ли асинхронные механики
(консюмеры pin.identity.*, outbox pin.news.*, детач snapshot-ов, reconcile CommentsCount) и
синхронная зависимость selections (embed-блоки). Owning team — PIN Engagement; аудитория —
engineering + support. Регистрируется в observability-dashboard-catalog
как service-борд контекста (RED + доменные бизнес-метрики).
Область Действия
| Поле | Значение |
|---|
| Инструмент | Grafana |
| Folder | pin/news |
| Сервисы | news (owner); upstream identity (события), selections (internal API embed) |
| Аудитория | engineering / support |
| Primary SLO | Лента global/subscription p99 < 300 мс; FTS p99 < 400 мс |
| Статус | draft |
Переменные
Метрики — платформенного уровня (опубликованная лента публична, ADR-0052); tenantId применяется как
drill-down по логам/трейсам для authoring/company-scope, не как высококардинальный label метрик
(AuthorCompanyId не выносится в labels — bounded-требование каталога).
| Переменная | Тип | Источник | Значение по умолчанию | Безопасность |
|---|
environment | string (enum) | resource attribute deployment.environment | production | Обязательный фильтр |
service | string | resource attribute service.name | news | Фиксирован |
feedKind | string (enum global/subscription/fts) | label feed_kind | * | Bounded (3 значения) |
authorType | string (enum PostAuthorType) | label author_type | * | Bounded (5 значений) |
topic | string (enum pin.news.*/pin.identity.*) | label topic | * | Bounded |
tenantId | TenantId (= AuthorCompanyId, nullable) | correlationId/tenant_id в логах/трейсах | * | Только drill-down authoring/company scope |
Панели
| Panel | Metric/Query | Агрегация | Порог | Runbook |
|---|
feed-rps | news_feed_query_requests_total{feed_kind} | rate() by feed_kind | info | — |
feed-latency | news_feed_query_duration_ms{feed_kind} | p50/p99 by feed_kind | p99: global/subscription 300 мс, fts 400 мс | feed-latency |
publish-rate | news_posts_published_total{category_slug,author_type,publish_kind} | increase(1d) by category/author/kind | info | — |
comment-rate | news_comments_added_total{is_reply} | rate() | info | — |
identity-consumer-lag | news_consumer_group_lag_seconds{topic} | max by topic | warn 30 с / crit 60 с | replay-identity-dlq |
consumer-dlq | news_consumer_dlq_total{topic,consumer,reason} | increase(5m) + depth | crit > 0 | replay-identity-dlq |
selections-client-errors | news_selections_client_requests_total{operation,status} | 5xx-доля by operation | warn/crit по порогу | selections-degraded |
detach-outbox-pending | news_snapshot_detach_outbox_pending | last / deriv(30m) | warn: растёт устойчиво | stuck-snapshot-detach |
comments-count-drift | news_comments_count_drift_posts | last (из reconcile-job) | warn > 0 | recompute-comments-count |
news-outbox-lag | news_outbox_publish_delay_seconds{topic=~"pin.news..*"} | p95 / max age | crit > 300 с | stuck-news-outbox |
posts-by-status | news_posts_by_status{status} | last by status | info | — |
feed_kind=fts — глобальная лента с searchTerm (полнотекстовый поиск — Elasticsearch-проекция news-posts, ADR-0059); publish_kind —
first/republish (из IsFirstPublish, post-published.md); status —
PostStatus (Draft/Published/Unpublished/Archived, post.md).
Метрики
Источник — OTel-инструменты приложения (RED) и PostgreSQL-gauges (периодический scrape counter-запросов).
Все labels bounded, enum — строкой; PII/секретов/unbounded-id в labels нет.
| Метрика | Тип | Labels | Владелец | Смысл |
|---|
news_feed_query_requests_total | counter | feed_kind, status | news (OTel) | RPS лент global/subscription/fts; status = ok/error. |
news_feed_query_duration_ms | histogram | feed_kind | news (OTel) | Latency лент; p50/p99 против SLO 300/400 мс. |
news_posts_published_total | counter | category_slug, author_type, publish_kind | news (OTel) | Публикации/републикации по категориям и типам авторов. |
news_comments_added_total | counter | is_reply | news (OTel) | Темп комментариев (корневые/ответы). |
news_consumer_group_lag_seconds | gauge | topic, consumer | news (Kafka/OTel) | Лаг консюмеров по pin.identity.users.v1/pin.identity.companies.v1. |
news_consumer_dlq_total | counter | topic, consumer, reason | news (OTel) | Dead-letter консюмеров; reason = unknown_version/handler_error. |
news_selections_client_requests_total | counter | operation, status | news (OTel) | Вызовы internal API selections; operation = create/detach/get, status = ok/4xx/5xx/timeout; 5xx create/detach блокируют embed-публикацию. |
news_snapshot_detach_outbox_pending | gauge | — | news (PostgreSQL) | Число неотвязанных snapshot-ов (news.snapshot_detach_outbox, статус Pending). |
news_comments_count_drift_posts | gauge | — | news (reconcile-job) | Число постов с расхождением Post.CommentsCount ↔ факт (INV-CMT-005), из comment-count-reconcile. |
news_outbox_publish_delay_seconds | gauge | topic | news (PostgreSQL) | Возраст старейшего неопубликованного сообщения outbox для pin.news.post-published.v1/comment-added.v1. |
news_posts_by_status | gauge | status | news (PostgreSQL) | Размеры Draft/Published/Unpublished/Archived. |
Сигналы Logs И Traces
| Сигнал | Query | Correlation |
|---|
| Logs (selections 5xx) | service=news component=selections-client level=Error operation IN (create,detach) | correlationId, tenantId, postId |
| Logs (consumer DLQ) | service=news consumer=~"identity-.*" outcome=dead-lettered | correlationId, messageId, aggregateId (= PostId) |
| Logs (detach retry) | service=news job=snapshot-detach-retry outcome=failed | correlationId, snapshotId, postId |
| Traces (publish) | service=news span=публикация-поста (child: selections.create, запись outbox) | correlationId, causationId |
Trace публикации связывает переход Post → Published, запись PostVersion и outbox post-published
в одном согласованном изменении (INV-NWS-005).
Оповещения Alerts
| Alert | Условие | Severity | Notification | Runbook |
|---|
news_selections_client_5xx_spike | 5xx-доля create/detach > порога 5 мин (блокирует embed) | High | #pin-news-oncall | selections-degraded |
news_consumer_dlq_present | increase(news_consumer_dlq_total[5m]) > 0 | High | #pin-news-oncall | replay-identity-dlq |
news_identity_consumer_lag_breach | news_consumer_group_lag_seconds > 60 5 мин | High | #pin-news-oncall | replay-identity-dlq |
news_outbox_publish_delay_breach | news_outbox_publish_delay_seconds{topic=~"pin.news..*"} > 300 5 мин | High | #pin-news-oncall | stuck-news-outbox |
news_snapshot_detach_backlog_growing | news_snapshot_detach_outbox_pending растёт (deriv > 0) 30 мин ∧ > базового уровня | Medium | #pin-news-oncall | stuck-snapshot-detach |
news_fts_latency_slo_breach | feed-latency p99 feed_kind=fts > 400 мс 10 мин | Medium | #pin-news-oncall | feed-latency |
news_comments_count_drift | news_comments_count_drift_posts > 0 после reconcile-run | Low | #pin-news-oncall | recompute-comments-count |
SLO, Бюджет Ошибок И Эскалация
| SLO | Цель | Окно | Индикатор (панель) | Действие при нарушении |
|---|
Латентность ленты global/subscription | p99 < 300 мс | 30 дней | feed-latency | news_fts_latency_slo_breach не покрывает — деградация ленты расследуется по feed-latency |
Латентность поиска (fts) | p99 < 400 мс | 30 дней | feed-latency{feed_kind=fts} | Medium-alert 10 мин → feed-latency |
Свежесть реплик identity | лаг < 60 с | rolling | identity-consumer-lag | High-alert 5 мин → replay-identity-dlq |
Доставка pin.news.* (outbox) | возраст < 300 с | rolling | news-outbox-lag | High-alert 5 мин → stuck-news-outbox |
| Целостность консюмеров | DLQ = 0 | rolling | consumer-dlq | High-alert при любом росте → replay |
- Бюджет ошибок латентности тратится на минутах вне SLO; устойчивое превышение p99 (10+ мин) поднимает
приоритет расследования до High даже без формального alert (борд — ранний сигнал деградации до брейча).
- Приоритеты алертов. High (лаг реплик, outbox, DLQ, selections 5xx) — немедленная реакция oncall;
Medium (fts-латентность, растущий backlog детача) — в течение смены; Low (
CommentsCount drift) —
плановый reconcile. Все ведут на greenfield-runbook.
- Корреляция инцидента. При High-алерте по
identity-consumer-lag/consumer-dlq подписи авторов/
компаний устаревают (эффекты Blocked/Suspended применяются query-слоем на выдаче) — деградация видна
пользователю как «старая подпись/статус», не как отказ ленты; это ожидаемое eventual-поведение до replay.
Маскирование Sensitive Data
- Борд не отображает
Comment.Body (UGC/PII), тела блоков PostContentDocument, содержимое
SelectionSnapshot, secrets и токены — только счётчики/латентности/лаги.
AuthorUserId/AuthorCompanyId/PostId/CommentId в labels не выносятся (unbounded); доступны
только как correlation в логах/трейсах для drill-down.
- Screenshots для инцидентов маскируют
tenantId и любые id в аннотациях.
Проверка
| Проверка | Ожидаемый Результат |
|---|
| Empty state | При отсутствии трафика панели показывают 0/нет данных без ошибок запроса. |
| Tenant drill-down | Логи/трейсы authoring фильтруются по выбранному tenantId (= AuthorCompanyId). |
| Alert links | Каждый alert ведёт на действующий (планируемый greenfield) runbook. |
| Time range | Панели корректны на 15m (инцидент) и 7d (тренды публикаций/детача). |
| SLO-панель | feed-latency показывает пороговые линии 300/400 мс по feed_kind. |
Топология сигналов
Ограничения И Допущения
- Метрики outbox/detach/status/drift — PostgreSQL-gauges через периодический scrape (задержка ≤ интервала
scrape); мгновенные всплески между scrape-ами не видны — источник истины остаётся в БД.
news_comments_count_drift_posts обновляется ночным comment-count-reconcile (не realtime): алерт
сигнализирует накопленный дрейф, не текущий.
- FTS отделяется от
global по наличию searchTerm (label feed_kind=fts), а не по отдельному endpoint.
- Runbook-файлы — greenfield (пути целевые, по runbook-template).
- Ранжирование (
recommended) отложено (решение №10) — панели по ranking-сигналам отсутствуют.
Обратные ссылки
Автоссылки: где используется этот документ.
Связанные Документы
- Сервис: README (Runtime И Эксплуатация — SLO/Dashboard/Alerts/Runbooks/Jobs); домены
post.md, comment.md.
- События:
post-published.md, comment-added.md
(ContractVersion = 1, топики pin.news.*.v1, транзакционный outbox); consumed
pin.identity.users.v1/pin.identity.companies.v1.
- Операции:
publish-post.md,
list-global-feed.md,
list-subscription-feed.md,
add-comment.md.
- Jobs (планируются):
../jobs/comment-count-reconcile.md, ../jobs/snapshot-detach-retry.md.
- Runbooks (планируются): replay-identity-dlq,
stuck-snapshot-detach,
recompute-comments-count,
stuck-news-outbox, selections-degraded,
feed-latency.
- Каталог бордов: observability-dashboard-catalog.
- ADR: ADR-0052 (tenancy),
ADR-0056 (PostgreSQL-only, без ClickHouse).