Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Fixed

- Stop queries that run longer than 6 minutes from failing with `Request failed (network error): … (The operation timed out.)`. `--read-timeout` is now the only limit on query streams, and `0` means no limit.

- Keep the TypeScript manifest compiler out of CLI downloads by installing it with the cached single-file preview runtime.

- Complete stdin-based credential configuration before exiting on Windows.
Expand Down
24 changes: 24 additions & 0 deletions cli/src/lib/http.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -362,6 +362,30 @@ describe('shared dispatcher', () => {
});
});

describe('native fetch timeout', () => {
test.each([false, true])(
'is disabled so long-running streams outlive 300s of silence (ignoreSslErrors=%p)',
ignoreSslErrors => {
setCliContext({
debug: false,
json: false,
agent: false,
ignoreSslErrors,
});
const init = buildFetchInit(
{
method: 'POST',
url: 'https://api.altertable.test/query',
authHeader: 'Authorization: Basic test',
},
{},
AbortSignal.timeout(1_000)
) as { timeout?: unknown };
expect(init.timeout).toBe(false);
}
);
});

describe('ignore ssl errors', () => {
const request = {
method: 'GET',
Expand Down
15 changes: 13 additions & 2 deletions cli/src/lib/http.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,8 @@ type MockHttpEntry = {
type UndiciAgentOptions = {
keepAliveTimeout: number;
keepAliveMaxTimeout: number;
headersTimeout: number;
bodyTimeout: number;
connect?: { rejectUnauthorized: boolean };
};

Expand Down Expand Up @@ -86,6 +88,8 @@ export function getSharedDispatcher(): unknown {
sharedDispatcher = createDispatcher({
keepAliveTimeout: 30_000,
keepAliveMaxTimeout: 60_000,
headersTimeout: 0,
bodyTimeout: 0,
});

return sharedDispatcher;
Expand All @@ -104,6 +108,8 @@ function getInsecureDispatcher(): unknown {
insecureDispatcher = createDispatcher({
keepAliveTimeout: 30_000,
keepAliveMaxTimeout: 60_000,
headersTimeout: 0,
bodyTimeout: 0,
connect: { rejectUnauthorized: false },
});

Expand All @@ -130,8 +136,12 @@ function warnInsecureTlsOnce(): void {
}

/**
* Bun's fetch reads `tls`; Node/undici reads `dispatcher`. Set both so the
* escape hatch works under either runtime.
* Bun's fetch reads `tls` and `timeout`; Node/undici reads `dispatcher`. Set
* both so the escape hatch works under either runtime.
*
* Both runtimes otherwise abort a response that stays silent for 300s, which
* kills long-running queries whatever `--read-timeout` says. The connect and
* read timeouts are enforced through `signal` instead.
*/
export function buildFetchInit(
options: HttpSendOptions,
Expand All @@ -148,6 +158,7 @@ export function buildFetchInit(
headers,
body: options.body,
signal,
timeout: false,
dispatcher: ignoreSslErrors
? getInsecureDispatcher()
: getSharedDispatcher(),
Expand Down
Loading