lightning-terminal/db/migsets/sql_migrations_dev.go
Elle Mouton fb5863e38c
multi: wait for lnd with a configurable timeout during SQL migration
The kvdb-to-SQL data migration polls lnd's ListMacaroonIDs RPC, which
only becomes available once lnd reaches its "RPC active" state. On
nodes with a large channel/graph state, lnd can take well over a
minute to get there after the wallet is unlocked, which exceeded the
previous fixed 60-second (120 x 500ms) poll budget and caused the
migration - and therefore litd startup - to fail permanently,
requiring a manual restart.

Replace the fixed attempt cap with a wait bounded by the new
--lndreadytimeout config option, defaulting to a generous 10 minutes,
while still aborting early if the daemon is shutting down. The wait
happens inside the migration's SQL write transaction, so it is kept
bounded rather than unbounded as a safety backstop.
2026-07-29 15:47:47 -07:00

88 lines
2.7 KiB
Go

//go:build dev
package migsets
import (
"context"
"path/filepath"
"time"
"github.com/golang-migrate/migrate/v4"
"github.com/golang-migrate/migrate/v4/database/pgx/v5"
"github.com/lightninglabs/lightning-terminal/db"
"github.com/lightningnetwork/lnd/clock"
"github.com/lightningnetwork/lnd/lnrpc"
"github.com/lightningnetwork/lnd/sqldb/v2"
)
// MakeMigrationSets creates the migration sets for the dev environments.
func MakeMigrationSets(ctx context.Context,
basicClient lnrpc.LightningClient, macPath, litDir, network string,
clock clock.Clock,
lndReadyTimeout time.Duration) []sqldb.MigrationSet {
accountsDir := filepath.Dir(macPath)
networkDir := filepath.Join(litDir, network)
// Create the prod migration set.
migSet := sqldb.MigrationSet{
TrackingTableName: pgx.DefaultMigrationsTable,
SQLFileDirectory: "sqlc/migrations",
SQLFiles: db.SqlSchemas,
// LatestMigrationVersion is the latest migration version of the
// database. This is used to implement downgrade protection for
// the daemon.
//
// NOTE: This MUST be updated when a new migration is added.
LatestMigrationVersion: db.LatestMigrationVersion,
Descriptors: db.MakeMigrationDescriptors(),
MakeProgrammaticMigrations: func(baseDB *sqldb.BaseDB) (
map[uint]migrate.ProgrammaticMigrEntry, error) {
// Any programmatic migrations added to this map will be
// executed when the migration number for the uint key
// is applied. If no entry exists for a given uint, then
// no programmatic migration will be executed for that
// migration number.
res := make(map[uint]migrate.ProgrammaticMigrEntry)
res[db.KVDBtoSQLMigVersion] = Mig6ProgrammaticMigration(
ctx, basicClient, baseDB, accountsDir,
networkDir, clock, db.KVDBtoSQLMigVersion,
lndReadyTimeout,
)
return res, nil
},
}
// If there are no dev migrations in the sqlc/migrations_dev folder, we
// can return early.
if !db.HasDevMigrations() {
return []sqldb.MigrationSet{migSet}
}
// Create the dev migration set.
migSetDev := sqldb.MigrationSet{
TrackingTableName: pgx.DefaultMigrationsTable + "_dev",
SQLFileDirectory: "sqlc/migrations_dev",
SQLFiles: db.SqlSchemas,
// LatestMigrationVersion is the latest migration version of the
// dev migrations database. This is used to implement downgrade
// protection for the daemon.
//
// NOTE: This MUST be updated when a new dev migration is added.
LatestMigrationVersion: db.LatestDevMigrationVersion,
MakeProgrammaticMigrations: func(_ *sqldb.BaseDB) (
map[uint]migrate.ProgrammaticMigrEntry, error) {
return make(map[uint]migrate.ProgrammaticMigrEntry), nil
},
}
return []sqldb.MigrationSet{migSet, migSetDev}
}