golang-migrate - 如果数据库有更新的迁移版本则跳过迁移

golang-migrate - skip migrations if DB has newer migration version

我有一个场景,如果我回滚到我的应用程序的以前版本,迁移步骤将失败并出现有关缺少脚本的错误,例如。 error: no migration found for version 10 error: file does not exist

我不想回滚数据库更改,只是跳过 运行 在这种情况下的迁移步骤。

我已经尝试在我的 entrypoint.sh 代码中实现一个简单的检查;但是,golang-migrate 似乎没有提供通过 cli 检索(和保留)数据库迁移版本的方法。

我在下面的示例中尝试了 version 命令,它打印了当前版本。但是,该值无法保存到变量中 - 我认为该命令在 运行 之后与数据库断开连接并擦除检索到的版本。

#!/bin/bash

set -euo pipefail

MIGRATION_COUNT=$(find /app/config/db/migrations/*.up.sql | wc -l)
echo 'MIGRATION_COUNT: ' $MIGRATION_COUNT

CURRENT_VERSION=$(/app/migrate -source=file:///app/config/db/migrations/ -database=<connection_string> version)
echo 'CURRENT_VERSION: ' $CURRENT_VERSION

if [ "$MIGRATION_COUNT" -gt "$CURRENT_VERSION" ]; then
  /app/migrate \
  -source=file:///app/config/db/migrations/ \
  -database=<connection_string> \
  up
fi

/app/my-app

上面脚本的输出(你可以看到当前版本是10打印但不保存到CURRENT_VERSION变量):

Attaching to my_app
my_app     | MIGRATION_COUNT:  9
my_app     | 10
my_app     | CURRENT_VERSION:  [2021-09-06T03:00:55.8023451Z] [INFO] [app=myapp-migrate] Migrating database{"host":"db","port":5432,"dbname":"myappname","user":"myapp","password":"XXXXX","tls":{"mode":"disable"},"maxconn":25,"maxidle":3}
my_app     | /app/entrypoint.sh: line 11: [: [2021-09-06T03:00:55.8023451Z] [INFO] [app=myapp-migrate] Migrating database{"host":"db","port":5432,"dbname":"myappname","user":"myapp","password":"XXXXX","tls":{"mode":"disable"},"maxconn":25,"maxidle":3}: integer expression expected

想知道是否有人知道如何在 bash 脚本中检索当前版本。如果没有,是否有另一种方法来实现迁移步骤的跳过?我无法使用 golang-migrate library

为这种逻辑找到任何选项

要解决这个问题,您必须首先了解 $() ONLY captures stdout。因此,如果您执行一个将结果写入标准输出的函数,那么您的解决方案是完全正确的并且可以工作。由于您的解决方案对我来说似乎是正确的,因此我查看了您正在使用的工具中的代码,您瞧,他们正在做一些相当混乱的事情。据我所知,几乎所有的输出,无论是正常的还是错误的,都是通过使用 Go 的 log 包编写的。然而,日志包有 属性 默认情况下使用通道 stderr 而不是 stdout - 当然是正确的。

Here 是他们(go-migrate)对 Println 函数的实现,他们使用该函数来打印您要捕获的版本字符串。

因此,与 go-migrate 的开发人员相比,您的错误更少。按照惯例,只有错误应该写入 stderr,一般输出(例如您的版本号)应该写入 stdout。

无论如何要解决这个问题,您可以尝试这样的事情:

CURRENT_VERSION=$(/app/migrate -source=file:///app/config/db/migrations/ -database=<connection_string> version 2>&1)

Note: This solution is NOT safe because you are now sending stderr in stdout and so you may be capturing real errors in the variable and not just the version number. So be careful!