A user who closes a slow screen expects the query to stop. It did not. Over HTTP/1.1 keep-alive, and behind every proxy that speaks HTTP/1.1 to the backend, the browser's abort never reaches the server, and the query ran on, holding the parent cursor's row lock.
Cancellation that reaches the engine
- A request id on every request The header already on each call keys a cancellable request; a cancel call resolves only through the caller's own session and always answers 204.
- Cancelled at the database Navigator and form sub-cursor queries are cancelled through the JDBC connection, not merely abandoned.
- A backstop A configurable timeout, ten minutes by default, and a cancelled handler's failure maps to 499 at info level, never a 500.
Progress
- Streamed A task's status and completion stream over server-sent events, about once a second, built from the same code as the polled path. Any problem falls back to polling.
- Polite polling The polled queue carries Retry-After: one second for the first ten, then two, five and ten, capped by the session cache's idle time.
The lock a cancelled query held was the cost nobody saw. It is released now.