Add guide for downgrading versions (#2588)

* add downgrading guide and migrate cmd

* cleanup
This commit is contained in:
Mohammed Nafees
2025-12-08 16:48:01 +05:30
committed by GitHub
parent 44b3619bd8
commit 5f7b149b5b
4 changed files with 211 additions and 1 deletions
+13 -1
View File
@@ -11,6 +11,7 @@ import (
)
var printVersion bool
var migrateDown string
// rootCmd represents the base command when called without any subcommands
var rootCmd = &cobra.Command{
@@ -26,7 +27,11 @@ var rootCmd = &cobra.Command{
ctx, cancel := cmdutils.NewInterruptContext()
defer cancel()
migrate.RunMigrations(ctx)
if migrateDown != "" {
migrate.RunDownMigration(ctx, migrateDown)
} else {
migrate.RunMigrations(ctx)
}
},
}
@@ -41,6 +46,13 @@ func main() {
"print version and exit.",
)
rootCmd.PersistentFlags().StringVar(
&migrateDown,
"down",
"",
"migrate down to a specific version (e.g., 20240115180414).",
)
if err := rootCmd.Execute(); err != nil {
fmt.Println(err)
os.Exit(1)
+106
View File
@@ -326,3 +326,109 @@ func listMigrations() (goose.Migrations, error) {
return goose.CollectMigrations(".", minVersion, maxVersion)
}
// RunDownMigration runs down migrations to a specific version.
func RunDownMigration(ctx context.Context, targetVersion string) {
if err := runDownMigrationImpl(ctx, targetVersion); err != nil {
log.Fatalf("goose: %v", err)
}
}
func runDownMigrationImpl(ctx context.Context, targetVersion string) error {
var db *sql.DB
var conn *sql.Conn
retryCtx, cancel := context.WithTimeout(ctx, 30*time.Second)
err := retry.Do(retryCtx, retry.NewConstant(1*time.Second), func(ctx context.Context) error {
var err error
if db == nil {
db, err = goose.OpenDBWithDriver("postgres", os.Getenv("DATABASE_URL"))
if err != nil {
return retry.RetryableError(fmt.Errorf("failed to open DB: %w", err))
}
}
conn, err = db.Conn(ctx)
if err != nil {
return retry.RetryableError(fmt.Errorf("failed to open DB connection: %w", err))
}
return nil
})
cancel()
if err != nil {
return fmt.Errorf("failed to open DB: %w", err)
}
defer func() {
if conn != nil {
if err := conn.Close(); err != nil {
log.Printf("goose: failed to close DB connection: %v", err)
}
}
if db != nil {
if err := db.Close(); err != nil {
log.Printf("goose: failed to close DB: %v", err)
}
}
}()
locker, err := lock.NewPostgresSessionLocker()
if err != nil {
return fmt.Errorf("failed to create locker: %w", err)
}
err = locker.SessionLock(ctx, conn)
if err != nil {
return fmt.Errorf("failed to lock session: %w", err)
}
defer func() {
if err := locker.SessionUnlock(ctx, conn); err != nil {
log.Printf("goose: failed to unlock session: %v", err)
}
}()
fsys, err := fs.Sub(embedMigrations, "migrations")
if err != nil {
return fmt.Errorf("failed to create sub filesystem: %w", err)
}
goose.SetBaseFS(fsys)
targetVersionInt, err := strconv.ParseInt(targetVersion, 10, 64)
if err != nil {
return fmt.Errorf("invalid target version %s: %w", targetVersion, err)
}
currentVersion, err := goose.GetDBVersion(db)
if err != nil {
return fmt.Errorf("failed to get current database version: %w", err)
}
if currentVersion < targetVersionInt {
return fmt.Errorf("target version %d is higher than current version %d. Use standard migration (without --down flag) to upgrade", targetVersionInt, currentVersion)
}
if currentVersion == targetVersionInt {
fmt.Printf("Database is already at version %d. No migration needed.\n", targetVersionInt)
return nil
}
fmt.Printf("Migrating down from version %d to version %d\n", currentVersion, targetVersionInt)
err = goose.DownTo(db, ".", targetVersionInt)
if err != nil {
return fmt.Errorf("failed to migrate down to version %d: %w", targetVersionInt, err)
}
fmt.Printf("Successfully migrated down to version %d\n", targetVersionInt)
return nil
}
@@ -28,6 +28,7 @@ export default {
},
},
"worker-configuration-options": "Worker Configuration Options",
"downgrading-versions": "Downgrading Versions",
benchmarking: "Benchmarking",
"data-retention": "Data Retention",
"improving-performance": "Improving Performance",
@@ -0,0 +1,91 @@
import { Callout } from "nextra/components";
# Downgrading Hatchet Versions
This guide explains how to safely downgrade your Hatchet instance to a previous version.
<Callout type="warning">
Downgrading may result in data loss. Always test downgrades in a
non-production environment first.
</Callout>
## Overview
Downgrading Hatchet involves two steps:
1. Running down migrations to revert database schema changes
2. Deploying the older Hatchet version
## Prerequisites
- **Critical:** Backup your database before downgrading
- Ensure the target version supports the current data in your database
- Have access to run `hatchet-migrate` command
- Verify that all migrations between your current version and target version have down migrations
## Finding the Target Migration Version
To downgrade to a specific Hatchet version, you need to identify the last migration that was included in that version.
Visit the Hatchet GitHub repository for your target version:
```
https://github.com/hatchet-dev/hatchet/tree/{GIT_TAG}/cmd/hatchet-migrate/migrate/migrations
```
Replace `{GIT_TAG}` with your target version (e.g., `v0.71.0`).
Find the last migration file in that directory - the timestamp at the beginning of the filename is your target migration version.
**Example:**
- Target Hatchet version: `v0.71.0`
- Last migration file: `20250813183355_v1_0_36.sql`
- Migration version: `20250813183355`
## Running Down Migrations
<Callout type="info">
Use a stable release of the `hatchet-migrate` binary (avoid alpha tags) from
the [Hatchet releases page](https://github.com/hatchet-dev/hatchet/tags) to
ensure down migrations work correctly.
</Callout>
Once you have identified the target migration version, use the `hatchet-migrate` command with the `--down` flag:
```bash
hatchet-migrate --down 20241023223039
```
This will:
1. Connect to your database using the `DATABASE_URL` environment variable
2. Check the current migration version
3. Run all down migrations from the current version to the target version
4. Display progress and confirm when complete
## Deploying the Older Version
After successfully running the down migrations, deploy the older Hatchet version:
### Docker Compose
Update your `docker-compose.yml`:
```yaml
services:
hatchet-engine:
image: ghcr.io/hatchet-dev/hatchet/hatchet-engine:v0.71.0
# ... rest of configuration
hatchet-dashboard:
image: ghcr.io/hatchet-dev/hatchet/hatchet-dashboard:v0.71.0
# ... rest of configuration
```
Then restart:
```bash
docker-compose down
docker-compose up -d
```