Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix sdk retry mechanism #1140

Merged
merged 4 commits into from
Dec 20, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
ALL-1234: disable evicting nodes option
  • Loading branch information
Filip Kaštovský committed Dec 20, 2024
commit 874e4aea95a10d8913037e4fa59deeab5cbc87f9
2 changes: 1 addition & 1 deletion src/connector/tatum.connector.ts
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ export class TatumConnector {
}
const response = await res.json()
if (response?.error) {
return await this.retry(url, request, responseBody, retry)
return response
}
return response
}
Expand Down
31 changes: 26 additions & 5 deletions src/service/rpc/generic/LoadBalancer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,11 +81,16 @@ export class LoadBalancer implements AbstractRpcInterface {
}
private interval: ReturnType<typeof setInterval>
private network: Network
private evictNodesOnFailure: boolean
private noActiveNode = false

constructor(private readonly id: string) {
this.connector = Container.of(this.id).get(TatumConnector)
this.network = Container.of(this.id).get(CONFIG).network

const config = Container.of(this.id).get(CONFIG)
this.network = config.network
this.evictNodesOnFailure = !!config.rpc?.evictNodesOnFailure

this.logger = Container.of(this.id).get(LOGGER)
}

Expand Down Expand Up @@ -147,6 +152,12 @@ export class LoadBalancer implements AbstractRpcInterface {
}
}

private resetFailedStatuses(nodeType: RpcNodeType) {
for (const server of this.rpcUrls[nodeType]) {
server.failed = false
}
}

private async checkStatuses() {
try {
await this.checkStatus(RpcNodeType.NORMAL)
Expand Down Expand Up @@ -496,20 +507,30 @@ export class LoadBalancer implements AbstractRpcInterface {
throw e
}

const servers = this.rpcUrls[nodeType] as RpcStatus[]

/**
* If the node is not responding, it will be marked as failed.
* New node will be selected and will be used for the given blockchain.
*/
const servers = this.rpcUrls[nodeType] as RpcStatus[]

servers[activeIndex].failed = true

const { index, fastestServer } = LoadBalancer.getFastestServer(
servers,
rpcConfig?.allowedBlocksBehind as number,
)

if (index === -1) {
this.logger.error(
`Looks like your request is malformed or all RPC nodes are down. Turn on verbose mode to see more details and check status pages.`,
)
if (this.evictNodesOnFailure) {
this.logger.error(
`Looks like your request is malformed or all RPC nodes are down. Turn on verbose mode to see more details and check status pages.`,
)
} else {
// Recover failed nodes, prepare them for the next round of requests
this.resetFailedStatuses(nodeType)
}

throw e
}
Utils.log({
Expand Down
9 changes: 8 additions & 1 deletion src/service/tatum/tatum.dto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,9 +66,16 @@ export interface TatumConfig {
nodes?: RpcNode[]

/**
* If this is set to `true`, the SDK will not automatically load balance and failover between the available OpenRPC nodes and will use the fastest URL fetched during the startup. Defaults to `false`.
* If this is set to `true`, the SDK will not automatically load balance and failover between the available OpenRPC nodes and will use the fastest URL fetched during the startup. Defaults to `false` unless there only a single node is provided.
*/
oneTimeLoadBalancing?: boolean

/**
* If this is set to `true`, the SDK will evict nodes from routing pool if they are failing. If `oneTimeLoadBalancing` is set to `true` or you haven't provided your own rpc nodes, this parameter will default to `false`. Defaults to `true` otherwise.
*
* We discourage setting this to `true` if you are using `oneTimeLoadBalancing` as it will result in the SDK not being able to recover a failing node.
*/
evictNodesOnFailure?: boolean
}

/**
Expand Down
22 changes: 20 additions & 2 deletions src/service/tatum/tatum.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Container, Service } from 'typedi'
import { isLoadBalancerNetwork, Network } from '../../dto'
import { Network, isLoadBalancerNetwork } from '../../dto'
import { CONFIG, Constant, EnvUtils, LOGGER, LoggerUtils, Utils } from '../../util'
import {
ExtensionConstructor,
Expand Down Expand Up @@ -84,6 +84,10 @@ export class TatumSDK {

const mergedConfig = Utils.deepMerge(defaultConfig, config) as TatumConfig

if (mergedConfig.rpc && this.shouldEvictNodesOnFailure(mergedConfig)) {
mergedConfig.rpc.evictNodesOnFailure = true
}

LoggerUtils.setLoggerForEnv(mergedConfig, EnvUtils.isDevelopment(), EnvUtils.isBrowser())

// TODO: check when rpc is customized if there is allowedBlocksBehind if not throw error or set default
Expand All @@ -103,7 +107,9 @@ export class TatumSDK {
}

if (isLoadBalancerNetwork(mergedConfig.network)) {
const loadBalancer = Container.of(id).get(mergedConfig.network === Network.TRON ? TronLoadBalancer : LoadBalancer)
const loadBalancer = Container.of(id).get(
mergedConfig.network === Network.TRON ? TronLoadBalancer : LoadBalancer,
)
await loadBalancer.init()
}

Expand Down Expand Up @@ -185,4 +191,16 @@ export class TatumSDK {
}
return result
}

private static shouldEvictNodesOnFailure(config: TatumConfig): boolean | undefined {
if (config.rpc?.evictNodesOnFailure !== undefined && config.rpc?.oneTimeLoadBalancing !== null) {
return config.rpc.evictNodesOnFailure
}

if (!config.rpc?.nodes) {
return false
}

return !config.rpc?.oneTimeLoadBalancing
}
}
Loading