@@ -13,7 +13,12 @@ import {
1313 type WebSocketTransportConfig ,
1414} from '../../src/transports'
1515import { SingleNumberResultResponse , sleep } from '../../src/util'
16- import { mockWebSocketProvider , runAllUntilTime , TestAdapter } from '../../src/util/testing-utils'
16+ import {
17+ mockWebSocketProvider ,
18+ runAllUntil ,
19+ runAllUntilTime ,
20+ TestAdapter ,
21+ } from '../../src/util/testing-utils'
1722import { InputParameters } from '../../src/validation'
1823
1924export const test = untypedTest as TestFn < {
@@ -487,6 +492,78 @@ test.serial('reconnects if provider stops sending expected messages', async (t)
487492 await t . context . clock . runToLastAsync ( )
488493} )
489494
495+ test . serial ( 'should not inflate failover metric while connection is closed' , async ( t ) => {
496+ const base = 'ETH'
497+ const quote = 'DOGE'
498+ const WS_SUBSCRIPTION_UNRESPONSIVE_TTL = 120_000
499+ process . env [ 'METRICS_ENABLED' ] = 'true'
500+ eaMetrics . clear ( )
501+
502+ // Mock WS
503+ mockWebSocketProvider ( WebSocketClassProvider )
504+ const mockWsServer = new Server ( ENDPOINT_URL , { mock : false } )
505+ let connectionCounter = 0
506+
507+ mockWsServer . on ( 'connection' , ( socket ) => {
508+ let counter = 0
509+ const parseMessage = ( ) => {
510+ if ( counter ++ === 0 ) {
511+ socket . send ( JSON . stringify ( { error : '' } ) )
512+ }
513+ }
514+ connectionCounter ++
515+ socket . on ( 'message' , parseMessage )
516+ } )
517+
518+ const adapter = createAdapter ( {
519+ WS_SUBSCRIPTION_TTL : 30_000 ,
520+ WS_SUBSCRIPTION_UNRESPONSIVE_TTL ,
521+ } )
522+
523+ const testAdapter = await TestAdapter . startWithMockedCache ( adapter , t . context )
524+
525+ const error = await testAdapter . request ( {
526+ base,
527+ quote,
528+ } )
529+ t . is ( error . statusCode , 504 )
530+
531+ await runAllUntil ( t . context . clock , ( ) => connectionCounter >= 1 )
532+ t . is ( connectionCounter , 1 )
533+
534+ await runAllUntilTime ( t . context . clock , WS_SUBSCRIPTION_UNRESPONSIVE_TTL + 1000 )
535+
536+ // The connection was closed because it was unresponsive but it wasn't
537+ // reopened because all the subscriptions expired.
538+ t . is ( connectionCounter , 1 )
539+ ; ( await testAdapter . getMetrics ( ) ) . assert ( t , {
540+ name : 'ws_connection_failover_count' ,
541+ labels : {
542+ transport_name : 'default_single_transport' ,
543+ url : ENDPOINT_URL ,
544+ } ,
545+ expectedValue : 1 ,
546+ } )
547+
548+ // Even after waiting a long time, the connection counter and failover metric
549+ // should remain the same.
550+ await runAllUntilTime ( t . context . clock , 2 * WS_SUBSCRIPTION_UNRESPONSIVE_TTL )
551+ t . is ( connectionCounter , 1 )
552+ ; ( await testAdapter . getMetrics ( ) ) . assert ( t , {
553+ name : 'ws_connection_failover_count' ,
554+ labels : {
555+ transport_name : 'default_single_transport' ,
556+ url : ENDPOINT_URL ,
557+ } ,
558+ expectedValue : 1 ,
559+ } )
560+
561+ testAdapter . api . close ( )
562+ mockWsServer . close ( )
563+ await t . context . clock . runToLastAsync ( )
564+ process . env [ 'METRICS_ENABLED' ] = 'false'
565+ } )
566+
490567test . serial ( 'resubscribes after reconnection if server closes connection' , async ( t ) => {
491568 const base = 'ETH'
492569 const quote = 'DOGE'
0 commit comments