health

package
v1.3.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 10, 2026 License: Apache-2.0 Imports: 6 Imported by: 0

Documentation

Overview

Package health — ЕДИНСТВЕННЫЙ в дереве носитель разведённых живости и готовности.

Готовность (`/readyz`) строится из ИМЕНОВАННЫХ проверок критичных зависимостей (база / канал к владельцу прав / дренер регистраций / исполнитель операций). Отказ зависимости снимает под из ротации (503), а живость (`/healthz`) при этом остаётся 200 — она зависит ТОЛЬКО от процесса, чтобы блип зависимости не вызвал шторм перезапусков. Каждый чекер ограничен собственным сроком: зависшая зависимость считается недоступной, но не вешает обработчик.

На гашении SetShuttingDown переводит `/readyz` в 503 (kubelet перестаёт слать трафик) ДО остановки gRPC-серверов.

Почему носитель ОДИН, а не по копии на сервис

Копий было три, и они были кодом идентичны — то есть один механизм, о котором дерево говорило трижды. Разойтись им было нечем: копии не собираются вместе и друг друга не читают, поэтому расхождение пришло бы молча. Замер, из которого это выведено (задача продукта #1655): трём сервисам из семи готовность требовалось завести впервые, и заведение по месту дало бы ШЕСТЬ копий вместо трёх (`architecture.md` §«Переиспользование через общий фундамент pkg/»).

Чего этот пакет НЕ решает

ЧТО именно проверяет каждая зависимость — вопрос композиционного корня: он один знает, какая база у сервиса своя и к кому он ходит. Пакет отвечает лишь за то, чтобы ответ был РАЗВЕДЁН на два и чтобы ни один чекер не мог подвесить обработчик.

Index

Constants

This section is empty.

Variables

View Source
var ErrDependencyNotWired = errors.New("dependency not wired yet")

ErrDependencyNotWired — зависимость объявлена корнем, но её носитель ещё не установлен. Причина «не готов» без раскрытия внутренних деталей наружу.

Functions

This section is empty.

Types

type Aggregator

type Aggregator struct {
	// contains filtered or unexported fields
}

Aggregator агрегирует readiness по набору чекеров и разводит liveness/readiness. Потокобезопасен (shutting — под mutex'ом; чекеры read-only).

func New

func New(checkers []Checker, opts ...Option) *Aggregator

New конструирует Aggregator поверх набора чекеров.

func (*Aggregator) Evaluate

func (a *Aggregator) Evaluate(ctx context.Context) (bool, []string)

Evaluate прогоняет все чекеры конкурентно с per-checker bounded-timeout и возвращает готовность + имена упавших зависимостей (в порядке объявления чекеров). Результат зеркалится в observer.

func (*Aggregator) LiveHandler

func (a *Aggregator) LiveHandler() http.HandlerFunc

LiveHandler — liveness probe. 200 `ok`, пока процесс жив и не в shutdown. НЕ зависит от внешних зависимостей (защита от restart-storm).

func (*Aggregator) ReadyHandler

func (a *Aggregator) ReadyHandler() http.HandlerFunc

ReadyHandler — readiness probe. 200 `{"status":"ready"}`, когда все критичные зависимости здоровы; 503 со списком упавших — иначе; 503 `{"status":"shutting_down"}` на graceful-shutdown.

func (*Aggregator) SetShuttingDown

func (a *Aggregator) SetShuttingDown()

SetShuttingDown помечает процесс в состоянии graceful-shutdown — readiness сразу флипает в 503, liveness тоже отдаёт 503 (процесс гасится).

type Checker

type Checker struct {
	Name  string
	Check func(ctx context.Context) error
}

Checker — именованная проверка одной зависимости. Check возвращает nil, если зависимость здорова; любая ошибка (или таймаут) трактуется как down.

type Option

type Option func(*Aggregator)

Option — функциональная опция Aggregator.

func WithResultObserver

func WithResultObserver(f func(dependency string, up bool)) Option

WithResultObserver подключает зеркало результата readiness (напр. dependency_up Prometheus-gauge): вызывается на каждый чекер при каждой оценке.

func WithTimeout

func WithTimeout(d time.Duration) Option

WithTimeout задаёт per-checker бюджет (дефолт 1s).

type Slot

type Slot struct {
	// contains filtered or unexported fields
}

Slot — зависимость, чей носитель появляется ПОЗЖЕ поверхности.

Зачем

Диагностическая поверхность поднимается РАНО и намеренно: пока её нет, проба живости получает отказ соединения, и медленный старт читается kubelet'ом как мёртвый процесс — то есть шторм перезапусков ровно там, где процесс исправно поднимается. Часть зависимостей при этом ещё не создана: соединение с соседом набирается ниже по тексту корня.

Прямое замыкание на переменную корня здесь негодно ДВАЖДЫ: обработчик читает её из другой горутины (гонка, и `-race` это покажет), а до присваивания он увидит нулевое значение и объявит зависимость исправной. Slot закрывает оба: доступ синхронизирован, а до установки ответ — НЕ ГОТОВ.

Умолчание выбрано fail-closed осознанно: неустановленная зависимость есть «ответа нет», а неполученный ответ не является «да».

func (*Slot) Check

func (s *Slot) Check(ctx context.Context) error

Check — тело чекера. До Install отвечает ErrDependencyNotWired: «носителя ещё нет» и «носитель отвечает» обязаны быть различимы, иначе окно старта молча зачитывается в готовность.

func (*Slot) Checker

func (s *Slot) Checker(name string) Checker

Checker собирает Slot в именованную проверку.

func (*Slot) Install

func (s *Slot) Install(check func(ctx context.Context) error)

Install подключает носителя зависимости. Повторный вызов заменяет прежнего — корень вправе пересобрать соединение, не пересобирая поверхность.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL