mirror of
https://github.com/hyperledger/fabric-samples.git
synced 2026-06-22 17:45:10 +00:00
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:
parent
73049e0153
commit
b8509490ad
7 changed files with 148 additions and 5 deletions
|
|
@ -21,6 +21,8 @@ PORT=3000
|
||||||
|
|
||||||
RETRY_DELAY=3000
|
RETRY_DELAY=3000
|
||||||
|
|
||||||
|
MAX_RETRY_COUNT=5
|
||||||
|
|
||||||
HLF_CONNECTION_PROFILE_ORG1=$(cat ${CONNECTION_PROFILE_FILE_ORG1} | jq -c .)
|
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')"
|
HLF_CERTIFICATE_ORG1="$(cat ${CERTIFICATE_FILE_ORG1} | sed -e 's/$/\\n/' | tr -d '\r\n')"
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ export const logLevel = 'info';
|
||||||
export const port = '3000';
|
export const port = '3000';
|
||||||
|
|
||||||
export const retryDelay = '3000';
|
export const retryDelay = '3000';
|
||||||
|
export const maxRetryCount = 5;
|
||||||
|
|
||||||
export const asLocalHost = true;
|
export const asLocalHost = true;
|
||||||
|
|
||||||
|
|
@ -46,7 +47,7 @@ export const redisHost = 'localhost';
|
||||||
|
|
||||||
export const redisPort = '6379';
|
export const redisPort = '6379';
|
||||||
|
|
||||||
export const redisUsername = 'conga';
|
export const redisUsername = '';
|
||||||
|
|
||||||
export const redisPassword = '';
|
export const redisPassword = '';
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -32,10 +32,22 @@ mocked(Gateway.prototype.getNetwork).mockResolvedValue({
|
||||||
addBlockListener: jest.fn(),
|
addBlockListener: jest.fn(),
|
||||||
removeBlockListener: 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 {
|
export {
|
||||||
DefaultEventHandlerStrategies,
|
DefaultEventHandlerStrategies,
|
||||||
DefaultQueryHandlerStrategies,
|
DefaultQueryHandlerStrategies,
|
||||||
Gateway,
|
Gateway,
|
||||||
Wallets,
|
Wallets,
|
||||||
|
getMockedNetwork,
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
@ -21,6 +21,12 @@ export const retryDelay = env
|
||||||
.example('3000')
|
.example('3000')
|
||||||
.asIntPositive();
|
.asIntPositive();
|
||||||
|
|
||||||
|
export const maxRetryCount = env
|
||||||
|
.get('MAX_RETRY_COUNT')
|
||||||
|
.default('5')
|
||||||
|
.example('5')
|
||||||
|
.asIntPositive();
|
||||||
|
|
||||||
export const asLocalHost = env
|
export const asLocalHost = env
|
||||||
.get('AS_LOCAL_HOST')
|
.get('AS_LOCAL_HOST')
|
||||||
.default('true')
|
.default('true')
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,11 @@ import { Request } from 'express';
|
||||||
import { Redis } from 'ioredis';
|
import { Redis } from 'ioredis';
|
||||||
import * as config from './config';
|
import * as config from './config';
|
||||||
import { logger } from './logger';
|
import { logger } from './logger';
|
||||||
import { storeTransactionDetails, clearTransactionDetails } from './redis';
|
import {
|
||||||
|
storeTransactionDetails,
|
||||||
|
clearTransactionDetails,
|
||||||
|
incrementRetryCount,
|
||||||
|
} from './redis';
|
||||||
import {
|
import {
|
||||||
AssetExistsError,
|
AssetExistsError,
|
||||||
AssetNotFoundError,
|
AssetNotFoundError,
|
||||||
|
|
@ -251,12 +255,12 @@ const handleError = (transactionId: string, err: Error): Error => {
|
||||||
return new TransactionError('Transaction error', transactionId);
|
return new TransactionError('Transaction error', transactionId);
|
||||||
};
|
};
|
||||||
|
|
||||||
const retryTransaction = async (
|
export const retryTransaction = async (
|
||||||
contract: Contract,
|
contract: Contract,
|
||||||
redis: Redis,
|
redis: Redis,
|
||||||
transactionId: string,
|
transactionId: string,
|
||||||
savedTransaction: Record<string, string>
|
savedTransaction: Record<string, string>
|
||||||
) => {
|
): Promise<void> => {
|
||||||
logger.debug('Retrying transaction %s', transactionId);
|
logger.debug('Retrying transaction %s', transactionId);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
@ -279,7 +283,11 @@ const retryTransaction = async (
|
||||||
savedTransaction.retries,
|
savedTransaction.retries,
|
||||||
transactionId
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -70,3 +70,20 @@ export const clearTransactionDetails = async (
|
||||||
};
|
};
|
||||||
|
|
||||||
// TODO add getTransaction etc. helpers?
|
// 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
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue