diff --git a/backend/src/api/bitcoin/esplora-api.ts b/backend/src/api/bitcoin/esplora-api.ts index 37f6e5892..0366695d1 100644 --- a/backend/src/api/bitcoin/esplora-api.ts +++ b/backend/src/api/bitcoin/esplora-api.ts @@ -1,8 +1,13 @@ import config from '../../config'; import axios, { AxiosRequestConfig } from 'axios'; +import http from 'http'; import { AbstractBitcoinApi } from './bitcoin-api-abstract-factory'; import { IEsploraApi } from './esplora-api.interface'; +const axiosConnection = axios.create({ + httpAgent: new http.Agent({ keepAlive: true }) +}); + class ElectrsApi implements AbstractBitcoinApi { axiosConfig: AxiosRequestConfig = { timeout: 10000, @@ -11,52 +16,52 @@ class ElectrsApi implements AbstractBitcoinApi { constructor() { } $getRawMempool(): Promise { - return axios.get(config.ESPLORA.REST_API_URL + '/mempool/txids', this.axiosConfig) + return axiosConnection.get(config.ESPLORA.REST_API_URL + '/mempool/txids', this.axiosConfig) .then((response) => response.data); } $getRawTransaction(txId: string): Promise { - return axios.get(config.ESPLORA.REST_API_URL + '/tx/' + txId, this.axiosConfig) + return axiosConnection.get(config.ESPLORA.REST_API_URL + '/tx/' + txId, this.axiosConfig) .then((response) => response.data); } $getTransactionHex(txId: string): Promise { - return axios.get(config.ESPLORA.REST_API_URL + '/tx/' + txId + '/hex', this.axiosConfig) + return axiosConnection.get(config.ESPLORA.REST_API_URL + '/tx/' + txId + '/hex', this.axiosConfig) .then((response) => response.data); } $getBlockHeightTip(): Promise { - return axios.get(config.ESPLORA.REST_API_URL + '/blocks/tip/height', this.axiosConfig) + return axiosConnection.get(config.ESPLORA.REST_API_URL + '/blocks/tip/height', this.axiosConfig) .then((response) => response.data); } $getBlockHashTip(): Promise { - return axios.get(config.ESPLORA.REST_API_URL + '/blocks/tip/hash', this.axiosConfig) + return axiosConnection.get(config.ESPLORA.REST_API_URL + '/blocks/tip/hash', this.axiosConfig) .then((response) => response.data); } $getTxIdsForBlock(hash: string): Promise { - return axios.get(config.ESPLORA.REST_API_URL + '/block/' + hash + '/txids', this.axiosConfig) + return axiosConnection.get(config.ESPLORA.REST_API_URL + '/block/' + hash + '/txids', this.axiosConfig) .then((response) => response.data); } $getBlockHash(height: number): Promise { - return axios.get(config.ESPLORA.REST_API_URL + '/block-height/' + height, this.axiosConfig) + return axiosConnection.get(config.ESPLORA.REST_API_URL + '/block-height/' + height, this.axiosConfig) .then((response) => response.data); } $getBlockHeader(hash: string): Promise { - return axios.get(config.ESPLORA.REST_API_URL + '/block/' + hash + '/header', this.axiosConfig) + return axiosConnection.get(config.ESPLORA.REST_API_URL + '/block/' + hash + '/header', this.axiosConfig) .then((response) => response.data); } $getBlock(hash: string): Promise { - return axios.get(config.ESPLORA.REST_API_URL + '/block/' + hash, this.axiosConfig) + return axiosConnection.get(config.ESPLORA.REST_API_URL + '/block/' + hash, this.axiosConfig) .then((response) => response.data); } $getRawBlock(hash: string): Promise { - return axios.get(config.ESPLORA.REST_API_URL + '/block/' + hash + "/raw", { ...this.axiosConfig, responseType: 'arraybuffer' }) + return axiosConnection.get(config.ESPLORA.REST_API_URL + '/block/' + hash + "/raw", { ...this.axiosConfig, responseType: 'arraybuffer' }) .then((response) => { return Buffer.from(response.data); }); } @@ -77,12 +82,12 @@ class ElectrsApi implements AbstractBitcoinApi { } $getOutspend(txId: string, vout: number): Promise { - return axios.get(config.ESPLORA.REST_API_URL + '/tx/' + txId + '/outspend/' + vout, this.axiosConfig) + return axiosConnection.get(config.ESPLORA.REST_API_URL + '/tx/' + txId + '/outspend/' + vout, this.axiosConfig) .then((response) => response.data); } $getOutspends(txId: string): Promise { - return axios.get(config.ESPLORA.REST_API_URL + '/tx/' + txId + '/outspends', this.axiosConfig) + return axiosConnection.get(config.ESPLORA.REST_API_URL + '/tx/' + txId + '/outspends', this.axiosConfig) .then((response) => response.data); } diff --git a/backend/src/index.ts b/backend/src/index.ts index a81275066..919c039c3 100644 --- a/backend/src/index.ts +++ b/backend/src/index.ts @@ -36,6 +36,7 @@ import bitcoinRoutes from './api/bitcoin/bitcoin.routes'; import fundingTxFetcher from './tasks/lightning/sync-tasks/funding-tx-fetcher'; import forensicsService from './tasks/lightning/forensics.service'; import priceUpdater from './tasks/price-updater'; +import { AxiosError } from 'axios'; class Server { private wss: WebSocket.Server | undefined; @@ -178,7 +179,7 @@ class Server { setTimeout(this.runMainUpdateLoop.bind(this), config.MEMPOOL.POLL_RATE_MS); this.currentBackendRetryInterval = 5; - } catch (e) { + } catch (e: any) { const loggerMsg = `runMainLoop error: ${(e instanceof Error ? e.message : e)}. Retrying in ${this.currentBackendRetryInterval} sec.`; if (this.currentBackendRetryInterval > 5) { logger.warn(loggerMsg); @@ -186,7 +187,9 @@ class Server { } else { logger.debug(loggerMsg); } - logger.debug(JSON.stringify(e)); + if (e instanceof AxiosError) { + logger.debug(`AxiosError: ${e?.message}`); + } setTimeout(this.runMainUpdateLoop.bind(this), 1000 * this.currentBackendRetryInterval); this.currentBackendRetryInterval *= 2; this.currentBackendRetryInterval = Math.min(this.currentBackendRetryInterval, 60);