'Transaction cannot be rolled back...' using unmanaged transactions - amazon-web-services

We use unmanaged transactions in many cases but this issue only occurs in 2 functions which are invoked more commonly and only on production environment (Haven't been able to reproduce it on dev).
Our code looks similar to this:
const t = await database.t();
try {
await function1(..., {t});
await function2(..., {t});
}
catch (e) {
await t.rollback(); <- This throws the error
throw e
};
// more logic
await t.commit();
Where database is just a Sequelize instantiation with name of database, username and password.
We assumed it's a connection error according to this: https://github.com/sequelize/sequelize/issues/4850 but in this case code wouldn't reach beyond line one on our pseudocode.
Error output on CloudWatch:

If you have multiple try-catch then maybe need to check the transaction state before rollback/commit:
const t = await database.t();
try {
await function1(..., { t });
await function2(..., { t });
}
catch (e) {
if (!t.finished) {
await t.rollback();
}
throw e;
};
// more logic
await t.commit();
Reference links:
https://github.com/sequelize/sequelize/issues/6547#issuecomment-466016971
https://github.com/sequelize/sequelize/pull/5043/files#diff-6c5ddfc7d68c447e32ef4c38b7ed69628910355ea0aff735bd4bcecc1256a8d8

Related

jest.spyOn mock return value not returning value

The code I'm trying to test:
const utils = require('../utils/utils');
let imageBuffer;
try {
imageBuffer = await utils.retrieveImageFromURI(params)
console.log(imageBuffer) // comes back as undefined when I mock the utils.retreieveImageFromURI
if (!imageBuffer || imageBuffer.length < 1024) {
throw new Error(`Retrieve from uri (${params.camera.ingest.uri}) was less than 1kb in size - indicating an error`)
}
console.log(`${params.camera.camId} - Successful Ingestion from URI`);
} catch (err) {
reject({ 'Task': `Attempting to pull image from camera (${params.camera.camId}) at ${params.camera.ingest.uri}`, 'Error': err.message, 'Stack': err.stack })
return;
}
Specifically, I'm trying to mock the utils.retrieveImageFromURI function - which has API calls and other things in it.
When I try to mock the function using spyOn I am trying it like so:
describe("FUNCTION: ingestAndSave", () => {
let fakeImageBuffer = Array(1200).fill('a').join('b'); // just get a long string
console.log(fakeImageBuffer.length) //2399
let retrieveImageFromURISpy
beforeAll(() => {
retrieveImageFromURISpy = jest.spyOn(utils, 'retrieveImageFromURI').mockReturnValue(fakeImageBuffer)
})
test("Will call retrieveImageFromURI", async () => {
await ingest.ingestAndSave({camera:TEST_CONSTANTS.validCameraObject, sourceQueueURL:"httpexamplecom", receiptHandle: "1234abcd"})
expect(retrieveImageFromURISpy).toHaveBeenCalledTimes(1)
})
afterEach(() => {
jest.resetAllMocks()
})
afterAll(() => {
jest.restoreAllMocks()
})
})
When I do this, I get a console log that imageBuffer (which is supposed to be the return of the mocked function) is undefined and that, in turn, triggers the thrown Error that "Retrieve from uri ...." ... which causes my test to fail. I know I could wrap the test call in a try/catch but the very next test will be a "does not throw error" test... so this needs to be solved.
It's not clear to me why the mockReturnValue isn't getting returned.
Other steps:
I've gone to the REAL retrieveImageFromURI function and added a console log - it is not running.
I've changed mockReturnValue to mockImplementation like so:
retrieveImageFromURISpy = jest.spyOn(utils, 'retrieveImageFromURI').mockImplementation(() => {
console.log("Here")
return fakeImageBuffer
})
And it does NOT console log 'here'. I'm unsure why not.
I have also tried to return it as a resolved Promise, like so:
retrieveImageFromURISpy = jest.spyOn(utils, 'retrieveImageFromURI').mockImplementation(() => {
console.log("Here")
return Promise.resolve(fakeImageBuffer)
})
Note, this also doesn't console log.
I've also tried to return the promise directly with a mockReturnValue:
`retrieveImageFromURISpy = jest.spyOn(utils, 'retrieveImageFromURI').mockReturnValue(Promise.resolve(fakeImageBuffer)`)

How to resolve the type error issue in nestjs unit test?

I'm trying to create a jest test for the below method. And I got errors for two scenarios.
So basically in checkKioskUserPhone method,
Find the user by the phone number( commonService.findKioskUserByPhone)
In findKioskUserByPhone method, we are gonna find the user by the phone number and send error messages if it's unregistered or already registered.
And then return user.
(back to checkKioskUserPhone) if the user doesn't have auth code and pin number we are gonna send him/her auth code and return jwt, and etc.
async checkKioskUserPhone(kioskLoginDto: KioskLoginDto): Promise<ResponseDto<UserAuthDto>> {
const user = await this.commonService.findKioskUserByPhone(kioskLoginDto);
const isConfirmedAuthCode = user.authCode === 'OK' ? true : false;
const isSetPin = user.pin ? true : false;
if (!isConfirmedAuthCode && !isSetPin) {
await this.userService.authenticatePhone(user.id, Builder(AuthorizePhoneDto).phone(user.phone).build());
}
const jwtInfo = await this.createToken(this.removeCredentialField(user));
return Builder<ResponseDto<UserAuthDto>>(ResponseDto)
.result(Builder(UserAuthDto).isConfirmedAuthCode(isConfirmedAuthCode).isSetPin(isSetPin).jwtInfo(jwtInfo).build())
.build();
}
async findKioskUserByPhone(kioskLoginDto: KioskLoginDto): Promise<User> {
const user = await this.userService.findOne({ where: { phone: kioskLoginDto.phone } });
// throw Error message when unregistered phone attempt to login
if (!user) {
throw new NotFoundException('User not found');
}
// throw Error message when registered phone by whatsapp attempt to login
if (user.provider !== Provider.KIOSK) {
throw new ConflictException('You are already joined by Whatsapp.');
}
return user;
}
Jest code
it('when unregistered phone attempt to login', async () => {
const phone = '2212223333';
const kioskLoginDto = Builder(KioskLoginDto).phone(phone).build();
service.commonService.findKioskUserByPhone = jest.fn().mockResolvedValue(null);
try {
await service.checkKioskUserPhone(kioskLoginDto);
expect('here').not.toBe('here');
} catch (error) {
expect(error).toBeInstanceOf(NotFoundException);
expect(error.message).toContain('User not found');
}
});
it('When registered phone by app attempt to login', async () => {
const phone = '2212223333';
const kioskLoginDto = Builder(KioskLoginDto).phone(phone).build();
const user = Builder(User).phone(phone).provider(Provider.WHATSAPP).build();
service.commonService.findKioskUserByPhone = jest.fn().mockResolvedValue(user);
try {
await service.checkKioskUserPhone(kioskLoginDto);
expect('here').not.toBe('here');
} catch (error) {
expect(error).toBeInstanceOf(ConflictException);
expect(error.message).toContain('You are already joined by Whatsapp.');
}
});
Jest Error screenshot
you're overriding the findKioskUserByPhone method to just return null:
service.commonService.findKioskUserByPhone = jest.fn().mockResolvedValue(null);
so findKioskUserByPhone simply is never running, a mock function is just returning null, and is thus never throwing the error you expect. instead, here:
const user = await this.commonService.findKioskUserByPhone(kioskLoginDto);
user is getting set to null and here:
const isConfirmedAuthCode = user.authCode === 'OK' ? true : false;
you're trying access some authCode property of null, which throws the TypeError you're getting.
you probably meant to override the findOne method on the user service:
service.userService.findOne = jest.fn().mockResolvedValue(null);
so the error you want will actually throw in findKioskUserByPhone
(note I don't know if this is actually where you have the user service to provide the mock, I'm just assuming)

how likely is it to miss a solidity event?

Hi i am making a finance application that depends on Events from blockchain,
Basically i update my database based on Events i receive using web3js, and when user asks i sign with private key for the contract to be able to give user Money.
My only concern is can i depend on events? like can there be a case where i miss events?
here is my code for doing so :
const contract = new web3.eth.Contract(abi, contract_address)
const stale_keccak256 = "0x507ac39eb33610191cd8fd54286e91c5cc464c262861643be3978f5a9f18ab02";
const unStake_keccak256 = "0x4ac743692c9ced0a3f0052fb9917c0856b6b12671016afe41b649643a89b1ad5";
const getReward_keccak256 = "0x25c30c62c42b51e4f667b70ef60f1f683c376f6ace28312ed45a40665e01af37";
let userRepository: Repository<UserData> = connection.getRepository(UserData);
let globalRepository: Repository<GlobalStakingInfo> = connection.getRepository(GlobalStakingInfo);
let userStakingRepository: Repository<UserStakingInfo> = connection.getRepository(UserStakingInfo);
let transactionRepository: Repository<Transaction> = connection.getRepository(Transaction);
const topics = []
web3.eth.subscribe('logs', {
address: contract_address, topics: topics
},
function (error: Error, result: Log) {
if (error) console.log(error)
}).on("data", async function (log: Log) {
let response: Boolean = false;
try {
response = await SaveTransaction(rpc_url, log.address, log.transactionHash, transactionRepository)
} catch (e) {
}
if (response) {
try {
let global_instance: GlobalStakingInfo | null = await globalRepository.findOne({where: {id: 1}})
if (!global_instance) {
global_instance = new GlobalStakingInfo()
global_instance.id = 1;
global_instance = await globalRepository.save(global_instance);
}
if (log.topics[0] === stale_keccak256) {
await onStake(web3, log, contract, userRepository, globalRepository, userStakingRepository, global_instance);
} else if (log.topics[0] === unStake_keccak256) {
await onUnStake(web3, log, contract, userStakingRepository, userRepository, globalRepository, global_instance)
} else if (log.topics[0] === getReward_keccak256) {
await onGetReward(web3, log, userRepository)
}
} catch (e) {
console.log("I MADE A BOBO", e)
}
}
}
)
The Code works and everything, i am just concerned if i could maybe miss a event? cause finance is related and people will lose money if missing event is a thing.
Please advise
You can increase redundancy by adding more instances of the listener connected to other nodes.
And also by polling past logs - again recommended to use a separate node.
Having multiple instances doing practically the same thing will result in multiplication of incoming data, so don't forget to store only unique logs. This might be a bit tricky, because theoretically one transaction ID can produce the same log twice (e.g. through a multicall), so the unique key could be a combination of a transaction ID as well as the log index (unique per block).

How to return error response in apollo link?

I'm using apollo link in schema stitching as an access control layer. I'm not quite sure how to make the link return error response if a user does not have permissions to access a particular operation. I know about such packages as graphql-shield and graphql-middleware but I'm curious whether it's possible to achieve basic access control using apollo link.
Here's what my link looks like:
const link = setContext((request, previousContext) => merge({
headers: {
...headers,
context: `${JSON.stringify(previousContext.graphqlContext ? _.omit(previousContext.graphqlContext, ['logger', 'models']) : {})}`,
},
})).concat(middlewareLink).concat(new HttpLink({ uri, fetch }));
The middlewareLink has checkPermissions that returns true of false depending on user's role
const middlewareLink = new ApolloLink((operation, forward) => {
const { operationName } = operation;
if (operationName !== 'IntrospectionQuery') {
const { variables } = operation;
const context = operation.getContext().graphqlContext;
const hasAccess = checkPermissions({ operationName, context, variables });
if (!hasAccess) {
// ...
}
}
return forward(operation);
});
What should I do if hasAccess is false. I guess I don't need to forward the operation as at this point it's clear that a user does not have access to it
UPDATE
I guess what I need to do is to extend the ApolloLink class, but so far I didn't manage to return error
Don't know if anyone else needs this, but I was trying to get a NetworkError specifically in the onError callback using Typescript and React. Finally got this working:
const testLink = new ApolloLink((operation, forward) => {
let fetchResult: FetchResult = {
errors: [] // put GraphQL errors here
}
let linkResult = Observable.of(fetchResult).map(_ => {
throw new Error('This is a network error in ApolloClient'); // throw Network errors here
});
return linkResult;
});
Return GraphQL errors in the observable FetchResult response, while throwing an error in the observable callback will produce a NetworkError
After some digging I've actually figured it out. But I'm not quite sure if my approach is correct.
Basically, I've called forward with a subsequent map where I return an object containing errors and data fields. Again, I guess there's a better way of doing this (maybe by extending the ApolloLink class)
const middlewareLink = new ApolloLink((operation, forward) => {
const { operationName } = operation;
if (operationName !== 'IntrospectionQuery') {
const { variables } = operation;
const context = operation.getContext().graphqlContext;
try {
checkPermissions({ operationName, context, variables });
} catch (err) {
return forward(operation).map(() => {
const error = new ForbiddenError('Access denied');
return { errors: [error], data: null };
});
}
}
return forward(operation);
});

How to use Promise's reject?

As the documentation says
resolve is
The Promise.resolve(value) method returns a Promise object that is
resolved with the given value.
reject is
The Promise.reject(reason) method returns a Promise object that is
rejected with the given reason.
I understand the uses of resolve but what will be the uses of reject and when to use it ?
Promise.reject is promise's way of throwing errors. Usually you would have a condition inside of your promise:
const user = {
name: 'John',
age: 17
}
const p = new Promise((resolve, reject) => {
if (user.age > 18) {
resolve('Welcome!');
} else {
reject(new Error('Too young!'));
}
});
You can then chain then and catch methods to handle the results of resolve and reject respectively.
p.then(message => {
console.log(message); // 'Welcome!', if promise resolves, won't work with age of 17
})
.catch(err => {
console.error(err); // 'Too young!', because promise was rejected
});
Here are few examples this statement can be used for:
Function defined to return a Promise, however you perform some sync checks and would like to return an error:
function request(data) {
if (!data) return Promise.reject("Empty data!");
// other logic
}
Unit tests, for example you would like to test that default data is used if service returns error (rejected promise):
const mockService = mock(Service);
// mock request method to return rejected promise
when(mockService.performRequest()).thenReturn(Promise.reject("Failed!"));
// inject mock instance and check that default data used if service failed
const sut = new ClassUnderTest(mockService);
expect(sut.getData()).to.eq("Default data");