Skip to content

Fix cloudflare build#360

Closed
henryz78 wants to merge 7 commits into
mtvpls:mainfrom
henryz78:fix-cloudflare-build
Closed

Fix cloudflare build#360
henryz78 wants to merge 7 commits into
mtvpls:mainfrom
henryz78:fix-cloudflare-build

Conversation

@henryz78

@henryz78 henryz78 commented Jun 7, 2026

Copy link
Copy Markdown

📖 问题背景

解决在使用 Cloudflare Pages / Workers (OpenNext) 部署时,pnpm run build:cloudflare(Next.js 静态预编译阶段)出现以下报错导致构建失败的问题:

ERROR: getCloudflareContext has been called in sync mode in either a static route or at the top level of a non-static one

🔍 原因分析

D1StoragePostgresStorage 的构造函数中,原先同步调用了 this.schemaReady = this.ensureMangaShelfColumns();
这导致 Next.js 在构建期静态编译 API 路由导入该模块时,会立即实例化存储并向代理数据库发起 prepare 请求,从而在构建环境中触发了 getCloudflareContext()。由于构建期没有活的请求上下文,该方法同步调用便会报错。

🛠️ 解决方案

schemaReady 变量改造为惰性加载的属性访问器 (Lazy Getter)。
只有在运行时(有真正请求进来时)调用漫画书架等需要保障表结构完整的方法时,才会触发 ensureMangaShelfColumns()。由此避开了 Next.js 编译构建期间对 Cloudflare 运行环境绑定的同步访问。

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces configuration caching in the admin config route and refactors both D1Storage and PostgresStorage to lazily initialize the database schema (schemaReady) instead of eagerly doing so in the constructor. The review feedback points out a critical issue in both storage implementations: since ensureMangaShelfColumns internally catches and swallows all exceptions, the .catch block in the new lazy getters will never be triggered. This can cause _schemaReady to cache a resolved Promise even if the schema setup failed, preventing subsequent retries and leading to persistent database errors.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread src/lib/d1.db.ts
Comment on lines +45 to +53
private get schemaReady(): Promise<void> {
if (!this._schemaReady) {
this._schemaReady = this.ensureMangaShelfColumns().catch((err) => {
this._schemaReady = null;
throw err;
});
}
return this._schemaReady;
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

由于 ensureMangaShelfColumns 方法内部捕获了所有异常且未向上抛出,因此 schemaReady getter 中的 .catch 分支实际上永远不会被触发。如果数据库在首次请求时由于临时网络抖动或未就绪而导致列添加失败,_schemaReady 仍会被缓存为一个已成功解析的 Promise。这会导致后续所有对漫画书架的访问都默认列已存在,从而引发持续的数据库错误,且无法自动重试。\n\n建议修改 ensureMangaShelfColumns,使其在遇到非预期错误(如连接失败等非“列已存在”的错误)时向上抛出异常,以便 lazy getter 能够正确重置 _schemaReady 并在下一次请求时重试。

Comment thread src/lib/postgres.db.ts
Comment on lines +46 to +54
private get schemaReady(): Promise<void> {
if (!this._schemaReady) {
this._schemaReady = this.ensureMangaShelfColumns().catch((err) => {
this._schemaReady = null;
throw err;
});
}
return this._schemaReady;
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

由于 ensureMangaShelfColumns 方法内部捕获了所有异常且未向上抛出,因此 schemaReady getter 中的 .catch 分支实际上永远不会被触发。如果数据库在首次请求时由于临时网络抖动或未就绪而导致列添加失败,_schemaReady 仍会被缓存为一个已成功解析的 Promise。这会导致后续所有对漫画书架的访问都默认列已存在,从而引发持续的数据库错误,且无法自动重试。\n\n建议修改 ensureMangaShelfColumns,使其在遇到非预期错误(如连接失败等非“列已存在”的错误)时向上抛出异常,以便 lazy getter 能够正确重置 _schemaReady 并在下一次请求时重试。

@henryz78 henryz78 force-pushed the fix-cloudflare-build branch 2 times, most recently from 06fd669 to 242ed1f Compare June 8, 2026 04:39
@henryz78 henryz78 closed this Jun 8, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant