Skip to content

Commit ad6f7f5

Browse files
committed
some bug fixes & testiung mostly related to timeouts
1 parent e04a74e commit ad6f7f5

File tree

9 files changed

+57
-24
lines changed

9 files changed

+57
-24
lines changed

src/api/devops-api-http-client.ts

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ import { AxiosError, AxiosResponse } from 'axios';
1818
import { HTTPClientOptions } from '@/src/api/types';
1919
import { HTTP1AuthHeaderFactories, HTTP1Strategy } from '@/src/api/http1';
2020
import { DevopsApiResponseError, DevopsApiTimeout, DevopsUnexpectedStateError } from '@/src/devops/errors';
21-
import { AdminBlockingOptions } from '@/src/devops/types';
21+
import { AdminBlockingOptions, PollBlockingOptions } from '@/src/devops/types';
2222
import {
2323
MkTimeoutError,
2424
MultiCallTimeoutManager,
@@ -80,15 +80,14 @@ export class DevopsApiHttpClient extends HttpClient {
8080
? info.id(resp)
8181
: info.id;
8282

83-
await this._awaitStatus(id, 'ACTIVE', ['MAINTENANCE'], info.options, info.defaultPollInterval, timeoutManager);
83+
if (info?.options?.blocking !== false) {
84+
await this._awaitStatus(id, info.target, info.legalStates, info.options, info.defaultPollInterval, timeoutManager);
85+
}
86+
8487
return resp;
8588
}
8689

87-
private async _awaitStatus(id: string, target: string, legalStates: string[], options: AdminBlockingOptions | undefined, defaultPollInterval: number, timeoutManager: TimeoutManager): Promise<void> {
88-
if (options?.blocking === false) {
89-
return;
90-
}
91-
90+
private async _awaitStatus(id: string, target: string, legalStates: string[], options: PollBlockingOptions | undefined, defaultPollInterval: number, timeoutManager: TimeoutManager): Promise<void> {
9291
for (;;) {
9392
const resp = await this.request({
9493
method: HTTP_METHODS.Get,
@@ -113,7 +112,7 @@ export class DevopsApiHttpClient extends HttpClient {
113112
}
114113

115114
const mkTimeoutManager = (constructor: new (maxMs: number, mkTimeoutError: MkTimeoutError) => TimeoutManager, maxMs: number | undefined) => {
116-
const timeout = maxMs ?? DEFAULT_TIMEOUT;
115+
const timeout = maxMs ?? 0;
117116
return new constructor(timeout, mkTimeoutErrorMaker(timeout));
118117
}
119118

src/api/http-client.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ export class HttpClient {
8888
}
8989

9090
protected async _request(info: HTTPRequestInfo): Promise<GuaranteedAPIResponse> {
91-
return await this.requestStrategy.request({
91+
const fullInfo = {
9292
url: info.url,
9393
data: info.data,
9494
method: info.method,
@@ -97,7 +97,12 @@ export class HttpClient {
9797
userAgent: this.userAgent,
9898
timeoutManager: info.timeoutManager,
9999
reviver: info.reviver,
100-
});
100+
};
101+
102+
if (info.timeoutManager.msRemaining <= 0) {
103+
throw info.timeoutManager.mkTimeoutError(fullInfo);
104+
}
105+
return await this.requestStrategy.request(fullInfo);
101106
}
102107
}
103108

src/api/http1.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,9 @@ export class HTTP1Strategy implements HTTPRequestStrategy {
6868
data: info.data,
6969
params: info.params,
7070
method: info.method,
71-
timeout: info.timeoutManager.msRemaining,
71+
timeout: (isFinite(info.timeoutManager.msRemaining))
72+
? info.timeoutManager.msRemaining
73+
: 0,
7274
headers: {
7375
...this._authHeaderFactory(info.token),
7476
'User-Agent': info.userAgent,

src/api/http2.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,9 @@ export class HTTP2Strategy implements HTTPRequestStrategy {
3838
this.#session = this._reviveSession();
3939
}
4040

41-
const timer = setTimeout(() => reject(info.timeoutManager.mkTimeoutError(info)), info.timeoutManager.msRemaining);
41+
const timer = (isFinite(info.timeoutManager.msRemaining))
42+
? setTimeout(() => reject(info.timeoutManager.mkTimeoutError(info)), info.timeoutManager.msRemaining)
43+
: undefined;
4244

4345
const path = info.url.replace(this.origin, '');
4446
const params = info.params ? `?${new URLSearchParams(info.params).toString()}` : '';

src/api/timeout-managers.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,15 +30,19 @@ export interface TimeoutManager {
3030
}
3131

3232
export class SingleCallTimeoutManager implements TimeoutManager {
33-
constructor(readonly msRemaining: number, readonly mkTimeoutError: MkTimeoutError) {}
33+
public readonly msRemaining: number;
34+
35+
constructor(maxMs: number, readonly mkTimeoutError: MkTimeoutError) {
36+
this.msRemaining = maxMs || Infinity;
37+
}
3438
}
3539

3640
export class MultiCallTimeoutManager implements TimeoutManager {
3741
private _deadline!: number;
3842
private _started: boolean;
3943

4044
constructor(maxMs: number, readonly mkTimeoutError: MkTimeoutError) {
41-
this._deadline = maxMs;
45+
this._deadline = maxMs || Infinity;
4246
this._started = false;
4347
}
4448

src/devops/astra-db-admin.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -242,12 +242,12 @@ export class AstraDbAdmin extends DbAdmin {
242242
*/
243243
public async drop(options?: AdminBlockingOptions): Promise<void> {
244244
await this._httpClient.requestLongRunning({
245-
method: HTTP_METHODS.Delete,
246-
path: `/databases/${this._db.id}`,
245+
method: HTTP_METHODS.Post,
246+
path: `/databases/${this._db.id}/terminate`,
247247
}, {
248248
id: this._db.id,
249-
target: 'DELETED',
250-
legalStates: ['TERMINATED'],
249+
target: 'TERMINATED',
250+
legalStates: ['TERMINATING'],
251251
defaultPollInterval: 10000,
252252
options,
253253
});

tests/integration/data-api/collection/insert-many.test.ts

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
// limitations under the License.
1010
// noinspection DuplicatedCode
1111

12-
import { Collection, DataAPIError, InsertManyError, ObjectId, UUID } from '@/src/data-api';
12+
import { Collection, DataAPIError, DataAPITimeout, InsertManyError, ObjectId, UUID } from '@/src/data-api';
1313
import { assertTestsEnabled, initCollectionWithFailingClient, initTestObjects } from '@/tests/fixtures';
1414
import assert from 'assert';
1515

@@ -204,6 +204,25 @@ describe('integration.data-api.collection.insert-many', () => {
204204
}
205205
});
206206

207+
it('times out properly', async () => {
208+
try {
209+
const docs = Array.from({ length: 1000 }, (_, i) => ({ _id: i }));
210+
await collection.insertMany(docs, { ordered: true, maxTimeMS: 500, chunkSize: 10 });
211+
assert.fail('Expected an error');
212+
} catch (e) {
213+
assert.ok(e instanceof DataAPITimeout);
214+
assert.strictEqual(e.timeout, 500);
215+
const found = await collection.find({}).toArray();
216+
assert.ok(found.length > 0);
217+
assert.ok(found.length < 1000);
218+
}
219+
});
220+
221+
it('does not time out if maxTimeMS is high', async () => {
222+
const docs = Array.from({ length: 100 }, (_, i) => ({ _id: i }));
223+
await collection.insertMany(docs, { ordered: true, maxTimeMS: 500000, chunkSize: 10 });
224+
});
225+
207226
it('[dev] should insertMany with vectorize', async function () {
208227
assertTestsEnabled(this, 'DEV');
209228
const res = await collection.insertMany([

tests/integration/data-api/collection/update-many.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
// limitations under the License.
1010
// noinspection DuplicatedCode
1111

12-
import { BulkWriteError, Collection, DataAPIError, UpdateManyError } from '@/src/data-api';
12+
import { Collection, DataAPIError, UpdateManyError } from '@/src/data-api';
1313
import { initCollectionWithFailingClient, initTestObjects, sampleUsersList } from '@/tests/fixtures';
1414
import assert from 'assert';
1515

tests/integration/devops/lifecycle.test.ts

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ import { assertTestsEnabled, initTestObjects } from '@/tests/fixtures';
1717
import { DataApiClient } from '@/src/client';
1818
import assert from 'assert';
1919
import { DevopsApiResponseError } from '@/src/devops';
20+
import { SingleCallTimeoutManager } from '@/src/api/timeout-managers';
21+
import { DEFAULT_TIMEOUT } from '@/src/api';
2022

2123
describe('integration.devops.lifecycle', async () => {
2224
let client: DataApiClient;
@@ -89,7 +91,7 @@ describe('integration.devops.lifecycle', async () => {
8991
}
9092

9193
{
92-
await asyncDbAdmin['_httpClient'].awaitStatus(asyncDb, 'ACTIVE', ['INITIALIZING', 'PENDING'], {}, 10000);
94+
await asyncDbAdmin['_httpClient']['_awaitStatus'](asyncDb.id, 'ACTIVE', ['INITIALIZING', 'PENDING'], {}, 10000, new SingleCallTimeoutManager(DEFAULT_TIMEOUT, () => new Error('Timeout')));
9395
}
9496

9597
for (const [dbAdmin, db, dbType] of [[syncDbAdmin, syncDb, 'sync'], [asyncDbAdmin, asyncDb, 'async']] as const) {
@@ -132,7 +134,7 @@ describe('integration.devops.lifecycle', async () => {
132134

133135
{
134136
await syncDbAdmin.createNamespace('other_namespace');
135-
await asyncDbAdmin['_httpClient'].awaitStatus(asyncDb, 'ACTIVE', ['MAINTENANCE'], {}, 1000);
137+
await asyncDbAdmin['_httpClient']['_awaitStatus'](asyncDb.id, 'ACTIVE', ['MAINTENANCE'], {}, 1000, new SingleCallTimeoutManager(DEFAULT_TIMEOUT, () => new Error('Timeout')));
136138
}
137139

138140
for (const [dbAdmin, db, dbType] of [[syncDbAdmin, syncDb, 'sync'], [asyncDbAdmin, asyncDb, 'async']] as const) {
@@ -151,7 +153,7 @@ describe('integration.devops.lifecycle', async () => {
151153

152154
{
153155
await syncDbAdmin.dropNamespace('other_namespace', { blocking: true });
154-
await asyncDbAdmin['_httpClient'].awaitStatus(asyncDb, 'ACTIVE', ['MAINTENANCE'], {}, 1000);
156+
await asyncDbAdmin['_httpClient']['_awaitStatus'](asyncDb.id, 'ACTIVE', ['MAINTENANCE'], {}, 1000, new SingleCallTimeoutManager(DEFAULT_TIMEOUT, () => new Error('Timeout')));
155157
}
156158

157159
for (const [dbAdmin, db, dbType] of [[syncDbAdmin, syncDb, 'sync'], [asyncDbAdmin, asyncDb, 'async']] as const) {
@@ -172,7 +174,7 @@ describe('integration.devops.lifecycle', async () => {
172174

173175
{
174176
await admin.dropDatabase(syncDb);
175-
await asyncDbAdmin['_httpClient'].awaitStatus(asyncDbAdmin, 'TERMINATED', ['TERMINATING'], {}, 10000);
177+
await asyncDbAdmin['_httpClient']['_awaitStatus'](asyncDb.id, 'TERMINATED', ['TERMINATING'], {}, 10000, new SingleCallTimeoutManager(DEFAULT_TIMEOUT, () => new Error('Timeout')));
176178
}
177179

178180
for (const [dbAdmin, dbType] of [[syncDbAdmin, 'sync'], [asyncDbAdmin, 'async']] as const) {

0 commit comments

Comments
 (0)