feat(platform): show which startup step is running, with progress and ETA (#3813)
Co-authored-by: nova28 <17953305+nova28@users.noreply.github.com> Co-authored-by: Carlos Florencio <carlosmflorencio@gmail.com>
This commit is contained in:
@@ -14,6 +14,7 @@ import (
|
||||
"go.uber.org/zap"
|
||||
|
||||
"github.com/kandev/kandev/internal/db/dialect"
|
||||
"github.com/kandev/kandev/internal/startup"
|
||||
)
|
||||
|
||||
// migrateExecutorProfiles adds mcp_policy column and drops is_default from executor_profiles.
|
||||
@@ -53,7 +54,9 @@ func (r *Repository) migrateSessionsAddCostColumns() {
|
||||
}
|
||||
|
||||
// runMigrations applies idempotent ALTER TABLE migrations for schema evolution.
|
||||
func (r *Repository) runMigrations() error {
|
||||
//
|
||||
//nolint:cyclop,funlen,maintidx // Legacy flat list of ~60 independent idempotent migration steps predating startup-step instrumentation; splitting it is out of scope here.
|
||||
func (r *Repository) runMigrations(ctx context.Context) error {
|
||||
if err := r.migrateTaskPriorityToTextPostgres(); err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -214,7 +217,9 @@ func (r *Repository) runMigrations() error {
|
||||
// explicitly in CreateMessage/UpdateMessage. The backfill UPDATE is idempotent
|
||||
// (WHERE updated_at IS NULL).
|
||||
r.migrate.Apply("task_session_messages.updated_at", `ALTER TABLE task_session_messages ADD COLUMN updated_at TIMESTAMP`)
|
||||
startup.BeginStep(ctx, startup.StepMessageTimestampsBackfill)
|
||||
r.migrate.Apply("task_session_messages.updated_at.backfill", `UPDATE task_session_messages SET updated_at = created_at WHERE updated_at IS NULL`)
|
||||
startup.EndStep(ctx, startup.StepMessageTimestampsBackfill)
|
||||
r.migrate.Apply("idx_messages_session_updated", `CREATE INDEX IF NOT EXISTS idx_messages_session_updated ON task_session_messages(task_session_id, updated_at)`)
|
||||
|
||||
// task_session_commits gains a uniqueness constraint before its writer
|
||||
@@ -378,7 +383,7 @@ func (r *Repository) runMigrations() error {
|
||||
// table is not part of the supported upgrade path, so there is no
|
||||
// intermediate-shape rebuild to run here. Only the historical-message
|
||||
// backfill belongs in the migration phase.
|
||||
r.migrateSubagentContextBackfill()
|
||||
r.migrateSubagentContextBackfill(ctx)
|
||||
|
||||
// Durable per-session prompt ordinals. prompt_seq is allocated from a
|
||||
// per-session sequence counter inside the create write boundary, so an
|
||||
@@ -397,7 +402,7 @@ func (r *Repository) runMigrations() error {
|
||||
task_session_id TEXT PRIMARY KEY,
|
||||
last_seq INTEGER NOT NULL
|
||||
)`)
|
||||
if err := r.backfillPromptSeq(); err != nil {
|
||||
if err := r.backfillPromptSeq(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -504,7 +509,7 @@ func (r *Repository) backfillTaskSessionQueueIncarnations() error {
|
||||
// session's sequence counter at its backfilled maximum. Idempotent: user rows
|
||||
// already carrying a nonzero prompt_seq are untouched, and the counter seed
|
||||
// ignores existing rows.
|
||||
func (r *Repository) backfillPromptSeq() error {
|
||||
func (r *Repository) backfillPromptSeq(ctx context.Context) error {
|
||||
nmU := dialect.NormalizedMicrosecond(r.db.DriverName(), "u.created_at")
|
||||
nmM := dialect.NormalizedMicrosecond(r.db.DriverName(), "task_session_messages.created_at")
|
||||
update := fmt.Sprintf(`
|
||||
@@ -516,7 +521,8 @@ func (r *Repository) backfillPromptSeq() error {
|
||||
AND (%s < %s OR (%s = %s AND u.id <= task_session_messages.id))
|
||||
)
|
||||
WHERE author_type = 'user' AND prompt_seq = 0`, nmU, nmM, nmU, nmM)
|
||||
ctx := r.migrationContext()
|
||||
startup.BeginStep(ctx, startup.StepPromptSeqBackfill)
|
||||
defer startup.EndStep(ctx, startup.StepPromptSeqBackfill)
|
||||
if _, err := r.db.ExecContext(ctx, update); err != nil {
|
||||
return fmt.Errorf("backfill prompt_seq: %w", err)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user