Skip to content

Commit 7aae2a7

Browse files
authored
revert: "feat(container-loader): add optional connection retry timeout" (#25814)
Reverts #24948
1 parent 67766a6 commit 7aae2a7

File tree

3 files changed

+0
-184
lines changed

3 files changed

+0
-184
lines changed

packages/loader/container-loader/src/connectionManager.ts

Lines changed: 0 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -186,12 +186,6 @@ export class ConnectionManager implements IConnectionManager {
186186

187187
private connectFirstConnection = true;
188188

189-
/**
190-
* Tracks the initial connection start time for the entire lifetime of the class.
191-
* This is used only for retryConnectionTimeoutMs checks and is never reset.
192-
*/
193-
private initialConnectionStartTime: number | undefined;
194-
195189
private _connectionVerboseProps: Record<string, string | number> = {};
196190

197191
private _connectionProps: ITelemetryBaseProperties = {};
@@ -350,7 +344,6 @@ export class ConnectionManager implements IConnectionManager {
350344
reconnectAllowed: boolean,
351345
private readonly logger: ITelemetryLoggerExt,
352346
private readonly props: IConnectionManagerFactoryArgs,
353-
private readonly retryConnectionTimeoutMs?: number,
354347
) {
355348
this.clientDetails = this.client.details;
356349
this.defaultReconnectionMode = this.client.mode;
@@ -529,12 +522,6 @@ export class ConnectionManager implements IConnectionManager {
529522
let delayMs = InitialReconnectDelayInMs;
530523
let connectRepeatCount = 0;
531524
const connectStartTime = performanceNow();
532-
533-
// Set the initial connection start time only once for the entire lifetime of the class
534-
if (this.initialConnectionStartTime === undefined) {
535-
this.initialConnectionStartTime = connectStartTime;
536-
}
537-
538525
let lastError: unknown;
539526

540527
const abortController = new AbortController();
@@ -655,31 +642,6 @@ export class ConnectionManager implements IConnectionManager {
655642
this.props.reconnectionDelayHandler(delayMs, origError);
656643
}
657644

658-
// Check if the calculated delay would exceed the remaining timeout with a conservative buffer
659-
if (this.retryConnectionTimeoutMs !== undefined) {
660-
const elapsedTime = performanceNow() - this.initialConnectionStartTime;
661-
const remainingTime = this.retryConnectionTimeoutMs - elapsedTime;
662-
const connectionAttemptDuration = performanceNow() - connectStartTime;
663-
664-
// Use a 75% buffer to be conservative about timeout usage
665-
const timeoutBufferThreshold = remainingTime * 0.75;
666-
// Estimate the next attempt time as the delay plus the time it took to connect
667-
const estimatedNextAttemptTime = delayMs + connectionAttemptDuration;
668-
669-
if (estimatedNextAttemptTime >= timeoutBufferThreshold) {
670-
this.logger.sendTelemetryEvent({
671-
eventName: "RetryDelayExceedsConnectionTimeout",
672-
attempts: connectRepeatCount,
673-
duration: formatTick(elapsedTime),
674-
calculatedDelayMs: delayMs,
675-
remainingTimeMs: remainingTime,
676-
timeoutMs: this.retryConnectionTimeoutMs,
677-
});
678-
// Throw the error immediately since the estimated time for delay + next connection attempt would exceed our conservative timeout buffer
679-
throw normalizeError(origError, { props: fatalConnectErrorProp });
680-
}
681-
}
682-
683645
await new Promise<void>((resolve) => {
684646
setTimeout(resolve, delayMs);
685647
});

packages/loader/container-loader/src/container.ts

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -248,16 +248,6 @@ export interface IContainerCreateProps {
248248
* protocol implementation for handling the quorum and/or the audience.
249249
*/
250250
readonly protocolHandlerBuilder?: ProtocolHandlerBuilder;
251-
252-
/**
253-
* Optional property for specifying a timeout for retry connection loop.
254-
*
255-
* If provided, container will use this value as the maximum time to wait
256-
* for a successful connection before giving up throwing the most recent error.
257-
*
258-
* If not provided, default behavior will be to retry until non-retryable error occurs.
259-
*/
260-
readonly retryConnectionTimeoutMs?: number;
261251
}
262252

263253
/**
@@ -627,7 +617,6 @@ export class Container
627617
private attachmentData: AttachmentData = { state: AttachState.Detached };
628618
private readonly serializedStateManager: SerializedStateManager;
629619
private readonly _containerId: string;
630-
private readonly _retryConnectionTimeoutMs: number | undefined;
631620

632621
private lastVisible: number | undefined;
633622
private readonly visibilityEventHandler: (() => void) | undefined;
@@ -810,7 +799,6 @@ export class Container
810799
scope,
811800
subLogger,
812801
protocolHandlerBuilder,
813-
retryConnectionTimeoutMs,
814802
} = createProps;
815803

816804
// Validate that the Driver is compatible with this Loader.
@@ -826,7 +814,6 @@ export class Container
826814
const pendingLocalState = loadProps?.pendingLocalState;
827815

828816
this._canReconnect = canReconnect ?? true;
829-
this._retryConnectionTimeoutMs = retryConnectionTimeoutMs;
830817
this.clientDetailsOverride = clientDetailsOverride;
831818
this.urlResolver = urlResolver;
832819
this.serviceFactory = documentServiceFactory;
@@ -2067,7 +2054,6 @@ export class Container
20672054
this._canReconnect,
20682055
createChildLogger({ logger: this.subLogger, namespace: "ConnectionManager" }),
20692056
props,
2070-
this._retryConnectionTimeoutMs,
20712057
),
20722058
);
20732059

packages/loader/container-loader/src/test/connectionManager.spec.ts

Lines changed: 0 additions & 132 deletions
Original file line numberDiff line numberDiff line change
@@ -386,136 +386,4 @@ describe("connectionManager", () => {
386386
});
387387
});
388388
});
389-
390-
it("Connection retry timeout - throws error when delay exceeds remaining timeout", async () => {
391-
// Arrange
392-
const timeoutMs = 5000; // 5 second timeout
393-
const connectionManager = new ConnectionManager(
394-
() => mockDocumentService,
395-
() => false,
396-
client as IClient,
397-
true /* reconnectAllowed */,
398-
mockLogger.toTelemetryLogger(),
399-
props,
400-
timeoutMs, // Set the retry connection timeout
401-
);
402-
403-
// Mock connectToDeltaStream to throw retryable errors that cause delays
404-
const stubbedConnectToDeltaStream = stub(mockDocumentService, "connectToDeltaStream");
405-
stubbedConnectToDeltaStream.throws(
406-
new RetryableError("Throttling error", DriverErrorTypes.throttlingError, {
407-
retryAfterSeconds: 3, // 3 second delay from error
408-
driverVersion: pkgVersion,
409-
}),
410-
);
411-
412-
// Act
413-
connectionManager.connect({ text: "test:retry timeout" }, "write");
414-
415-
// Advance time to trigger multiple retries and eventually hit the timeout
416-
await clock.tickAsync(6000); // This should trigger the timeout logic
417-
418-
// Verify the telemetry event was logged
419-
mockLogger.assertMatchAny([
420-
{
421-
eventName: "RetryDelayExceedsConnectionTimeout",
422-
attempts: 2,
423-
calculatedDelayMs: 6000, // The calculated delay that exceeded timeout
424-
remainingTimeMs: 2000, // Should be positive but less than calculatedDelayMs
425-
timeoutMs,
426-
},
427-
]);
428-
429-
// Verify that the container was closed due to the timeout
430-
assert(closed, "Connection manager should close when retry delay exceeds timeout");
431-
432-
stubbedConnectToDeltaStream.restore();
433-
});
434-
435-
it("Connection retry timeout - continues retrying when delay is within timeout", async () => {
436-
// Arrange
437-
const timeoutMs = 20000; // 20 second timeout (longer than test duration)
438-
const connectionManager = new ConnectionManager(
439-
() => mockDocumentService,
440-
() => false,
441-
client as IClient,
442-
true /* reconnectAllowed */,
443-
mockLogger.toTelemetryLogger(),
444-
props,
445-
timeoutMs, // Set the retry connection timeout
446-
);
447-
448-
// Mock connectToDeltaStream to throw retryable errors with short delays
449-
const stubbedConnectToDeltaStream = stub(mockDocumentService, "connectToDeltaStream");
450-
stubbedConnectToDeltaStream.throws(
451-
new RetryableError("Temporary error", DriverErrorTypes.genericError, {
452-
retryAfterSeconds: 0.1, // Very small delay to keep within timeout
453-
driverVersion: pkgVersion,
454-
}),
455-
);
456-
457-
// Act
458-
connectionManager.connect({ text: "test:retry within timeout" }, "write");
459-
460-
// Advance time for a few retries but not long enough to exceed timeout
461-
await clock.tickAsync(2000); // 2 seconds - should allow for multiple retries
462-
463-
// Assert - the connection should still be retrying and not have closed
464-
assert(!closed, "Connection manager should not close when retries are within timeout");
465-
assert(
466-
stubbedConnectToDeltaStream.callCount > 1,
467-
"Should have made multiple connection attempts",
468-
);
469-
470-
// Verify no timeout telemetry was logged
471-
assert(
472-
!mockLogger.matchEvents([{ eventName: "RetryDelayExceedsConnectionTimeout" }]),
473-
"Should not log timeout event when retries are within limit",
474-
);
475-
476-
stubbedConnectToDeltaStream.restore();
477-
});
478-
479-
it("Connection retry timeout - no timeout when retryConnectionTimeoutMs is undefined", async () => {
480-
// Arrange - Create connection manager without timeout
481-
const connectionManager = new ConnectionManager(
482-
() => mockDocumentService,
483-
() => false,
484-
client as IClient,
485-
true /* reconnectAllowed */,
486-
mockLogger.toTelemetryLogger(),
487-
props,
488-
undefined, // No retry timeout
489-
);
490-
491-
// Mock connectToDeltaStream to throw retryable errors
492-
const stubbedConnectToDeltaStream = stub(mockDocumentService, "connectToDeltaStream");
493-
stubbedConnectToDeltaStream.throws(
494-
new RetryableError("Delay error", DriverErrorTypes.genericError, {
495-
retryAfterSeconds: 1, // 1 second delay
496-
driverVersion: pkgVersion,
497-
}),
498-
);
499-
500-
// Act
501-
connectionManager.connect({ text: "test:no timeout limit" }, "write");
502-
503-
// Advance time for several retries
504-
await clock.tickAsync(10000); // 10 seconds - would exceed most reasonable timeouts
505-
506-
// Assert - the connection should still be retrying and not have closed
507-
assert(!closed, "Connection manager should not close when no timeout is set");
508-
assert(
509-
stubbedConnectToDeltaStream.callCount > 1,
510-
"Should have made multiple connection attempts",
511-
);
512-
513-
// Verify no timeout telemetry was logged
514-
assert(
515-
!mockLogger.matchEvents([{ eventName: "RetryDelayExceedsConnectionTimeout" }]),
516-
"Should not log timeout event when no timeout is configured",
517-
);
518-
519-
stubbedConnectToDeltaStream.restore();
520-
});
521389
});

0 commit comments

Comments
 (0)