1818 *
1919 */
2020
21- import Axios , { AxiosInstance } from 'axios' ;
21+ import Axios , { AxiosInstance , AxiosRequestConfig } from 'axios' ;
2222import { MirrorNodeClientError } from './../errors/MirrorNodeClientError' ;
2323import { Logger } from "pino" ;
2424import constants from './../constants' ;
2525import { Histogram , Registry } from 'prom-client' ;
2626import { formatRequestIdMessage , formatTransactionId } from '../../formatters' ;
2727import axiosRetry from 'axios-retry' ;
2828import { predefined } from "../errors/JsonRpcError" ;
29+ const http = require ( 'http' ) ;
30+ const https = require ( 'https' ) ;
2931const LRU = require ( 'lru-cache' ) ;
3032
3133type REQUEST_METHODS = 'GET' | 'POST' ;
@@ -113,23 +115,53 @@ export class MirrorNodeClient {
113115 protected createAxiosClient (
114116 baseUrl : string
115117 ) : AxiosInstance {
118+ // defualt values for axios clients to mirror node
119+ const mirrorNodeTimeout = parseInt ( process . env . MIRROR_NODE_TIMEOUT || '10000' ) ;
120+ const mirrorNodeMaxRedirects = parseInt ( process . env . MIRROR_NODE_MAX_REDIRECTS || '5' ) ;
121+ const mirrorNodeHttpKeepAlive = process . env . MIRROR_NODE_HTTP_KEEP_ALIVE === 'true' ? true : false ;
122+ const mirrorNodeHttpKeepAliveMsecs = parseInt ( process . env . MIRROR_NODE_HTTP_KEEP_ALIVE_MSECS || '1000' ) ;
123+ const mirrorNodeHttpMaxSockets = parseInt ( process . env . MIRROR_NODE_HTTP_MAX_SOCKETS || '100' ) ;
124+ const mirrorNodeHttpMaxTotalSockets = parseInt ( process . env . MIRROR_NODE_HTTP_MAX_TOTAL_SOCKETS || '100' ) ;
125+ const mirrorNodeHttpSocketTimeout = parseInt ( process . env . MIRROR_NODE_HTTP_SOCKET_TIMEOUT || '60000' ) ;
126+ const isDevMode = process . env . DEV_MODE && process . env . DEV_MODE === 'true' ;
127+ const mirrorNodeRetries = parseInt ( process . env . MIRROR_NODE_RETRIES ! ) || 3 ;
128+ const mirrorNodeRetriesDevMode = parseInt ( process . env . MIRROR_NODE_RETRIES_DEVMODE ! ) || 5 ;
129+ const mirrorNodeRetryDelay = parseInt ( process . env . MIRROR_NODE_RETRY_DELAY ! ) || 250 ;
130+ const mirrorNodeRetryDelayDevMode = parseInt ( process . env . MIRROR_NODE_RETRY_DELAY_DEVMODE ! ) || 200 ;
131+
116132 const axiosClient : AxiosInstance = Axios . create ( {
117133 baseURL : baseUrl ,
118134 responseType : 'json' as const ,
119135 headers : {
120136 'Content-Type' : 'application/json'
121137 } ,
122- timeout : parseInt ( process . env . MIRROR_NODE_TIMEOUT || '10000' )
138+ timeout : mirrorNodeTimeout ,
139+ maxRedirects : mirrorNodeMaxRedirects ,
140+ // set http agent options to optimize performance - https://nodejs.org/api/http.html#new-agentoptions
141+ httpAgent : new http . Agent ( {
142+ keepAlive : mirrorNodeHttpKeepAlive ,
143+ keepAliveMsecs : mirrorNodeHttpKeepAliveMsecs ,
144+ maxSockets : mirrorNodeHttpMaxSockets ,
145+ maxTotalSockets : mirrorNodeHttpMaxTotalSockets ,
146+ timeout : mirrorNodeHttpSocketTimeout ,
147+ } ) ,
148+ httpsAgent : new https . Agent ( {
149+ keepAlive : mirrorNodeHttpKeepAlive ,
150+ keepAliveMsecs : mirrorNodeHttpKeepAliveMsecs ,
151+ maxSockets : mirrorNodeHttpMaxSockets ,
152+ maxTotalSockets : mirrorNodeHttpMaxTotalSockets ,
153+ timeout : mirrorNodeHttpSocketTimeout ,
154+ } ) ,
123155 } ) ;
124156 //@ts -ignore
125157 axiosRetry ( axiosClient , {
126- retries : parseInt ( process . env . MIRROR_NODE_RETRIES ! ) || 3 ,
158+ retries : isDevMode ? mirrorNodeRetriesDevMode : mirrorNodeRetries ,
127159 retryDelay : ( retryCount , error ) => {
128160 const request = error ?. request ?. _header ;
129161 const requestId = request ? request . split ( '\n' ) [ 3 ] . substring ( 11 , 47 ) : '' ;
130162 const requestIdPrefix = formatRequestIdMessage ( requestId ) ;
131- const delay = ( parseInt ( process . env . MIRROR_NODE_RETRY_DELAY ! ) || 250 ) * retryCount ;
132- this . logger . trace ( `${ requestIdPrefix } Retry delay ${ delay } ms` ) ;
163+ const delay = isDevMode ? mirrorNodeRetryDelayDevMode : mirrorNodeRetryDelay * retryCount ;
164+ this . logger . trace ( `${ requestIdPrefix } Retry delay ${ delay } ms` ) ;
133165 return delay ;
134166 } ,
135167 retryCondition : ( error ) => {
@@ -198,7 +230,7 @@ export class MirrorNodeClient {
198230 try {
199231 let response ;
200232
201- const axiosRequestConfig = {
233+ const axiosRequestConfig : AxiosRequestConfig = {
202234 headers :{
203235 'requestId' : requestId || ''
204236 } ,
@@ -220,8 +252,13 @@ export class MirrorNodeClient {
220252 ms = Date . now ( ) - start ;
221253 const effectiveStatusCode = error . response ?. status || MirrorNodeClientError . ErrorCodes [ error . code ] || MirrorNodeClient . unknownServerErrorHttpStatusCode ;
222254 this . mirrorResponseHistogram . labels ( pathLabel , effectiveStatusCode ) . observe ( ms ) ;
223- this . handleError ( error , path , effectiveStatusCode , method , controller , allowedErrorStatuses , requestId ) ;
255+
256+ // always abort the request on failure as the axios call can hang until the parent code/stack times out (might be a few minutes in a server-side applications)
257+ controller . abort ( ) ;
258+
259+ this . handleError ( error , path , effectiveStatusCode , method , allowedErrorStatuses , requestId ) ;
224260 }
261+
225262 return null ;
226263 }
227264
@@ -234,12 +271,8 @@ export class MirrorNodeClient {
234271 return this . request ( path , pathLabel , 'POST' , data , allowedErrorStatuses , requestId ) ;
235272 }
236273
237- handleError ( error : any , path : string , effectiveStatusCode : number , method : REQUEST_METHODS , controller : AbortController , allowedErrorStatuses ?: number [ ] , requestId ?: string ) {
238- const mirrorError = new MirrorNodeClientError ( error , effectiveStatusCode ) ;
239- if ( mirrorError . isTimeout ( ) ) {
240- controller . abort ( ) ;
241- }
242-
274+ handleError ( error : any , path : string , effectiveStatusCode : number , method : REQUEST_METHODS , allowedErrorStatuses ?: number [ ] , requestId ?: string ) {
275+ const mirrorError = new MirrorNodeClientError ( error , effectiveStatusCode ) ;
243276 const requestIdPrefix = formatRequestIdMessage ( requestId ) ;
244277 if ( allowedErrorStatuses && allowedErrorStatuses . length ) {
245278 if ( error . response && allowedErrorStatuses . indexOf ( effectiveStatusCode ) !== - 1 ) {
0 commit comments