diff --git a/node/coinstacks/common/api/src/evm/service.ts b/node/coinstacks/common/api/src/evm/service.ts index fe4d2e6be..25ea79ad7 100644 --- a/node/coinstacks/common/api/src/evm/service.ts +++ b/node/coinstacks/common/api/src/evm/service.ts @@ -31,7 +31,7 @@ import { ERC1155_ABI } from './abi/erc1155' import { ERC721_ABI } from './abi/erc721' const axiosNoRetry = axios.create({ timeout: 5000 }) -const axiosWithRetry = createAxiosRetry({ timeout: 10000 }) +const axiosWithRetry = createAxiosRetry({}, { timeout: 10000 }) type InternalTxFetchMethod = 'trace_transaction' | 'debug_traceTransaction' diff --git a/node/coinstacks/common/api/src/utils.ts b/node/coinstacks/common/api/src/utils.ts index 53ec0f880..0a235bf52 100644 --- a/node/coinstacks/common/api/src/utils.ts +++ b/node/coinstacks/common/api/src/utils.ts @@ -32,17 +32,22 @@ export const handleError = (err: unknown): ApiError => { return new ApiError('Internal Server Error', 500, 'unknown error') } -export const createAxiosRetry = (axiosParams?: CreateAxiosDefaults) => { +type RetryConfig = { + retries?: number + delayFactor?: number +} + +export const createAxiosRetry = (config: RetryConfig, axiosParams?: CreateAxiosDefaults) => { const axiosWithRetry = axios.create(axiosParams) axiosRetry(axiosWithRetry, { shouldResetTimeout: true, - retries: 5, + retries: config.retries ?? 5, retryDelay: (retryCount, err) => { // don't add delay on top of request timeout if (err.code === 'ECONNABORTED') return 0 // add exponential delay for network errors - return axiosRetry.exponentialDelay(retryCount, undefined, 500) + return axiosRetry.exponentialDelay(retryCount, undefined, config.delayFactor ?? 500) }, retryCondition: (err) => isNetworkOrIdempotentRequestError(err) || diff --git a/node/coinstacks/solana/api/src/utils.ts b/node/coinstacks/solana/api/src/utils.ts index 332589dd1..1b70126b4 100644 --- a/node/coinstacks/solana/api/src/utils.ts +++ b/node/coinstacks/solana/api/src/utils.ts @@ -10,7 +10,14 @@ if (!INDEXER_URL) throw new Error('INDEXER_URL env var not set') if (!RPC_API_KEY) throw new Error('RPC_API_KEY env var not set') export const axiosNoRetry = axios.create({ timeout: 5000, params: { 'api-key': RPC_API_KEY } }) -export const axiosWithRetry = createAxiosRetry({ timeout: 10000, params: { 'api-key': RPC_API_KEY } }) + +// Amounts to ~1 minutes worth of potential retries to account for logsSubscribe "confirmed" commit level +// and /transactions only returning "finalized" transactions. The "confirmed" commit level is required for logsSubscribe +// because "finalized" commit level is not stable and misses logs frequently. +export const axiosWithRetry = createAxiosRetry( + { retries: 6, delayFactor: 1000 }, + { timeout: 10000, params: { 'api-key': RPC_API_KEY } } +) export const getTransaction = async (txid: string, shouldRetry?: boolean, retryCount = 0): Promise => { try { diff --git a/node/coinstacks/solana/api/src/websocket.ts b/node/coinstacks/solana/api/src/websocket.ts index d4fb7907a..598b40f4d 100644 --- a/node/coinstacks/solana/api/src/websocket.ts +++ b/node/coinstacks/solana/api/src/websocket.ts @@ -91,7 +91,7 @@ export class WebsocketClient extends BaseWebsocketClient { jsonrpc: '2.0', id: this.currentId.toString(), method: 'logsSubscribe', - params: [{ mentions: [address] }], + params: [{ mentions: [address] }, { commitment: 'confirmed' }], } try {