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

huangapple go评论84阅读模式
英文:

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 检索(并保留)DB 迁移版本的方法。

有一个 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 库实现此类逻辑的任何选项。

英文:

I have a scenario where if I rollback to a previous version of my application the migration step will fail with errors regarding missing script eg. error: no migration found for version 10 error: file does not exist

I do not wish to rollback the DB changes, but simply skip running the migration step in this scenario.

I have tried implementing a simple check in my entrypoint.sh code; however, golang-migrate does not seem to provide a way to retrieve (and retain) the DB migration version via the cli.

There is the version command which I tried in my below example which prints the current version. However, that value cannot be saved to a variable - I think the command disconnects from the DB after running and wipes away the retrieved version.

#!/bin/bash

set -euo pipefail

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

CURRENT_VERSION=$(/app/migrate -source=file:///app/config/db/migrations/ -database=&lt;connection_string&gt; version)
echo &#39;CURRENT_VERSION: &#39; $CURRENT_VERSION

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

/app/my-app

The output of above script (you can see the current version is 10 does print but does not save to the CURRENT_VERSION variable):

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{&quot;host&quot;:&quot;db&quot;,&quot;port&quot;:5432,&quot;dbname&quot;:&quot;myappname&quot;,&quot;user&quot;:&quot;myapp&quot;,&quot;password&quot;:&quot;XXXXX&quot;,&quot;tls&quot;:{&quot;mode&quot;:&quot;disable&quot;},&quot;maxconn&quot;:25,&quot;maxidle&quot;:3}
my_app     | /app/entrypoint.sh: line 11: [: [2021-09-06T03:00:55.8023451Z] [INFO] [app=myapp-migrate] Migrating database{&quot;host&quot;:&quot;db&quot;,&quot;port&quot;:5432,&quot;dbname&quot;:&quot;myappname&quot;,&quot;user&quot;:&quot;myapp&quot;,&quot;password&quot;:&quot;XXXXX&quot;,&quot;tls&quot;:{&quot;mode&quot;:&quot;disable&quot;},&quot;maxconn&quot;:25,&quot;maxidle&quot;:3}: integer expression expected

Wondering if anyone knows how I can retrieve the current version in the bash script. If not, is there another way to implement the skipping of the migration step? I was not been able to find any options for that sort of logic using golang-migrate library

答案1

得分: 1

为了解决这个问题,你首先必须明白$()只能捕获标准输出(stdout)。所以,如果你执行一个将结果写入标准输出的函数,你的解决方案是完全正确的,并且可以工作。由于你的解决方案在我看来是正确的,我查看了你正在使用的工具的代码,结果发现他们做了一些混乱的事情。据我所见,几乎每个输出,无论是普通输出还是错误输出,都是通过使用Go的log包来写入的。然而,log包的特性是默认使用stderr通道而不是stdout通道,这当然是正确的。

这里是他们(go-migrate)实现的Println函数的代码,他们用它来打印你试图捕获的版本字符串。

所以错误不在于你,而在于go-migrate的开发人员。按照惯例,只有错误应该写入stderr,而像你的情况下的版本号这样的一般输出应该写入stdout。

为了绕过这个问题,你可以尝试像这样的解决方案:

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

注意:这个解决方案并不安全,因为现在你将stderr发送到了stdout,所以你可能会捕获到真正的错误而不仅仅是版本号。所以要小心!

英文:

To solve this, you must first understand that $() ONLY captures stdout. So if you execute a function that writes its result to stdout, your solution is perfectly correct and would work. Since your solution seemed correct to me, I looked at the code from the tool you are using and lo and behold, they are doing something rather messy. As far as I can see, almost every output no matter if regular or error is written through the use of Go's log package. However, the log package has the property to use the channel stderr instead of stdout by default - correctly of course.

Here is their (go-migrate's) implementation of the Println function that they use to print the version string that you're trying to capture.

So the error is less with you than with the developers of go-migrate. By convention, only errors should be written to stderr and general output such as the version number in your case should be written to stdout.

To work around this anyway, you could try something like this:

CURRENT_VERSION=$(/app/migrate -source=file:///app/config/db/migrations/ -database=&lt;connection_string&gt; version 2&gt;&amp;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!

<h1></h1>

huangapple
  • 本文由 发表于 2021年9月6日 11:13:12
  • 转载请务必保留本文链接:https://go.coder-hub.com/69068781.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定