排查和调试使用 Hyperdrive 连接数据库时常见的错误。
创建新的 Hyperdrive 配置,或更新现有配置的连接参数时,Hyperdrive 会在后台对数据库执行测试连接,然后再创建或更新配置。
Hyperdrive 还会发出空测试查询(PostgreSQL 中为 ;),以验证能否将查询传递到数据库。
| 错误代码 | 详情 | 建议修复 |
|---|---|---|
2008 |
主机名无效。 | Hyperdrive 无法解析数据库主机名。确认其在公网 DNS 中存在。 |
2009 |
主机名未解析为公网 IP 地址,或 IP 地址不是公网地址。 | Hyperdrive 只能连接公网 IP 地址。目前不支持 10.1.5.0 或 192.168.2.1 等私有 IP 地址。 |
2010 |
无法连接到 host:port。 | Hyperdrive 无法路由到主机名:确保其有解析为公网 IP 的公网 DNS 记录。检查主机名是否拼写错误。 |
2011 |
连接被拒绝。 | 网络防火墙或访问控制列表(ACL)可能拒绝了来自 Hyperdrive 的请求。确保已允许来自公网的连接。 |
2012 |
数据库不支持 TLS(SSL)。 | Hyperdrive 连接需要 TLS(SSL)。请在数据库上配置 TLS。 |
2013 |
数据库凭据无效。 | 确保用户名正确(且存在),密码正确(区分大小写)。 |
2014 |
指定的数据库名称不存在。 | 检查你提供的数据库(非表)名称是否存在于 Hyperdrive 要连接的数据库上。 |
2015 |
通用错误。 | Hyperdrive 连接失败且无法确定原因。请提交支持工单以便 Cloudflare 调查。 |
2016 |
测试查询失败。 | 确认 Hyperdrive 连接使用的用户对给定数据库具有读写查询权限。 |
尝试创建 Hyperdrive 配置时,Hyperdrive 也可能发出 Failed to connect to the provided database(无法连接到提供的数据库)。当 TLS(SSL)证书配置错误时可能出现此情况。以下是连接失败错误的非详尽列表:
| 错误消息 | 详情 | 建议修复 |
|---|---|---|
| Server return error and closed connection. | 尝试连接启用了客户端证书验证的数据库时出现此消息。 | 若数据库需要客户端证书,请确保 Hyperdrive 配置了客户端证书。 |
| TLS handshake failed: cert validation failed. | 当 Hyperdrive 配置了服务器 CA 证书,且表明服务器提供的证书未被预期的 CA 证书签名时出现此消息。 | 确保 Hyperdrive 使用正确的 CA 证书,或确保连接的是正确的数据库。 |
Hyperdrive 还可能在运行时返回错误。这可能发生在初始连接建立期间,或响应驱动发送的查询或其他 wire 协议命令时。
这些错误以 ErrorResponse wire 协议消息返回,大多数驱动通过从相关查询抛出异常或触发 error 事件来处理。
未与 PostgreSQL 文档 ↗ 中记录的错误消息代码一一对应的 Hyperdrive 错误使用 58000 错误代码。
Hyperdrive 还可能遇到数据库发送的 ErrorResponse wire 协议消息。Hyperdrive 会在可能的情况下原样传递这些错误。
| 错误消息 | 详情 | 建议修复 |
|---|---|---|
Internal error. |
Cloudflare 端出现问题。 | 检查是否有影响 Hyperdrive 的持续事件,并联系 Cloudflare 支持。若符合使用模式,可重试查询。 |
Failed to acquire a connection from the pool. |
Hyperdrive 等待数据库连接超时,或完全无法连接。 | 若此错误间歇出现,Hyperdrive 连接池已耗尽,因为 Worker 持有过多连接时间过长。可能由多种问题引起,但长时间运行的查询/事务是常见原因。 |
Server connection attempt failed: connection_refused |
Hyperdrive 无法创建到源数据库的新连接。 | 网络防火墙或访问控制列表(ACL)可能拒绝了来自 Hyperdrive 的请求。确保已允许来自公网的连接。有时,当超出连接限制时,数据库主机提供商可能拒绝传入连接。 |
Hyperdrive does not currently support MySQL COM_STMT_PREPARE messages |
Hyperdrive 不支持 MySQL 数据库的预处理语句。 | 从 MySQL 查询中移除预处理语句。 |
| 错误消息 | 详情 | 建议修复 |
|---|---|---|
Uncaught Error: No such module "node:<module>" |
Cloudflare Workers 项目或其导入的库尝试访问不可用的 Node 模块。 | 为 Cloudflare Workers 项目启用 Node.js 兼容性 以最大化兼容性。 |
若应用写入数据后后续读取返回较旧数据,Hyperdrive 查询缓存可能正在提供缓存的读查询结果。按 cacheStatus 检查 Hyperdrive 指标,确认读取返回 hit、miss、disabled 或 uncacheable。请参阅指标与分析。
要解决写入后读取到旧数据的问题,请参阅查询缓存指南,了解如何将新鲜读取与可缓存读取分离,包括为必须返回新鲜数据的读取使用禁用缓存的 Hyperdrive 配置。
若 Hyperdrive 已启用缓存但查询未被缓存,请检查以下项:
-
查询中包含稳定或易变 PostgreSQL 函数:包含分类为
STABLE或VOLATILE的 PostgreSQL 函数的查询不可缓存。常见示例包括NOW()、CURRENT_TIMESTAMP、CURRENT_DATE、RANDOM()和LASTVAL()。解决方法是将函数调用移至应用代码并将结果作为查询参数传递。例如,不要写WHERE created_at > NOW(),而是在 Worker 中计算时间戳并作为参数传递:WHERE created_at > $1。请参阅查询缓存获取完整的不可缓存函数列表。 -
SQL 注释中的函数名称:Hyperdrive 使用基于文本的模式匹配来检测某些不可缓存函数。SQL 注释中对
NOW()等函数名称的引用可能导致查询被视为不可缓存,即使函数未被实际调用。从查询文本(包括注释)中移除对不可缓存函数名称的引用。 -
驱动配置:驱动可能配置为 Hyperdrive 无法缓存查询。例如,使用 Postgres.js ↗ 驱动并设置
prepare: false↗ 时可能发生。解决方法是使用prepare: true启用预处理语句。
| 错误消息 | 详情 | 建议修复 |
|---|---|---|
Code generation from strings disallowed for this context |
你使用的数据库驱动尝试使用 eval() 命令,Cloudflare Workers 不支持(mysql2 驱动中常见)。 |
配置数据库驱动不使用 eval()。请参阅如何配置 mysql2 禁用 eval() 用法。 |
当数据库客户端或连接在全局作用域(请求处理程序之外)创建,或在请求间复用时,会出现这些错误。Workers 不允许跨请求 I/O,来自先前请求上下文的数据库连接将不可用。始终在处理程序内创建数据库客户端。
| 错误消息 | 详情 | 建议修复 |
|---|---|---|
Disallowed operation called within global scope. Asynchronous I/O (ex: fetch() or connect()), setting a timeout, and generating random values are not allowed within global scope. |
Worker 在脚本启动期间(请求处理程序之外)尝试打开数据库连接或执行 I/O。 | 将数据库客户端创建移至 fetch、queue 或其他处理程序函数中。 |
Cannot perform I/O on behalf of a different request. I/O objects (such as streams, request/response bodies, and others) created in the context of one request handler cannot be accessed from a different request's handler. |
在一个请求期间创建的数据库连接或客户端在后续请求中被复用。 | 每个请求创建新的数据库客户端,而非缓存在全局变量中。Hyperdrive 的连接池已消除连接启动开销。 |
| 错误消息 | 详情 | 建议修复 |
|---|---|---|
Connection terminated |
调用了客户端的 .end() 方法,或连接在先前请求结束时被清理。 |
在处理程序内创建新的 Client,而非复用先前请求的客户端。 |
Connection terminated unexpectedly |
底层连接在没有显式 .end() 调用的情况下断开——例如,先前请求的上下文被垃圾回收时。 |
每个请求在处理程序内创建新的 Client。 |
Client has encountered a connection error and is not queryable |
连接上发生套接字级错误(跨请求复用客户端时常见)。 | 在处理程序内创建新的 Client。不要将客户端存储在全局变量中。 |
Client was closed and is not queryable |
在已调用 .end() 的客户端上尝试查询。 |
在处理程序内创建新的 Client,而非复用已有客户端。 |
Cannot use a pool after calling end on the pool |
在已结束的 Pool 实例上调用 pool.connect()。 |
不要在全局作用域使用 new Pool()。在处理程序内创建 new Client()——Hyperdrive 会为你处理连接池。 |
Client has already been connected. You cannot reuse a client. |
在先前调用中已连接的客户端上调用 client.connect()。 |
每个请求创建新的 Client。node-postgres 客户端连接后无法重新连接。 |
Postgres.js 错误消息包含错误代码和目标主机。错误对象的 code 属性包含错误代码。
| 错误消息 | 详情 | 建议修复 |
|---|---|---|
write CONNECTION_ENDED <host>:<port> |
在调用 sql.end() 后或连接从先前请求清理后尝试查询。错误代码:CONNECTION_ENDED。 |
在处理程序内创建新的 postgres() 实例。 |
write CONNECTION_DESTROYED <host>:<port> |
连接被强制终止——例如在 sql.end({ timeout }) 过期期间,或因为连接已被终止。错误代码:CONNECTION_DESTROYED。 |
每个请求在处理程序内创建新的 postgres() 实例。 |
write CONNECTION_CLOSED <host>:<port> |
底层套接字在仍有待处理查询时意外关闭。错误代码:CONNECTION_CLOSED。 |
在处理程序内创建新的 postgres() 实例。若此错误在单个请求内出现,请检查网络问题或查询超时。 |
| 错误消息 | 详情 | 建议修复 |
|---|---|---|
Can't add new command when connection is in closed state |
在已关闭或遇到致命错误的连接上尝试查询。 | 在处理程序内创建新连接,而非从全局作用域复用连接。 |
Connection lost: The server closed the connection. |
底层套接字被服务器关闭或在请求间被垃圾回收。错误代码:PROTOCOL_CONNECTION_LOST。 |
每个请求在处理程序内创建新连接。 |
Pool is closed. |
在已关闭的连接池上调用 pool.getConnection()。 |
不要在全局作用域使用 createPool()。在处理程序内创建新的 createConnection()——Hyperdrive 会为你处理连接池。 |
| 错误消息 | 详情 | 建议修复 |
|---|---|---|
Cannot enqueue Query after fatal error. |
在先前遇到致命错误的连接上尝试查询。错误代码:PROTOCOL_ENQUEUE_AFTER_FATAL_ERROR。 |
在处理程序内创建新连接,而非从全局作用域复用连接。 |
Cannot enqueue Query after invoking quit. |
在调用 .end() 后的连接上尝试查询。错误代码:PROTOCOL_ENQUEUE_AFTER_QUIT。 |
每个请求在处理程序内创建新连接。 |
Cannot enqueue Handshake after already enqueuing a Handshake. |
在先前请求中已连接的连接上调用 .connect()。错误代码:PROTOCOL_ENQUEUE_HANDSHAKE_TWICE。 |
每个请求创建新连接。mysql 连接连接后无法重新连接。 |
将查询流量写为事务可能限制性能。因为在事务情况下,连接必须在整个事务期间保持,这会限制连接多路复用。若每个事务包含多个查询,对连接多路复用的影响可能尤为显著。建议在可能的情况下不要将查询包装在事务中,以便更积极地共享连接。