Fix ADO.NET: apply CommandTimeout as max_execution_time - #619
Open
polyglotAI-bot wants to merge 2 commits into
Open
polyglotAI-bot wants to merge 2 commits into
polyglotAI-bot wants to merge 2 commits into
Conversation
ClickHouseCommand.CommandTimeout was a dead auto-property: BuildQueryOptions never populated QueryOptions.MaxExecutionTime, so no server-side limit reached ClickHouse and a command set to time out ran to completion. A non-zero CommandTimeout is now mapped onto max_execution_time for every execution path. Zero (the ADO.NET "no limit" value and the default) and a negative value leave the setting alone, so existing callers are unaffected. An explicit max_execution_time in the command's own CustomSettings is equally specific and keeps precedence. Fixes: #618
polyglotAI-bot
requested review from
alex-clickhouse and
mzitnik
as code owners
September 17, 2026 08:37
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
Contributor
There was a problem hiding this comment.
🟡 Changes recommended
Review assessments request clarification of timeout semantics and documentation before approval.
Get a fresh assessment by requesting another Copilot review.
Pull request overview
This PR maps positive ClickHouseCommand.CommandTimeout values to ClickHouse’s server-side max_execution_time.
Changes:
- Adds timeout mapping with command-level setting precedence.
- Adds real-server tests for execution paths, defaults, negatives, and precedence.
- Updates documentation and changelog.
File summaries
| File | Summary |
|---|---|
docs/overview.mdx |
Documents CommandTimeout; nit (2 votes) to clarify inherited settings for zero/negative values. |
ClickHouse.Driver/ADO/ClickHouseCommand.cs |
Applies command timeouts; nits (3, 1 votes) to clarify positive-value behavior and streaming response timeout semantics. |
ClickHouse.Driver.Tests/ADO/CommandTimeoutTests.cs |
Adds coverage for timeout behavior and precedence. |
changelog.d/618-command-timeout.fixes.md |
Records the fix; nit (2 votes) to change “non-zero” to “positive” or document negative values. |
Review details
Suppressed comments (2)
ClickHouse.Driver/ADO/ClickHouseCommand.cs:53
- The XML docs repeat an inaccurate client-timeout guarantee: this command path uses
ResponseHeadersRead, soHttpClient.Timeoutdoes not necessarily cover later streaming-body consumption. Clarify that it bounds the response-header wait and thatCommandTimeoutremains server-side only for a streaming reader.
/// precedence over this property; a connection-level one does not. The overall wait for a
/// response is bounded separately by <see cref="ClickHouseClientSettings.Timeout"/>.
docs/overview.mdx:1382
- These statements overpromise the effective timeout. The implementation only supplies
MaxExecutionTimefor positive command values, so zero/negative leaves a connection-levelmax_execution_timeactive; additionallyPostSqlQueryAsyncusesResponseHeadersRead, so the connectionTimeoutdoes not bound consuming a streaming reader or raw result after headers arrive. Please document positive-timeout precedence and the initial-response limit, or change the implementation if a whole-operation client deadline is intended.
A `max_execution_time` entry in the command's own `CustomSettings` is equally specific and takes
precedence; a connection-level `max_execution_time` is less specific and does not. The overall wait
for a response is bounded separately by the connection string's `Timeout` (2 minutes by default),
which applies to the HTTP request as a whole.
- Files reviewed: 4/4 changed files
- Comments generated: 3
- Review effort level: Lite
💡 Configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Review feedback on #619: the docs overstated the effect of the property. Only a positive CommandTimeout maps to max_execution_time, so zero and negative values add no command-level limit — they do not remove a max_execution_time inherited from the connection or the server profile. The property is also a server-side limit only and does not cancel the client-side wait. Adds a regression test pinning that CommandTimeout of 0 or -1 keeps a connection-level max_execution_time active.
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
Fixes #618.
ClickHouseCommand.CommandTimeout(theDbCommand.CommandTimeoutoverride) was a deadauto-property.
BuildQueryOptions()populatedQueryId,BearerToken,Database,Roles,CustomSettingsandAcceptEncoding, but neverQueryOptions.MaxExecutionTime— the one optionthat carries a timeout to the server. Nothing else read the property either, so a command set to
time out after N seconds ran to completion: the server kept working and the caller kept waiting.
ADO.NET consumers (Dapper, EF Core, linq2db) configure timeouts through exactly this property, so
the ADO.NET surface could not bound execution at all while the lower-level
IClickHouseClientAPIcould.
BuildQueryOptions()now maps a non-zeroCommandTimeoutontoMaxExecutionTime, which theexisting URI builder emits as
max_execution_time. Zero — the ADO.NET "no limit" value and thisproperty's default — leaves the setting alone, as does a negative value, so callers that never set
the property see no change. A
max_execution_timeentry in the command's ownCustomSettingsstates the same intent in the server's own terms and is equally specific, so it keeps precedence;
CommandTimeoutis command-scoped and therefore outranks a connection-levelmax_execution_time.Scope note: this bounds execution server-side only. The overall wait for a response stays bounded by
the connection-level
Timeout(HttpClient.Timeout, 2 minutes by default). A per-commandclient-side abort would change the lifetime of a streaming
ClickHouseDataReader, which is aseparate behavioral decision and is deliberately not part of this fix.
Changes
ClickHouse.Driver/ADO/ClickHouseCommand.cs:BuildQueryOptions()setsMaxExecutionTimefromCommandTimeoutwhen it is positive and the command'sCustomSettingsdoes not already specifymax_execution_time; doc comment updated to describe the behavior and precedence.docs/overview.mdx: documentedCommandTimeoutin the ADO.NET command section.changelog.d/618-command-timeout.fixes.md: changelog fragment.ClickHouse.Driver.Tests/ADO/CommandTimeoutTests.cs: new tests.Test
CommandTimeoutTestsruns against a real server:ExecuteAsync_WithCommandTimeout_LongQueryIsCancelledByServer— parametrized over all fourexecution paths that reach
BuildQueryOptions(ExecuteScalarAsync,ExecuteNonQueryAsync,ExecuteReaderAsync,ExecuteRawResultAsync):SELECT sleep(3)withCommandTimeout = 1mustfail with error 159 (
TIMEOUT_EXCEEDED). Onmainevery case returns a result instead.ExecuteScalarAsync_WithCommandTimeout_AppliesMaxExecutionTimeSetting—getSetting('max_execution_time')reports 30 for
CommandTimeout = 30; onmainit reports the server default.0) and negative values leavemax_execution_timeat the server default.CustomSettings["max_execution_time"]wins overCommandTimeout, andCommandTimeoutwins over a connection-levelset_max_execution_time.dotnet test ClickHouse.Driver.Tests --framework net10.0, filtered to the ADO, QueryOptions,UriBuilder and ORM suites: 1792 passed, 0 failed.
dotnet run scripts/changelog.cs -- --checkis OK.Pre-PR validation gate
main, pass on this branch)QueryOptions)AGENTS.md(NUnit, real-server tests,[TestCase]parametrization, changelog fragment, docs updated)
CommandTimeoutis already inPublicAPI.Shipped.txt