← Hyperdrive (Postgres & MySQL) / hyperdrive / observability
Диагностика и отладка
Диагностика и устранение ошибок, которые чаще всего возникают при подключении к базе данных через Hyperdrive.
Ошибки конфигурации
При создании новой конфигурации Hyperdrive или обновлении параметров подключения для существующей конфигурации Hyperdrive перед созданием или обновлением конфигурации выполняет в фоновом режиме тестовое подключение к базе данных.
Hyperdrive также отправит пустой тестовый запрос, а именно ; в PostgreSQL, чтобы убедиться, что он может передавать запросы в вашу базу данных.
| Код ошибки | Подробности | Рекомендуемые исправления |
|---|---|---|
2008 |
Неверное имя хоста. | Hyperdrive не удалось определить хост базы данных по имени. Убедитесь, что он существует в публичном DNS. |
2009 |
Имя хоста не разрешается в публичный IP-адрес, либо указанный IP-адрес не является публичным. | Hyperdrive может подключаться только к публичным IP-адресам. Приватные IP-адреса, такие как 10.1.5.0 или 192.168.2.1, в настоящее время не поддерживаются. |
2010 |
Не удаётся подключиться к host:port. | Hyperdrive не удалось проложить маршрут до хоста: убедитесь, что для него есть публичная DNS-запись, указывающая на публичный IP-адрес, и что имя хоста указано без опечаток. |
2011 |
В соединении отказано. | Скорее всего, запросы от Hyperdrive отклоняет межсетевой экран или список контроля доступа (ACL). Убедитесь, что вы разрешили подключения из публичного интернета. |
2012 |
База данных не поддерживает TLS (SSL). | Для подключения Hyperdrive требуется TLS (SSL). Настройте TLS в своей базе данных. |
2013 |
Недействительные учетные данные базы данных. | Убедитесь, что имя пользователя указано верно (и существует), а пароль правильный (с учётом регистра). |
2014 |
Указанное имя базы данных не существует. | Убедитесь, что указанное вами имя базы данных (не таблицы) существует в той базе данных, к которой должен подключиться Hyperdrive. |
2015 |
Общая ошибка. | Hyperdrive не удалось подключиться, и определить причину не получилось. Создайте тикет в поддержку, чтобы Cloudflare могла разобраться в проблеме. |
2016 |
Тестовый запрос не выполнен. | Убедитесь, что у пользователя, от имени которого подключается Hyperdrive, есть права на выполнение запросов чтения и записи в указанной базе данных. |
Ошибка подключения
Hyperdrive также может выдавать Failed to connect to the provided database когда не удаётся подключиться к базе данных при попытке создать конфигурацию Hyperdrive. Это может произойти, если сертификаты TLS (SSL) настроены неверно. Ниже приведена неполная таблица возможных ошибок подключения:
| Сообщение об ошибке | Подробности | Рекомендуемые исправления |
|---|---|---|
| Сервер вернул ошибку и закрыл подключение. | Это сообщение появляется при попытке подключения к базе данных, для которой включена проверка клиентского сертификата. | Убедитесь, что настраиваете Hyperdrive с клиентские сертификаты если это требуется вашей базе данных. |
| Сбой TLS handshake: ошибка проверки сертификата. | Это сообщение появляется, если для Hyperdrive настроены сертификаты CA сервера, и означает, что сертификат, предоставленный сервером, не подписан ожидаемым сертификатом CA. | Убедитесь, что используете правильный CA-сертификат для Hyperdrive, либо что подключаетесь к нужной базе данных. |
Ошибки подключения
Hyperdrive также может возвращать ошибки во время выполнения. Это может происходить при установке первоначального соединения либо в ответ на запрос или другую команду протокола, отправленную вашим драйвером.
Эти ошибки возвращаются как ErrorResponse сообщений wire-протокола, которые большинство драйверов обрабатывают, выбрасывая исключение в соответствующем запросе или вызывая событие ошибки.
Ошибки Hyperdrive, которые не сопоставляются один к одному с кодом сообщения об ошибке описано в документации PostgreSQL ↗ используйте 58000 (код ошибки).
Hyperdrive также может сталкиваться с ErrorResponse сообщений wire-протокола, отправленных вашей базой данных. Hyperdrive передает эти ошибки без изменений, если это возможно.
Ошибки, специфичные для Hyperdrive
| Сообщение об ошибке | Подробности | Рекомендуемые исправления |
|---|---|---|
Internal error. |
Произошла ошибка на нашей стороне. | Проверьте, нет ли действующего инцидента, затрагивающего Hyperdrive, и обратитесь в службу поддержки Cloudflare. Повторный запрос допустим, если это соответствует вашему сценарию использования. |
Failed to acquire a connection from the pool. |
Hyperdrive превысил время ожидания подключения к базе данных или вообще не может подключиться. | Если эта ошибка возникает периодически, значит пул Hyperdrive исчерпывается из-за того, что ваш worker слишком долго держит открытым слишком много подключений. Причин может быть множество, но чаще всего виноваты долго выполняющиеся запросы или транзакции. |
Server connection attempt failed: connection_refused |
Hyperdrive не может создавать новые соединения с исходной базой данных. | Скорее всего, запросы от Hyperdrive отклоняет межсетевой экран или список контроля доступа (ACL). Убедитесь, что вы разрешили подключения из публичного интернета. Иногда причина в том, что провайдер хостинга базы данных отклоняет входящие подключения при превышении лимита подключений. |
Hyperdrive does not currently support MySQL COM_STMT_PREPARE messages |
Hyperdrive не поддерживает подготовленные выражения (prepared statements) для баз данных MySQL. | Уберите подготовленные выражения из запросов MySQL. |
Ошибки Node
| Сообщение об ошибке | Подробности | Рекомендуемые исправления |
|---|---|---|
Uncaught Error: No such module "node:<module>" |
Ваш проект Cloudflare Workers или импортируемая им библиотека пытается обратиться к модулю Node, который недоступен. | Включить Совместимость с Node.js для вашего проекта Cloudflare Workers, чтобы обеспечить максимальную совместимость. |
Устаревшие чтения после записи
Если ваше приложение записывает данные, а последующее чтение возвращает более старые данные, возможно, кеширование запросов Hyperdrive отдает кешированный результат запроса на чтение. Проверьте метрики Hyperdrive cacheStatus чтобы убедиться, возвращают ли операции чтения hit, miss, disabled, или uncacheable. См. Метрики и аналитика.
Чтобы устранить чтение устаревших данных после записи, см. Кеширование запросов с рекомендациями о том, как разделять актуальные и кэшируемые запросы на чтение, в том числе с помощью конфигурации Hyperdrive с отключенным кэшированием для запросов, которые должны возвращать только актуальные данные.
Некэшированные запросы
Если ваши запросы не кешируются, несмотря на включенное кеширование в Hyperdrive, проверьте следующее:
-
Функции PostgreSQL с категорией STABLE или VOLATILE в запросе: Запросы, содержащие функции PostgreSQL, отнесенные к категории
STABLEилиVOLATILEне подлежат кэшированию. Типичные примеры включаютNOW(),CURRENT_TIMESTAMP,CURRENT_DATE,RANDOM(), а такжеLASTVAL(). Для устранения этой проблемы перенесите вызов функции в код приложения и передайте результат как параметр запроса. Например, вместоWHERE created_at > NOW(), вычислите временную метку в вашем Worker и передайте ее как параметр:WHERE created_at > $1. См. Кеширование запросов с полным списком некэшируемых функций. -
Имена функций в комментариях SQL: Hyperdrive использует сопоставление текстовых шаблонов для обнаружения некоторых некэшируемых функций. Упоминания имен функций, таких как
NOW()в комментариях SQL может привести к тому, что запрос будет считаться некэшируемым, даже если функция фактически не вызывается. Удалите упоминания некэшируемых функций из текста запроса, включая комментарии. -
Настройка драйвера: Ваш драйвер может быть настроен так, что запросы не кэшируются Hyperdrive. Это может произойти, если вы используете Postgres.js ↗ драйвер с
prepare: false↗. Для устранения этой проблемы включите подготовленные выражения с помощьюprepare: true.
Ошибки драйвера
| Сообщение об ошибке | Подробности | Рекомендуемые исправления |
|---|---|---|
Code generation from strings disallowed for this context |
Используемый вами драйвер базы данных пытается использовать eval() команду, которая не поддерживается в Cloudflare Workers (она часто встречается в mysql2 драйвер). |
Настройте драйвер базы данных так, чтобы он не использовал eval(). Подробнее о том, как настроить mysql2 чтобы отключить использование eval(). |
Ошибки устаревшего подключения и контекста ввода-вывода
Эти ошибки возникают, когда клиент базы данных или соединение создаются в глобальной области видимости (вне обработчика запроса) либо повторно используются между запросами. Workers не допускают Ввод-вывод между запросами, а подключения к базе данных из контекста предыдущего запроса становятся непригодными для использования. Всегда создавать клиенты базы данных внутри обработчиков.
Ошибки среды выполнения Workers
| Сообщение об ошибке | Подробности | Рекомендуемые исправления |
|---|---|---|
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 пытается открыть подключение к базе данных или выполнить операцию ввода-вывода при запуске скрипта, вне обработчика запроса. | Перенесите создание клиента базы данных в 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 уже устраняет накладные расходы на установление соединения. |
node-postgres (pg) ошибки
| Сообщение об ошибке | Подробности | Рекомендуемые исправления |
|---|---|---|
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.connect() был вызван на Pool экземпляр, который уже был завершён. |
Не используйте new Pool() в глобальной области видимости. Создайте new Client() внутри обработчика: Hyperdrive берёт на себя управление пулом соединений. |
Client has already been connected. You cannot reuse a client. |
client.connect() был вызван для клиента, который уже был подключён при предыдущем вызове. |
Создайте новый Client на запрос. Клиенты node-postgres нельзя переподключить после того, как соединение уже установлено. |
Postgres.js (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() экземпляр внутри обработчика. Если это происходит в рамках одного запроса, проверьте наличие проблем с сетью или тайм-аутов запросов. |
ошибки mysql2
| Сообщение об ошибке | Подробности | Рекомендуемые исправления |
|---|---|---|
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 берёт на себя управление пулом соединений. |
ошибки mysql
| Сообщение об ошибке | Подробности | Рекомендуемые исправления |
|---|---|---|
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 нельзя переподключить после установления соединения. |
Повышение производительности
Если запросы отправляются в виде транзакций, это может снижать производительность. Дело в том, что во время транзакции соединение должно удерживаться на всё время её выполнения, а это ограничивает мультиплексирование соединений. Особенно заметно это проявляется, если на одну транзакцию приходится несколько запросов. По возможности не оборачивайте запросы в транзакции: так соединения будут разделяться между клиентами более активно.