@@ -54,6 +54,7 @@ export class HubConnection {
54
54
private connectionStarted : boolean ;
55
55
private startPromise ?: Promise < void > ;
56
56
private stopPromise ?: Promise < void > ;
57
+ private nextKeepAlive : number = 0 ;
57
58
58
59
// The type of these a) doesn't matter and b) varies when building in browser and node contexts
59
60
// Since we're building the WebPack bundle directly from the TypeScript, this matters (previously
@@ -73,6 +74,8 @@ export class HubConnection {
73
74
*
74
75
* The default value is 15,000 milliseconds (15 seconds).
75
76
* Allows the server to detect hard disconnects (like when a client unplugs their computer).
77
+ * The ping will happen at most as often as the server pings.
78
+ * If the server pings every 5 seconds, a value lower than 5 will ping every 5 seconds.
76
79
*/
77
80
public keepAliveIntervalInMilliseconds : number ;
78
81
@@ -603,24 +606,38 @@ export class HubConnection {
603
606
return ;
604
607
}
605
608
609
+ // Set the time we want the next keep alive to be sent
610
+ // Timer will be setup on next message receive
611
+ this . nextKeepAlive = new Date ( ) . getTime ( ) + this . keepAliveIntervalInMilliseconds ;
612
+
606
613
this . cleanupPingTimer ( ) ;
607
- this . pingServerHandle = setTimeout ( async ( ) => {
608
- if ( this . connectionState === HubConnectionState . Connected ) {
609
- try {
610
- await this . sendMessage ( this . cachedPingMessage ) ;
611
- } catch {
612
- // We don't care about the error. It should be seen elsewhere in the client.
613
- // The connection is probably in a bad or closed state now, cleanup the timer so it stops triggering
614
- this . cleanupPingTimer ( ) ;
615
- }
616
- }
617
- } , this . keepAliveIntervalInMilliseconds ) ;
618
614
}
619
615
620
616
private resetTimeoutPeriod ( ) {
621
617
if ( ! this . connection . features || ! this . connection . features . inherentKeepAlive ) {
622
618
// Set the timeout timer
623
619
this . timeoutHandle = setTimeout ( ( ) => this . serverTimeout ( ) , this . serverTimeoutInMilliseconds ) ;
620
+
621
+ // Set keepAlive timer if there isn't one
622
+ if ( this . pingServerHandle === undefined ) {
623
+ let nextPing = this . nextKeepAlive - new Date ( ) . getTime ( ) ;
624
+ if ( nextPing < 0 ) {
625
+ nextPing = 0 ;
626
+ }
627
+
628
+ // The timer needs to be set from a networking callback to avoid Chrome timer throttling from causing timers to run once a minute
629
+ this . pingServerHandle = setTimeout ( async ( ) => {
630
+ if ( this . connectionState === HubConnectionState . Connected ) {
631
+ try {
632
+ await this . sendMessage ( this . cachedPingMessage ) ;
633
+ } catch {
634
+ // We don't care about the error. It should be seen elsewhere in the client.
635
+ // The connection is probably in a bad or closed state now, cleanup the timer so it stops triggering
636
+ this . cleanupPingTimer ( ) ;
637
+ }
638
+ }
639
+ } , nextPing ) ;
640
+ }
624
641
}
625
642
}
626
643
@@ -811,6 +828,7 @@ export class HubConnection {
811
828
private cleanupPingTimer ( ) : void {
812
829
if ( this . pingServerHandle ) {
813
830
clearTimeout ( this . pingServerHandle ) ;
831
+ this . pingServerHandle = undefined ;
814
832
}
815
833
}
816
834
0 commit comments