@aws-amplify/api-graphql 4.7.1 → 4.7.2-graphql-data-ka.518fb2c.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/Providers/AWSWebSocketProvider/index.js +43 -25
- package/dist/cjs/Providers/AWSWebSocketProvider/index.js.map +1 -1
- package/dist/cjs/Providers/constants.js +5 -1
- package/dist/cjs/Providers/constants.js.map +1 -1
- package/dist/esm/Providers/AWSWebSocketProvider/index.d.ts +5 -3
- package/dist/esm/Providers/AWSWebSocketProvider/index.mjs +44 -26
- package/dist/esm/Providers/AWSWebSocketProvider/index.mjs.map +1 -1
- package/dist/esm/Providers/constants.d.ts +4 -0
- package/dist/esm/Providers/constants.mjs +5 -1
- package/dist/esm/Providers/constants.mjs.map +1 -1
- package/package.json +4 -4
- package/src/Providers/AWSWebSocketProvider/index.ts +58 -27
- package/src/Providers/constants.ts +5 -0
|
@@ -23,7 +23,7 @@ import {
|
|
|
23
23
|
CONNECTION_INIT_TIMEOUT,
|
|
24
24
|
CONNECTION_STATE_CHANGE,
|
|
25
25
|
DEFAULT_KEEP_ALIVE_ALERT_TIMEOUT,
|
|
26
|
-
|
|
26
|
+
DEFAULT_KEEP_ALIVE_HEARTBEAT_TIMEOUT,
|
|
27
27
|
MAX_DELAY_MS,
|
|
28
28
|
MESSAGE_TYPES,
|
|
29
29
|
NON_RETRYABLE_CODES,
|
|
@@ -83,9 +83,8 @@ export abstract class AWSWebSocketProvider {
|
|
|
83
83
|
|
|
84
84
|
protected awsRealTimeSocket?: WebSocket;
|
|
85
85
|
private socketStatus: SOCKET_STATUS = SOCKET_STATUS.CLOSED;
|
|
86
|
-
private
|
|
87
|
-
private
|
|
88
|
-
private keepAliveAlertTimeoutId?: ReturnType<typeof setTimeout>;
|
|
86
|
+
private kaTimestamp?: number;
|
|
87
|
+
private keepAliveHeartbeatIntervalId?: ReturnType<typeof setTimeout>;
|
|
89
88
|
private promiseArray: { res(): void; rej(reason?: any): void }[] = [];
|
|
90
89
|
private connectionState: ConnectionState | undefined;
|
|
91
90
|
private readonly connectionStateMonitor = new ConnectionStateMonitor();
|
|
@@ -119,6 +118,7 @@ export abstract class AWSWebSocketProvider {
|
|
|
119
118
|
return new Promise<void>((resolve, reject) => {
|
|
120
119
|
if (this.awsRealTimeSocket) {
|
|
121
120
|
this.awsRealTimeSocket.onclose = (_: CloseEvent) => {
|
|
121
|
+
this._closeSocket();
|
|
122
122
|
this.subscriptionObserverMap = new Map();
|
|
123
123
|
this.awsRealTimeSocket = undefined;
|
|
124
124
|
resolve();
|
|
@@ -171,7 +171,7 @@ export abstract class AWSWebSocketProvider {
|
|
|
171
171
|
this.logger.debug(
|
|
172
172
|
`${CONTROL_MSG.REALTIME_SUBSCRIPTION_INIT_ERROR}: ${err}`,
|
|
173
173
|
);
|
|
174
|
-
this.
|
|
174
|
+
this._closeSocket();
|
|
175
175
|
})
|
|
176
176
|
.finally(() => {
|
|
177
177
|
subscriptionStartInProgress = false;
|
|
@@ -435,7 +435,7 @@ export abstract class AWSWebSocketProvider {
|
|
|
435
435
|
this.logger.debug({ err });
|
|
436
436
|
const message = String(err.message ?? '');
|
|
437
437
|
// Resolving to give the state observer time to propogate the update
|
|
438
|
-
this.
|
|
438
|
+
this._closeSocket();
|
|
439
439
|
|
|
440
440
|
// Capture the error only when the network didn't cause disruption
|
|
441
441
|
if (
|
|
@@ -544,12 +544,7 @@ export abstract class AWSWebSocketProvider {
|
|
|
544
544
|
setTimeout(this._closeSocketIfRequired.bind(this), 1000);
|
|
545
545
|
} else {
|
|
546
546
|
this.logger.debug('closing WebSocket...');
|
|
547
|
-
|
|
548
|
-
clearTimeout(this.keepAliveTimeoutId);
|
|
549
|
-
}
|
|
550
|
-
if (this.keepAliveAlertTimeoutId) {
|
|
551
|
-
clearTimeout(this.keepAliveAlertTimeoutId);
|
|
552
|
-
}
|
|
547
|
+
|
|
553
548
|
const tempSocket = this.awsRealTimeSocket;
|
|
554
549
|
// Cleaning callbacks to avoid race condition, socket still exists
|
|
555
550
|
tempSocket.onclose = null;
|
|
@@ -557,7 +552,7 @@ export abstract class AWSWebSocketProvider {
|
|
|
557
552
|
tempSocket.close(1000);
|
|
558
553
|
this.awsRealTimeSocket = undefined;
|
|
559
554
|
this.socketStatus = SOCKET_STATUS.CLOSED;
|
|
560
|
-
this.
|
|
555
|
+
this._closeSocket();
|
|
561
556
|
}
|
|
562
557
|
}
|
|
563
558
|
|
|
@@ -577,13 +572,43 @@ export abstract class AWSWebSocketProvider {
|
|
|
577
572
|
errorType: string;
|
|
578
573
|
};
|
|
579
574
|
|
|
575
|
+
private maintainKeepAlive() {
|
|
576
|
+
this.kaTimestamp = Date.now();
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
private keepAliveHeartbeat(connectionTimeoutMs: number) {
|
|
580
|
+
const currentTime = Date.now();
|
|
581
|
+
|
|
582
|
+
// Check for missed KA message
|
|
583
|
+
if (
|
|
584
|
+
this.kaTimestamp &&
|
|
585
|
+
currentTime - this.kaTimestamp > DEFAULT_KEEP_ALIVE_ALERT_TIMEOUT
|
|
586
|
+
) {
|
|
587
|
+
this.connectionStateMonitor.record(CONNECTION_CHANGE.KEEP_ALIVE_MISSED);
|
|
588
|
+
} else {
|
|
589
|
+
this.connectionStateMonitor.record(CONNECTION_CHANGE.KEEP_ALIVE);
|
|
590
|
+
}
|
|
591
|
+
|
|
592
|
+
// Recognize we are disconnected if we haven't seen messages in the keep alive timeout period
|
|
593
|
+
if (
|
|
594
|
+
this.kaTimestamp &&
|
|
595
|
+
currentTime - this.kaTimestamp > connectionTimeoutMs
|
|
596
|
+
) {
|
|
597
|
+
this._errorDisconnect(CONTROL_MSG.TIMEOUT_DISCONNECT);
|
|
598
|
+
}
|
|
599
|
+
}
|
|
600
|
+
|
|
580
601
|
private _handleIncomingSubscriptionMessage(message: MessageEvent) {
|
|
581
602
|
if (typeof message.data !== 'string') {
|
|
582
603
|
return;
|
|
583
604
|
}
|
|
584
605
|
|
|
585
606
|
const [isData, data] = this._handleSubscriptionData(message);
|
|
586
|
-
if (isData)
|
|
607
|
+
if (isData) {
|
|
608
|
+
this.maintainKeepAlive();
|
|
609
|
+
|
|
610
|
+
return;
|
|
611
|
+
}
|
|
587
612
|
|
|
588
613
|
const { type, id, payload } = data;
|
|
589
614
|
|
|
@@ -632,16 +657,7 @@ export abstract class AWSWebSocketProvider {
|
|
|
632
657
|
}
|
|
633
658
|
|
|
634
659
|
if (type === MESSAGE_TYPES.GQL_CONNECTION_KEEP_ALIVE) {
|
|
635
|
-
|
|
636
|
-
if (this.keepAliveAlertTimeoutId)
|
|
637
|
-
clearTimeout(this.keepAliveAlertTimeoutId);
|
|
638
|
-
this.keepAliveTimeoutId = setTimeout(() => {
|
|
639
|
-
this._errorDisconnect(CONTROL_MSG.TIMEOUT_DISCONNECT);
|
|
640
|
-
}, this.keepAliveTimeout);
|
|
641
|
-
this.keepAliveAlertTimeoutId = setTimeout(() => {
|
|
642
|
-
this.connectionStateMonitor.record(CONNECTION_CHANGE.KEEP_ALIVE_MISSED);
|
|
643
|
-
}, DEFAULT_KEEP_ALIVE_ALERT_TIMEOUT);
|
|
644
|
-
this.connectionStateMonitor.record(CONNECTION_CHANGE.KEEP_ALIVE);
|
|
660
|
+
this.maintainKeepAlive();
|
|
645
661
|
|
|
646
662
|
return;
|
|
647
663
|
}
|
|
@@ -686,13 +702,21 @@ export abstract class AWSWebSocketProvider {
|
|
|
686
702
|
this.logger.debug(`Disconnect error: ${msg}`);
|
|
687
703
|
|
|
688
704
|
if (this.awsRealTimeSocket) {
|
|
689
|
-
this.
|
|
705
|
+
this._closeSocket();
|
|
690
706
|
this.awsRealTimeSocket.close();
|
|
691
707
|
}
|
|
692
708
|
|
|
693
709
|
this.socketStatus = SOCKET_STATUS.CLOSED;
|
|
694
710
|
}
|
|
695
711
|
|
|
712
|
+
private _closeSocket() {
|
|
713
|
+
if (this.keepAliveHeartbeatIntervalId) {
|
|
714
|
+
clearInterval(this.keepAliveHeartbeatIntervalId);
|
|
715
|
+
this.keepAliveHeartbeatIntervalId = undefined;
|
|
716
|
+
}
|
|
717
|
+
this.connectionStateMonitor.record(CONNECTION_CHANGE.CLOSED);
|
|
718
|
+
}
|
|
719
|
+
|
|
696
720
|
private _timeoutStartSubscriptionAck(subscriptionId: string) {
|
|
697
721
|
const subscriptionObserver =
|
|
698
722
|
this.subscriptionObserverMap.get(subscriptionId);
|
|
@@ -708,7 +732,7 @@ export abstract class AWSWebSocketProvider {
|
|
|
708
732
|
subscriptionState: SUBSCRIPTION_STATUS.FAILED,
|
|
709
733
|
});
|
|
710
734
|
|
|
711
|
-
this.
|
|
735
|
+
this._closeSocket();
|
|
712
736
|
this.logger.debug(
|
|
713
737
|
'timeoutStartSubscription',
|
|
714
738
|
JSON.stringify({ query, variables }),
|
|
@@ -820,6 +844,7 @@ export abstract class AWSWebSocketProvider {
|
|
|
820
844
|
this.logger.debug(`WebSocket connection error`);
|
|
821
845
|
};
|
|
822
846
|
newSocket.onclose = () => {
|
|
847
|
+
this._closeSocket();
|
|
823
848
|
reject(new Error('Connection handshake error'));
|
|
824
849
|
};
|
|
825
850
|
newSocket.onopen = () => {
|
|
@@ -849,6 +874,7 @@ export abstract class AWSWebSocketProvider {
|
|
|
849
874
|
|
|
850
875
|
this.awsRealTimeSocket.onclose = event => {
|
|
851
876
|
this.logger.debug(`WebSocket closed ${event.reason}`);
|
|
877
|
+
this._closeSocket();
|
|
852
878
|
reject(new Error(JSON.stringify(event)));
|
|
853
879
|
};
|
|
854
880
|
|
|
@@ -912,7 +938,11 @@ export abstract class AWSWebSocketProvider {
|
|
|
912
938
|
return;
|
|
913
939
|
}
|
|
914
940
|
|
|
915
|
-
this
|
|
941
|
+
// Setup a keep alive heartbeat for this connection
|
|
942
|
+
this.keepAliveHeartbeatIntervalId = setInterval(() => {
|
|
943
|
+
this.keepAliveHeartbeat(connectionTimeoutMs);
|
|
944
|
+
}, DEFAULT_KEEP_ALIVE_HEARTBEAT_TIMEOUT);
|
|
945
|
+
|
|
916
946
|
this.awsRealTimeSocket.onmessage =
|
|
917
947
|
this._handleIncomingSubscriptionMessage.bind(this);
|
|
918
948
|
|
|
@@ -923,6 +953,7 @@ export abstract class AWSWebSocketProvider {
|
|
|
923
953
|
|
|
924
954
|
this.awsRealTimeSocket.onclose = event => {
|
|
925
955
|
this.logger.debug(`WebSocket closed ${event.reason}`);
|
|
956
|
+
this._closeSocket();
|
|
926
957
|
this._errorDisconnect(CONTROL_MSG.CONNECTION_CLOSED);
|
|
927
958
|
};
|
|
928
959
|
}
|
|
@@ -128,6 +128,11 @@ export const START_ACK_TIMEOUT = 15000;
|
|
|
128
128
|
*/
|
|
129
129
|
export const DEFAULT_KEEP_ALIVE_TIMEOUT = 5 * 60 * 1000;
|
|
130
130
|
|
|
131
|
+
/**
|
|
132
|
+
* Default Time in milleseconds between monitoring checks of keep alive status
|
|
133
|
+
*/
|
|
134
|
+
export const DEFAULT_KEEP_ALIVE_HEARTBEAT_TIMEOUT = 5 * 1000;
|
|
135
|
+
|
|
131
136
|
/**
|
|
132
137
|
* Default Time in milleseconds to alert for missed GQL_CONNECTION_KEEP_ALIVE message
|
|
133
138
|
*/
|