DTeam 技术日志

Doer、Delivery、Dream

排错:Drizzle ORM 在多分支开发场景下,发现产品环境缺失 migrate 记录

冯宇 Posted at — Sep 14, 2023 阅读

症状

我们在多分支开发场景下,发现在不同分支下生成 migrate 文件之后,由于发布周期不同会导致有些脚本得不到执行。

例如在 hotfix 分支下创建了一个 0004_even_cyclops.sql 脚本,并且紧急合并到产品环境发布,后在主线分支上创建另一个 migrate 脚本 0004_bumpy_katie_power.sql,生成的 drizzle/ 目录如下:

drizzle
├── 0000_calm_talos.sql
├── 0001_reflective_malice.sql
├── 0002_careful_northstar.sql
├── 0003_blushing_martin_li.sql
├── 0004_bumpy_katie_power.sql
├── 0004_even_cyclops.sql
├── 0006_luxuriant_bloodscream.sql
└── meta
    ├── 0000_snapshot.json
    ├── 0001_snapshot.json
    ├── 0002_snapshot.json
    ├── 0003_snapshot.json
    ├── 0004_snapshot.json
    ├── 0006_snapshot.json
    └── _journal.json

则最终合并分支之后再次发布到产品环境,发现 0004_bumpy_katie_power.sql 始终得不到执行。

对比了下产品环境数据库和本地数据库的 drizzle.__drizzle_migrations 表记录,也可以验证这一点:

# select * from drizzle.__drizzle_migrations;
 id |                               hash                               |  created_at
----+------------------------------------------------------------------+---------------
  1 | 73e00ad97a659f73bd51194eeee283d667f14d6b0b9de5b4d5490f3619bf14e4 | 1687266312031
  2 | 7bdb1311c466d102f24d535d7734813d9a0facc72b68d306f1b2c3e32cba3842 | 1688633592510
  3 | 31948976f9c8d9575e60e1f8b26f974ca368692cbffd03b9d4a5f55467cbb67a | 1690341446264
  4 | d23bbcfbdd0079d83c75104679690e7c4e119bbb0fbbc830dc99f7fa73510964 | 1692003212319
  5 | cfc87892e506ede48fba2481456cf59a43d4eec8973a28e72376b1d627d93944 | 1692870925275   #<==== 产品环境缺失这条记录
  6 | bdd1b7528769c2019e1e7359d10f82dca0e3d8e90f6858b197cb3a8c826a42ef | 1693282336886
  7 | 82ed06acbb97c6ff42db7e8abda50a00e1ed914249ec3ca3adf6d08c4f3fdb2c | 1693794387936
(7 行记录)

发现产品环境确实少了中间一条 migrate hash 记录。

原因

通过打开 drizzle 的日志,我们发现了端倪:

// 打开 drizzle 的日志
const db = drizzle(sql, { logger: true });

migrate(db, { migrationsFolder: "drizzle" }).then(() => sql.end());

执行 migrate 的时候输出如下:

Query: CREATE SCHEMA IF NOT EXISTS "drizzle"
Query:
			CREATE TABLE IF NOT EXISTS "drizzle"."__drizzle_migrations" (
				id SERIAL PRIMARY KEY,
				hash text NOT NULL,
				created_at bigint
			)

Query: select id, hash, created_at from "drizzle"."__drizzle_migrations" order by created_at desc limit 1
Query: begin
Query: commit

我们发现 drizzle orm 在执行 migrate 的时候,并不是通过比对每一个 migrate 脚本的 hash 值来判断是否执行,而是通过查询 __drizzle_migrations 表的最后一条记录的 hash 值来判断是否执行。

这样就会导致这样的问题:

  1. hotfix 分支先发布,也就先执行了 0004_even_cyclops.sql,并且记录了 hash 值
  2. 但是主线分支的 0004_bumpy_katie_power.sql,实际生成在前,但是并没有发布到发布分支上执行,也就没有记录 hash 值
  3. 最终由于 drizzle 的算法 —— 只会比对最后一条记录的 hash 值,所以 0004_bumpy_katie_power.sql 始终得不到执行

解决

最终,我们通过手动修复 migrate 的方案解决这个问题。

本地用空库重新生成 drizzle.__drizzle_migrations 表的记录,将这个表记录同步到产品环境中。

如果产品环境数据库可以在本地连接 (例如通过 ssh tunnel 等方式或直连),可以直接通过 drizzle-kit push:pg 同步 schema 到产品环境。否则只能在产品环境手工执行缺失的 migrate 脚本。

关于这个问题,我已经给官方提交了 issue,希望后续可以解决: [FEATURE]:Support multiple branch development ?

觉得有帮助的话,不妨考虑购买付费文章来支持我们 🙂 :

付费文章

友情链接


相关文章