retry count check

build err fix

retry condition testcase

retryCount to maxRetryCount

Signed-off-by: sapthasurendran <saptha.surendran@ibm.com>
This commit is contained in:
sapthasurendran 2021-07-30 14:19:10 +05:30 committed by James Taylor
parent 73049e0153
commit b8509490ad
7 changed files with 148 additions and 5 deletions

View file

@ -21,6 +21,8 @@ PORT=3000
RETRY_DELAY=3000
MAX_RETRY_COUNT=5
HLF_CONNECTION_PROFILE_ORG1=$(cat ${CONNECTION_PROFILE_FILE_ORG1} | jq -c .)
HLF_CERTIFICATE_ORG1="$(cat ${CERTIFICATE_FILE_ORG1} | sed -e 's/$/\\n/' | tr -d '\r\n')"

View file

@ -7,6 +7,7 @@ export const logLevel = 'info';
export const port = '3000';
export const retryDelay = '3000';
export const maxRetryCount = 5;
export const asLocalHost = true;
@ -46,7 +47,7 @@ export const redisHost = 'localhost';
export const redisPort = '6379';
export const redisUsername = 'conga';
export const redisUsername = '';
export const redisPassword = '';

View file

@ -32,10 +32,22 @@ mocked(Gateway.prototype.getNetwork).mockResolvedValue({
addBlockListener: jest.fn(),
removeBlockListener: jest.fn(),
});
const getMockedNetwork = (getContract = jest.fn()) => {
return mocked(Gateway.prototype.getNetwork).mockResolvedValue({
getGateway: jest.fn(),
getContract,
getChannel: jest.fn(),
addCommitListener: jest.fn(),
removeCommitListener: jest.fn(),
addBlockListener: jest.fn(),
removeBlockListener: jest.fn(),
});
};
export {
DefaultEventHandlerStrategies,
DefaultQueryHandlerStrategies,
Gateway,
Wallets,
getMockedNetwork,
};

View file

@ -0,0 +1,97 @@
import { retryTransaction } from '../fabric';
import { getMockedNetwork } from '../__mocks__/fabric-network';
import { Redis } from 'ioredis';
import * as redis from '../redis';
// import { Gateway, Gateway, Gateway } from 'fabric-network';
/**
* retryTransaction
*/
jest.mock('../config');
describe('Testing retryTransaction', () => {
let contract: any = null;
const transaction = {
submit: jest.fn().mockRejectedValue({}),
};
const mockedContact = {
deserializeTransaction: jest.fn().mockReturnValue(transaction),
};
beforeAll(async () => {
const rejectableGetContract = jest.fn().mockImplementation(
() =>
mockedContact
);
const network = getMockedNetwork(rejectableGetContract)('');
contract = (await network).getContract('');
});
describe('Check retry condition ', () => {
const transactionId =
'0ae62c01e4c4b112c3f3954a2f11243da76778e46df9ad2783bcbafc79652b95';
const key = `txn:${transactionId}`;
const state = `{"name":"CreateAsset","nonce":"damqinq8nrI4n4qY8lFVsZw7RwG2ufrv","transactionId":${transactionId}`;
const args = '["test111","red",400,"Jean",101]';
const timestamp = 1628078044362;
const savedTransaction = {
timestamp: timestamp.toString(),
state: state,
retries: '',
args: args,
};
let data: Record<string, any> = {};
beforeEach(() => {
data = {};
const clearTransactionDetails = jest.spyOn(
redis,
'clearTransactionDetails'
);
clearTransactionDetails.mockImplementation(
async (redis: Redis, transactionId: string) => {
const key = `txn:${transactionId}`;
delete data[key];
}
);
const incrementRetryCount = jest.spyOn(redis, 'incrementRetryCount');
incrementRetryCount.mockImplementation(
async (redis: Redis, transactionId: string) => {
const key = `txn:${transactionId}`;
data[key].retries = (parseInt(data[key].retries) + 1).toString();
}
);
});
it('Transaction should exist if retry count is less then max rety count', async () => {
savedTransaction.retries = '3';
data = { [key]: savedTransaction };
await retryTransaction(
contract,
redis.redis,
transactionId,
savedTransaction
);
expect(data[key]).toMatchObject({
timestamp: timestamp.toString(),
state: state,
retries: '4',
args: args,
});
});
it('Clear transaction once retry reaches max retry count ', async () => {
savedTransaction.retries = '5';
data = { [key]: savedTransaction };
await retryTransaction(
contract,
redis.redis,
transactionId,
savedTransaction
);
expect(data[key]).toBe(undefined);
});
});
});

View file

@ -21,6 +21,12 @@ export const retryDelay = env
.example('3000')
.asIntPositive();
export const maxRetryCount = env
.get('MAX_RETRY_COUNT')
.default('5')
.example('5')
.asIntPositive();
export const asLocalHost = env
.get('AS_LOCAL_HOST')
.default('true')

View file

@ -18,7 +18,11 @@ import { Request } from 'express';
import { Redis } from 'ioredis';
import * as config from './config';
import { logger } from './logger';
import { storeTransactionDetails, clearTransactionDetails } from './redis';
import {
storeTransactionDetails,
clearTransactionDetails,
incrementRetryCount,
} from './redis';
import {
AssetExistsError,
AssetNotFoundError,
@ -251,12 +255,12 @@ const handleError = (transactionId: string, err: Error): Error => {
return new TransactionError('Transaction error', transactionId);
};
const retryTransaction = async (
export const retryTransaction = async (
contract: Contract,
redis: Redis,
transactionId: string,
savedTransaction: Record<string, string>
) => {
): Promise<void> => {
logger.debug('Retrying transaction %s', transactionId);
try {
@ -279,7 +283,11 @@ const retryTransaction = async (
savedTransaction.retries,
transactionId
);
await (redis as Redis).hincrby(`txn:${transactionId}`, 'retries', 1);
if (parseInt(savedTransaction.retries) < config.maxRetryCount) {
await incrementRetryCount(redis, transactionId);
} else {
await clearTransactionDetails(redis, transactionId);
}
}
}
};

View file

@ -70,3 +70,20 @@ export const clearTransactionDetails = async (
};
// TODO add getTransaction etc. helpers?
export const incrementRetryCount = async (
redis: Redis,
transactionId: string
): Promise<void> => {
const key = `txn:${transactionId}`;
logger.debug('Incrementing retries fortransaction Key: %s', key);
try {
await (redis as Redis).hincrby(`txn:${transactionId}`, 'retries', 1);
} catch (err) {
logger.error(
err,
'Error incrementing retries for transaction ID %s',
transactionId
);
}
};