psql выполняется запрос и вы нажимаете Ctrl+C, клиент отправляет серверу запрос на отмену выполнения. Но как это работает?Сервер не может использовать уже существующее соединение, потому что оно занято обработкой текущего запроса. Поэтому Postgres использует второе, временное соединение, которое работает по принципу «отправил и забыл», аналогично
SIGINT. Этот механизм намеренно сделан максимально простым, потому что отмена должна срабатывать даже тогда, когда всё остальное зависло.Все драйверы, клиенты и инструменты, поддерживающие отмену запросов, используют один и тот же механизм.
PID, секретный ключ и код запроса на отмену
Во время инициализации соединения, после завершения аутентификации, сервер отправляет сообщение
BackendKeyData, содержащее:pid — идентификатор процесса (PID) backend-процесса, обслуживающего ваше соединение;secret — случайное 32-битное целое число, генерируемое при запуске сессии.Согласованный код запроса на отмену — фиксированное значение:
0x04d2162e, или PG_PROTOCOL(1234,5678) в исходном коде Postgres.Чтобы отменить запрос, клиент открывает новое соединение с портом Postgres и отправляет сообщение
CancelRequest, содержащее PID, секретный ключ и код запроса на отмену.Что делает сервер?
- Распознаёт сообщение как
CancelRequest, а не как стартовое сообщение (StartupMessage);- Находит backend-процесс с указанным PID;
- Проверяет совпадение секретного ключа;
- Отправляет сигнал
SIGINT этому backend-процессу;- Закрывает соединение для отмены, не отправляя никакого ответа.
- Backend-процесс получает
SIGINT, что запускает механизм обработки прерываний в Postgres. После этого в исходное соединение возвращается ошибка:
ErrorResponse: ERROR: canceling statement due to user request
ReadyForQuery
Что именно происходит внутри Postgres после получения запросом сигнала
SIGINT — тема уже не для выходного чтения. Об этом поговорим в одном из постов на след неделе.👉 @SQLPortal
