Skip to content
This repository has been archived by the owner on Jun 11, 2024. It is now read-only.

Commit

Permalink
🔨 Refactor client.js
Browse files Browse the repository at this point in the history
  • Loading branch information
sameersubudhi committed Jan 4, 2024
1 parent 0cdc650 commit f8739c3
Show file tree
Hide file tree
Showing 8 changed files with 49 additions and 41 deletions.
2 changes: 1 addition & 1 deletion docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ services:
- SERVICE_BROKER=nats://nats:4222
- GEOIP_JSON=${GEOIP_JSON}
- LISK_APP_WS=${LISK_APP_WS}
- USE_HTTP_API=${USE_HTTP_API}
- USE_LISK_HTTP_API=${USE_LISK_HTTP_API}
- LISK_APP_HTTP=${LISK_APP_HTTP}
- SERVICE_BROKER_TIMEOUT=${SERVICE_BROKER_TIMEOUT}
- SERVICE_LOG_CONSOLE=${SERVICE_LOG_CONSOLE}
Expand Down
2 changes: 1 addition & 1 deletion docker/example.env
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@

# Lisk ecosystem configuration
LISK_APP_WS=ws://host.docker.internal:7887
# USE_HTTP_API=true
# USE_LISK_HTTP_API=true
# LISK_APP_HTTP=http://host.docker.internal:7887

# Lisk Service geolocation backend (empty = disabled)
Expand Down
2 changes: 1 addition & 1 deletion docs/antora/modules/ROOT/pages/configuration/index.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -373,7 +373,7 @@ By default, it is set to `ws://127.0.0.1:7887`.
By default, it is set to `http://127.0.0.1:7887`.
| http://127.0.0.1:7887

| `USE_HTTP_API`
| `USE_LISK_HTTP_API`
| boolean
| Boolean flag to enable HTTP-API based connection to the Lisk application node.
| true
Expand Down
2 changes: 1 addition & 1 deletion ecosystem.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ module.exports = {
SERVICE_BROKER: 'redis://lisk:password@127.0.0.1:6379/0',
// USE_LISK_IPC_CLIENT: true,
// LISK_APP_DATA_PATH: '~/.lisk/lisk-core',
// USE_HTTP_API: true,
// USE_LISK_HTTP_API: true,
// LISK_APP_HTTP: 'http://127.0.0.1:7887',
// LISK_APP_WS: 'ws://127.0.0.1:7887',
// GEOIP_JSON: 'https://geoip.lisk.com/json',
Expand Down
2 changes: 1 addition & 1 deletion services/blockchain-connector/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ A list of the most commonly used environment variables is presented below:
- `SERVICE_BROKER`: URL of the microservice message broker (NATS or Redis).
- `LISK_APP_WS`: URL to connect with the Lisk SDK-based application node over WebSocket. By default, it is set to `ws://127.0.0.1:7887`.
- `LISK_APP_HTTP`: URL to connect with the Lisk SDK-based application node over HTTP(s). By default, it is set to `http://127.0.0.1:7887`.
- `USE_HTTP_API`: Boolean flag to enable HTTP-API based connection to the Lisk SDK-based application node.
- `USE_LISK_HTTP_API`: Boolean flag to enable HTTP-API based connection to the Lisk SDK-based application node.
- `USE_LISK_IPC_CLIENT`: Boolean flag to enable IPC-based connection to the Lisk SDK-based application node. Not applicable to a docker-based setup.
- `LISK_APP_DATA_PATH`: Data path to connect with the Lisk SDK-based application node over IPC. Not applicable to a docker-based setup.
- `GENESIS_BLOCK_URL`: URL of the Lisk SDK-based application' genesis block. Only to be used when the genesis block is large enough to be transmitted over API calls within the timeout.
Expand Down
2 changes: 1 addition & 1 deletion services/blockchain-connector/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ config.endpoints.geoip = process.env.GEOIP_JSON || 'https://geoip.lisk.com/json'
/**
* API Client related settings
*/
config.isUseHttpApi = Boolean(String(process.env.USE_HTTP_API).toLowerCase() === 'true'); // Disabled by default
config.isUseHttpApi = Boolean(String(process.env.USE_LISK_HTTP_API).toLowerCase() === 'true'); // Disabled by default
config.isUseLiskIPCClient = Boolean(
String(process.env.USE_LISK_IPC_CLIENT).toLowerCase() === 'true',
);
Expand Down
72 changes: 40 additions & 32 deletions services/blockchain-connector/shared/sdk/client.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,11 @@ const delay = require('../utils/delay');
const logger = Logger();

// Constants
const timeoutMessage = 'Response not received in';
const HTTP_TIMEOUT_STATUS = 'ETIMEDOUT';
const RPC_TIMEOUT_MESSAGE = 'Response not received in';
const TIMEOUT_REGEX_STR = `(?:${HTTP_TIMEOUT_STATUS}|${RPC_TIMEOUT_MESSAGE})`;
const TIMEOUT_REGEX = new RegExp(TIMEOUT_REGEX_STR);

const liskAddressWs = config.endpoints.liskWs;
const liskAddressHttp = config.endpoints.liskHttp;
const NUM_REQUEST_RETRIES = config.apiClient.request.maxRetries;
Expand All @@ -46,22 +50,21 @@ const checkIsClientAlive = async clientCache =>
return resolve(false);
}

// Skip heartbeat check for IPC client
if (config.isUseLiskIPCClient) {
return resolve(true);
return resolve(clientCache._channel.isAlive);
}

const heartbeatCheckBeginTime = Date.now();
const wsInstance = clientCache._channel._ws;
const wsClientInstance = clientCache._channel._ws;

// eslint-disable-next-line no-use-before-define
const boundPongListener = () => pongListener(resolve);
wsInstance.on('pong', boundPongListener);
wsInstance.ping(() => {});
wsClientInstance.on('pong', boundPongListener);
wsClientInstance.ping(() => {});

// eslint-disable-next-line consistent-return
const timeout = setTimeout(() => {
wsInstance.removeListener('pong', boundPongListener);
wsClientInstance.removeListener('pong', boundPongListener);
logger.debug(
`Did not receive API client pong after ${Date.now() - heartbeatCheckBeginTime}ms.`,
);
Expand All @@ -70,7 +73,7 @@ const checkIsClientAlive = async clientCache =>

const pongListener = res => {
clearTimeout(timeout);
wsInstance.removeListener('pong', boundPongListener);
wsClientInstance.removeListener('pong', boundPongListener);
logger.debug(`Received API client pong in ${Date.now() - heartbeatCheckBeginTime}ms.`);
return res(true);
};
Expand Down Expand Up @@ -118,40 +121,47 @@ const getApiClient = async () => {
return cachedApiClients[0];
};

const isResponse2XX = response => String(response.status).startsWith('2');
const is2XXResponse = response => String(response.status).startsWith('2');
const isSuccessResponse = response => is2XXResponse(response) && response.data.result;

const buildHTTPResponse = (endpoint, params, response) => {
if (isSuccessResponse(response)) return response.data.result;

let id = -1;
const errorMessage =
response.data && response.data.error
? response.data.error.message
: `${response.status}: ${response.message}`;
logger.trace(
`Error invoking endpoint '${endpoint}' with params ${JSON.stringify(params)}:\n${errorMessage}`,
);
throw new Error(errorMessage);
};

let id = 0;
// eslint-disable-next-line consistent-return
const invokeEndpoint = async (endpoint, params = {}, numRetries = NUM_REQUEST_RETRIES) => {
let retriesLeft = numRetries;
do {
id++;
try {
if (config.isUseHttpApi) {
// HTTP API-based communication with the Lisk app node
const rpcRequest = {
jsonrpc: '2.0',
id,
id: id++,
method: endpoint,
params,
};

const response = await HTTP.post(`${liskAddressHttp}/rpc`, rpcRequest);
return isResponse2XX(response)
? response.data.result
: (() => {
logger.trace(
`Error when invoking endpoint ${endpoint} with params ${JSON.stringify(params)}: ${
response.data.error.message
}`,
);
throw new Error(response.data.error);
})();
return buildHTTPResponse(endpoint, params, response);
}

// WS and IPC client-based communication with the Lisk app node
const apiClient = await getApiClient();
const response = await apiClient._channel.invoke(endpoint, params);
return response;
} catch (err) {
if (err.message.includes(timeoutMessage)) {
if (TIMEOUT_REGEX.test(err.message)) {
if (!retriesLeft) {
const exceptionMsg = Object.getOwnPropertyNames(params).length
? `Request timed out when calling '${endpoint}' with params:\n${JSON.stringify(
Expand Down Expand Up @@ -243,25 +253,23 @@ const resetApiClientListener = async () => {
};
Signals.get('resetApiClient').add(resetApiClientListener);

// Check periodically for client aliveness and refill cached clients pool
(async () => {
if (config.isUseHttpApi) return;
if (!config.isUseHttpApi) {
refreshClientsCache(); // Initialize the client cache

// eslint-disable-next-line no-constant-condition
while (true) {
// Periodically ensure API client liveliness
setInterval(async () => {
const cacheRefreshStartTime = Date.now();
await refreshClientsCache();
logger.debug(
`Refreshed API client cache in ${Date.now() - cacheRefreshStartTime}ms. There are ${
cachedApiClients.length
} API client(s) in the pool.`,
);
await delay(CLIENT_ALIVE_ASSUMPTION_TIME);
}
})();
}, CLIENT_ALIVE_ASSUMPTION_TIME);
}

module.exports = {
timeoutMessage,
TIMEOUT_REGEX,

getApiClient,
invokeEndpoint,
Expand Down
6 changes: 3 additions & 3 deletions services/blockchain-connector/shared/sdk/genesisBlock.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ const {
const { getNodeInfo } = require('./endpoints_1');
const { getGenesisBlockFromFS } = require('./blocksUtils');

const { timeoutMessage, invokeEndpoint } = require('./client');
const { TIMEOUT_REGEX, invokeEndpoint } = require('./client');
const { formatBlock } = require('./formatter');

Check notice

Code scanning / Semgrep

Semgrep Finding: javascript.lang.correctness.useless-assign.useless-assignment Note

const is assigned twice; the first assignment is useless

const logger = Logger();
Expand Down Expand Up @@ -57,7 +57,7 @@ const getGenesisBlock = async (isIncludeAssets = false) => {
const block = await invokeEndpoint('chain_getBlockByHeight', { height });
return block;
} catch (err) {
if (err.message.includes(timeoutMessage)) {
if (TIMEOUT_REGEX.test(err.message)) {
throw new TimeoutException("Request timed out when calling 'getGenesisBlock'.");
}
throw err;
Expand Down Expand Up @@ -85,7 +85,7 @@ const getGenesisConfig = async () => {
}
return genesisConfig;
} catch (err) {
if (err.message.includes(timeoutMessage)) {
if (TIMEOUT_REGEX.test(err.message)) {
throw new TimeoutException("Request timed out when calling 'getGenesisConfig'.");
}
throw err;
Expand Down

0 comments on commit f8739c3

Please sign in to comment.