Documentation
¶
Overview ¶
Package migratorrun — накат цепочки миграций, объявленный ОДИН раз на дерево.
Все семь точек наката (`services/*/cmd/migrator`) применяют миграции через Runner и своей редакции этого шага не держат. Решение и его довод — docs/architecture/migrator-form.md; здесь они не пересказываются.
Что сюда переехало ¶
Один и тот же вопрос — «как этот сервис применяет миграции» — решался в дереве ДВУМЯ формами, и решения об этом не принимал никто: формы разошлись как побочный эффект того, что сервисы заводились в разное время (#1383). Три службы держали собственный пакет-обёртку `internal/apps/migrator` (`Dialect` + `Runner` + `Config.Validate`), четыре звали goose прямо из `main.go`. Три обёртки при этом копиями НЕ были: у двух `Dialect` был интерфейсом, у одной — структурой.
Почему дом здесь, а не в pkg/migratorcli ¶
Решение называет домом общего пакета `pkg/`, и `pkg/migratorcli` уже несёт всё, что базы не касается: разбор аргументов, приоритет источников DSN, предусловия, открытие базы с барьером готовности, настройку goose.
Накат туда не переехал по ОДНОЙ измеренной причине: ему нужен живой счёт строк перед сносом (`pkg/dropguard`), а `pkg/` не имеет НИ ОДНОГО ребра в `internal/` (предикат: `git grep -l 'kacho/internal/' -- pkg ':!*_test.go'` → пусто). Завести первое такое ребро ради одного вызова значило бы принять решение о `pkg/` целиком, никем не принятое, и принять его молча.
Довод содержательный, а не обходной: счёт перед сносом — политика об этом дереве и его цепочках, а не переиспользуемый фундамент. Пакет, которому он нужен, репозиторно-внутренний по природе. Довод самого решения при этом сохранён дословно — общий пакет не лежит внутри одной службы и потому не заводит ребра между службами (ban #8).
Счёт перед сносом стоит ПО ПОСТРОЕНИЮ ¶
Он живёт внутри Runner.Up: обойти его нельзя, не обойдя сам Up. В прямой форме это был отдельный оператор в `main.go`, и его наличие держал гейт — то есть шаг, который зовут отдельной строкой, однажды могли не позвать.
Index ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Config ¶
type Config struct {
// Service — имя службы, чью цепочку применяет накат. Обязательное: без него
// живой счёт строк перед сносом не может назвать, что он стережёт, а
// безымянный отказ в логе init-контейнера некому адресовать.
Service string
// Dialect — имя диалекта, как его назвал оператор. Пустое имя НЕ означает
// «умолчание»: разбор аргументов подставляет умолчание сам, поэтому пустая
// строка сюда доезжает только как явное `--dialect ""` — то есть как
// названный и неподдерживаемый диалект.
Dialect string
// DSN — строка подключения. Резолвит её [migratorcli.ResolveDSN] у всех
// семи, с одним приоритетом: `--dsn` > [migratorcli.EnvDSN] > конфигурация.
DSN string
// FS — файловая система с миграциями (`internal/migrations.FS` службы).
// Параметром, а не импортом: правило `internal` языка запрещает пакету из
// корня импортировать `services/<svc>/internal/migrations`.
FS fs.FS
// MigrationsDir — путь внутри FS; для корня встроенной — ".".
MigrationsDir string
// DSNExtraSources — чем ЭТА служба заполняет DSN СВЕРХ двух общих, в порядке
// убывания приоритета. Два общих здесь не перечисляются: их печатает
// [migratorcli.DSNSourceList], поэтому умолчать источник, который перебивает
// названные, нельзя by construction.
DSNExtraSources []string
}
Config — параметры одного запуска наката. Заполняет их `cmd/migrator/main.go` каждой службы из разобранных аргументов, окружения и своей конфигурации.
type Runner ¶
type Runner struct {
// contains filtered or unexported fields
}
Runner — накат цепочки. Один экземпляр на жизнь процесса; параллельное использование не предполагается (goose держит настройку в пакетных глобалках, а командная строка гоняет одну команду за раз).
func New ¶
New собирает Runner, проверив предусловия ДО первого обращения к базе.
Проверки, их порядок и тексты отказа объявлены один раз на дерево — migratorcli.RunnerPreconditions. Здесь они не переобъявляются: своей редакции того же текста завестись негде, потому что Runner в дереве один.
func (*Runner) Down ¶
Down откатывает цепочку: незаданная цель — один шаг назад, заданная — до названной версии включительно.
Счёта перед сносом здесь нет намеренно: откат — заявленный снос, а не побочный. Предмет стража — снос, приезжающий вместе с накатом, о котором оператор не знал.
func (*Runner) Status ¶
Status печатает применённые и непринятые миграции.
out принимается параметром и ЗДЕСЬ НЕ ЧИТАЕТСЯ: goose v3 пишет в собственный логгер, а перенаправление идёт через goose.SetLogger. Параметр остаётся, чтобы перенаправление, когда его заведут, не меняло подпись у семи вызывающих.
func (*Runner) Up ¶
Up применяет цепочку — сперва СОСЧИТАВ строки в таблицах, которые уронят ещё не применённые миграции В ПРЕДЕЛАХ ЭТОГО ПРОГОНА, и лишь затем применяя. Ненулевой счёт прекращает применение.
Граница прогона разбирается ДО счёта: страж обязан считать ровно те сносы, которые этот прогон ВЫПОЛНИТ, а не все ещё не применённые. Разбор — та же функция, которой читает цель goose, поэтому двух редакций одного числа завестись не может; заодно негодная цель отвергается до соединения с базой.
Обойти счёт цель НЕ ДАЁТ, и это построение, а не обещание: незаданная цель — нулевое значение dropguard.Target, то есть «считать всё», а суженная сужает ровно настолько же и применяемое.