ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

FreeLLM API 数据库迁移全指南:从创建迁移到生产自动执行

FreeLLM API 数据库迁移全指南:从创建迁移到生产自动执行 FreeLLM API 数据库迁移全指南从创建迁移到生产自动执行【免费下载链接】freellmapi7.4 billion tokens per month. 34 free LLM providers. 635 free model endpoints. All behind one /v1 endpoint, plus any custom OpenAI-compatible endpoint. Smart routing, automatic failover, encrypted keys. Personal experimentation only.项目地址: https://gitcode.com/GitHub_Trending/fr/freellmapi本篇技术指南以 FreeLLM API 服务端server/的数据库迁移Database Migrations体系为核心完整讲解 schema 变更如何以迁移文件落地、如何用 npm 脚本创建与执行迁移、本地开发、测试与生产环境各自的迁移策略以及内置模型目录数据为何必须随迁移演进。读完本文你将掌握db:migration:create / up / down / fresh / status全套命令的用法与底层原理并理解迁移注册表、可逆性约定和防止漏注册的测试保障机制可以直接在自己的 fork 或二次开发中安全地修改数据库结构。一、迁移机制概览为什么 schema 变更必须走迁移文件FreeLLM API 服务端使用 SQLite 作为持久化存储默认数据库文件位于server/data/freeapi.db可用环境变量FREEAPI_DB_PATH覆盖其中保存着模型目录、加密后的 provider 密钥、统一 API Key、请求聚合统计、备份记录等核心数据。因为数据库文件分布在每个部署实例上任何表结构或内置数据的变更都不能只改代码而必须通过迁移migration文件逐版本推进。server/src/db/README.md开宗明义Schema changes belong in migration files undersrc/db/migrations/.从源码看这套迁移系统由三个部分组成见 server/src/db/migrate/迁移文件目录server/src/db/migrations/每一个.ts文件就是一个版本同时导出up(db)与down(db)两个函数执行器 runnerserver/src/db/migrate/runner.ts负责建migrations追踪表、按文件名顺序找出未应用的迁移并在事务中执行CLI 入口server/src/db/migrate/cli.ts把npm run db:migration:*脚本映射为up / down / fresh / status / create五个子命令。数据库连接层面见 server/src/db/index.ts在打开连接时还会做几件基础加固开启journal_mode WAL、foreign_keys ON、busy_timeout 5000让代理热路径与仪表盘的并发写入在争抢时等待而非直接SQLITE_BUSY失败并在启动阶段限制数据库文件及目录权限以保护加密密钥。二、迁移文件存放位置与版本命名规则所有迁移文件统一存放在server/src/db/migrations/目录下命名格式为YYYYMMDD_HHMMSS_description.ts其中时间戳使用UTC 时间见 cli.ts 中的 formatTimestamp。这种命名有双重作用天然排序执行器按文件名localeCompare排序后逐个应用文件名顺序即迁移顺序可追溯性一眼即可看出该迁移是哪个日期创建的。当前仓库共有 33 个迁移文件覆盖了从 2026-01-01 的 legacy 基线到 2026-09-03 的响应缓存表例如20260101_000000_legacy_baseline.ts—— 建表 模型种子数据的不可逆基线20260627_000001_custom_provider_modalities.ts—— 为 embedding/media 模型表补充key_id列20260903_000002_response_cache.ts—— 新增响应缓存表。注意文件名中带-d.ts的声明文件不会被当作迁移执行器在扫描时明确排除了.d.ts结尾的文件见 runner.ts。三、创建新迁移db:migration:create当需要修改表结构或内置数据时不要手写文件使用官方提供的脚手架命令npm run db:migration:create --nameadd_embedding_index3.1--name参数的清洗规则CLI 会从--name参数也支持npm_config_name环境变量读取描述并做清洗见 cli.ts 的 sanitiseMigrationName统一转小写连续空格或-合并为单个_删除所有非字母、数字、下划线字符折叠连续下划线并去除首尾下划线若清洗后不含任何字母或数字命令直接报错退出。因此--nameAdd Embedding Index最终会生成类似20260911_000000_add_embedding_index.ts的文件。3.2 脚手架做了什么执行create时见 cli.ts 的 createMigrationFileCLI 依次完成从 TEMPLATE.ts 读取模板内容把short description替换为原始--name、YYYY-MM-DD替换为当前 UTC 日期以wx标志写入server/src/db/migrations/目标文件已存在则报错防止覆盖自动更新迁移注册表defaults.ts生成 import 语句与注册条目追加到DEFAULT_MIGRATIONS数组末尾见 updateDefaultMigrationRegistry。第三步非常关键本仓库的执行器在默认情况下不会扫描目录而是遍历静态注册表DEFAULT_MIGRATIONS。如果只建了文件却没注册该迁移会被静默跳过。脚手架自动注册正是为了堵住这个最常见的失误详见下文第六节。3.3 迁移文件模板解析脚手架生成的模板内容如下TEMPLATE.ts// Migration: short description // Created: YYYY-MM-DD // // DOWN: reversible | irreversible - reason import type { Db } from ../types.js; export function up(db: Db): void { db.exec( -- your SQL here ); } export function down(db: Db): void { // If reversible: db.exec( -- inverse SQL here ); // If irreversible: // throw new Error(irreversible migration: reason); }每个迁移必须导出up(db)与down(db)两个函数二者都接收Db连接对象可以自由使用db.exec()执行 DDL、db.prepare()操作数据。模板头部要求作者显式标注该迁移是否可逆若不可逆down中应直接throw new Error(irreversible migration: reason)这样回滚时会有明确报错而不是静默产生错误结果。以真实迁移 20260627_000001_custom_provider_modalities.ts 为例它演示了幂等迁移的写法——每次先通过PRAGMA table_info检查列是否存在存在则跳过ALTER TABLEdown也做对称处理并且索引用IF NOT EXISTS/IF EXISTS兜底export function up(db: Db): void { addKeyIdColumn(db, embedding_models); addKeyIdColumn(db, media_models); db.prepare(CREATE INDEX IF NOT EXISTS idx_embedding_models_key_id ON embedding_models(key_id)).run(); db.prepare(CREATE INDEX IF NOT EXISTS idx_media_models_key_id ON media_models(key_id)).run(); }四、本地开发手动执行与回滚在本地开发环境中pending 迁移不会自动执行需要手动运行# 应用所有未执行的迁移 npm run db:migration:up # 回滚最近一个已应用的迁移 npm run db:migration:down # 查看哪些迁移已执行、哪些待执行 npm run db:migration:status三个命令分别对应 server/package.json 中的脚本定义底层都通过tsx src/db/migrate/cli.ts command调用 CLI。为什么开发环境不自动迁移看 initDb 的实现当NODE_ENV不是development时即生产与测试启动时同步执行全部迁移而development下只检查migrations表是否存在不存在则打印提示并退出进程[dev] Database not initialised. Run: npm run db:migration:up Then restart the server.这种设计的意图很明显开发中你随时可能在改迁移文件本身手动控制执行时机可以反复调试也能避免服务启动的隐式副作用掩盖问题。4.1status的输出db:migration:status通过 getMigrationStatuses 读取已应用记录并对照注册表逐一标记状态最终用console.table打印filenamestatusapplied_at20260101_000000_legacy_baseline.tsapplied2026-09-01 08:00:00.........20260903_000002_response_cache.tspending其中status只有applied与pending两种取值。4.2 底层执行语义up的执行逻辑在 runPendingMigrations确保migrations追踪表存在见下方 SQL读取已应用文件名集合按文件名顺序遍历注册表跳过已应用的对每个 pending 迁移在同一个 SQLite 事务里执行migration.up(db)然后插入(filename)记录。CREATE TABLE IF NOT EXISTS migrations ( id INTEGER PRIMARY KEY AUTOINCREMENT, filename TEXT NOT NULL UNIQUE, applied_at TEXT NOT NULL DEFAULT (datetime(now)) )迁移体与记录写入同事务意味着只要up中途抛错整个迁移回滚文件名也不会被标记下次运行会重新尝试不会出现执行了一半的中间态。down则取出migrations表中id最大即最近应用的一条找到对应模块后在同一事务中执行migration.down(db)并删除记录见 runLatestDownMigration。也就是说down是一次只回滚一个版本。五、生产环境启动时自动迁移生产启动时应用 pending 迁移是框架行为无需任何手工步骤。核心在 initDbif (process.env.NODE_ENV ! development) { runMigrationsSync(db, up); }由于生产路径使用同步执行器runMigrationsSync它要求注册表中的每个模块都直接携带module即编译后的静态 import因此生产构建npm run build产出dist/后迁移会以编译产物形式随服务发布启动时按文件名顺序一次性把 schema 推进到最新。两个值得注意的运维事实升级路径安全老部署升级到新版本时up会只执行尚未应用的增量迁移已存在的表结构不会被重复操作——前提是迁移按上文的幂等或基线约定编写切勿在生产手工跑fresh详见第七节。六、迁移注册表防止建了文件但没注册一个容易被忽略但极其重要的设计默认执行器不扫描migrations/目录而是遍历 defaults.ts 中静态声明的DEFAULT_MIGRATIONS数组。其注册形式如下import * as legacyBaseline from ../migrations/20260101_000000_legacy_baseline.js; // ... export const DEFAULT_MIGRATIONS: readonly DefaultMigration[] [ { filename: LEGACY_BASELINE_FILENAME, module: legacyBaseline }, // ... ];这样设计的原因在 registry-drift.test.ts 的注释 中写得很清楚The runner walks the static DEFAULT_MIGRATIONS list, not the directory, so a migration file that nobody registered is skipped in silence... Adding the file and forgetting the registry is the easy mistake — this makes it a failing test instead of a quiet no-op.即漏注册的迁移会无声地永不执行只在升级后的实例上以诡异症状暴露。为此仓库内置了两个注册表守卫测试磁盘上每个.ts迁移文件都必须在注册表中出现注册表必须严格按文件名升序排列与执行顺序一致。所以当你不通过脚手架、手动新增迁移文件时必须自己同步修改defaults.ts并跑一遍该测试完整测试见 registry-drift.test.ts。七、db:migration:fresh本地与测试专用生产禁止fresh用于把数据库重置到刚迁移完的可用状态。它的语义是先删掉所有业务表再从头跑全部迁移因此立即得到一份完整的全新 schemanpm run db:migration:fresh其实现cli.ts 的 runFresh第一行就是一个硬性守卫if (process.env.NODE_ENV production) { console.error(db:migration:fresh is not allowed in production); process.exit(1); }随后 dropAllUserTables 会关闭外键约束遍历sqlite_master中所有非sqlite_%前缀的表并DROP TABLE再执行up。这意味着本地开发当想从零重建数据库、或迁移文件改得面目全非时fresh是最快的重置方式测试每个测试 DB 希望从完整 schema 开始fresh语义与此一致生产它等价于清空数据库重来会毁掉所有密钥、统计与配置因此被代码层面强制禁止——即使你手滑执行进程也会直接退出。八、测试环境initDb 自动迁移每个测试库拿到完整 schemaserver/src/db/README.md明确指出Tests auto-run migrations frominitDb()so each test DB starts with the full schema.因为测试运行时的NODE_ENV不是development测试代码调用 initDb常以:memory:或临时文件为路径时runMigrationsSync 会同步应用全部迁移从而保证每个测试用例都基于完整、一致的 schema 运行无需测试自行建表。配套的迁移专项测试脚本在 server/package.json 中定义npm run test:migrations它执行src/__tests__/db/migrate/roundtrip.test.ts。这个 roundtrip往返测试是整个迁移体系正确性的核心保障覆盖三件事connectDb打开连接时不应自动迁移验证开发环境行为的分界legacy 基线可重放对旧库先跑基线再跑全部迁移验证增量迁移能正确修正旧数据如禁用失效的 opencode 促销模型全量往返跑完所有up→ 一路down回到只剩基线 → 再up一遍断言最终 schema 与数据快照与第一次完全一致见 roundtrip.test.ts。其中往返测试还对某迁移的down必须真的改变数据库状态或明确抛不可逆错误做了断言任何down写成空操作的迁移都会在测试中失败。九、内置模型目录数据住在迁移里README 特别强调Built-in model catalog rows live in migrations. Add, retire, or correct default models with a new forward migration.FreeLLM API 的模型目录包含 34 个免费 provider、635 个免费模型端点的内置默认数据并非来自外部文件而是由迁移脚本种入数据库。最大的例子就是 20260101_000000_legacy_baseline.ts约 2300 行它的up依次建表、初始化加密密钥、执行seedModels并串联了migrateModels到migrateModelsV25共 25 轮模型数据迭代最后调用applyModelPricing、初始化 embeddings/media/quirk 数据、生成统一 API Key。这意味着对默认模型的增删改add / retire / correct也必须以新增 forward migration 的形式提交而不是直接改基线文件——这样所有已部署实例升级时都能通过增量迁移收敛到同一份目录数据。需要注意的一点演进约束基线文件注释指出自 2026 年 6 月 Premium 实时目录catalog-sync上线后V25 是最后一个通过迁移推送模型数据的版本。此后模型/限额数据改由已发布的目录catalog经catalog-sync服务下发付费层约 12 小时内生效、免费层按月 promote迁移文件只承载 schema、家族规则、provider 管道与 quirk 修正等基线级变更。如果你的二次开发需要调整内置模型默认值请遵循同样的原则优先用新迁移增量修正避免回改历史基线。十、最佳实践与注意事项汇总最后把 README 与源码体现出的约定整理为可直接执行的 checklist关注点约定存放位置server/src/db/migrations/命名YYYYMMDD_HHMMSS_desc.tsUTC创建方式优先npm run db:migration:create --name描述自动生成模板并注册手动建文件必须同时更新 defaults.ts 注册表并跑registry-drift测试迁移内容必须导出up(db)/down(db)可逆迁移提供对称的down不可逆迁移在down中抛错幂等性涉及ALTER TABLE/CREATE INDEX时用PRAGMA table_infoIF NOT EXISTS检查避免重复执行报错本地开发db:migration:up/db:migration:down/db:migration:status手动控制生产部署启动时自动同步迁移NODE_ENV ! development无需手工干预测试测试库经initDb()自动获得完整 schema迁移正确性由npm run test:migrationsroundtrip守护重置db:migration:fresh仅限本地与测试代码层面禁止在NODE_ENVproduction下执行模型目录数据默认模型新增/退役/修正一律走新的 forward migration不改历史基线如需进一步深入建议按以下路径阅读源码先看 server/src/db/migrate/cli.ts 理解命令入口再看 server/src/db/migrate/runner.ts 掌握事务与追踪表逻辑随后通读 server/src/db/migrate/defaults.ts 熟悉注册表全貌最后用 roundtrip.test.ts 与 registry-drift.test.ts 验证自己对迁移语义的理解是否与实现一致。【免费下载链接】freellmapi7.4 billion tokens per month. 34 free LLM providers. 635 free model endpoints. All behind one /v1 endpoint, plus any custom OpenAI-compatible endpoint. Smart routing, automatic failover, encrypted keys. Personal experimentation only.项目地址: https://gitcode.com/GitHub_Trending/fr/freellmapi创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表