PostgreSQL: Read returning more quickly than write - postgresql

I have two queries written with SequelizeJS
Read:
Object.getObject = async function(){
return await this.findOne();
}
Write:
Object.updateObject = async function(info){
const t = await sequelize.transaction();
const currentObject = await Object.findOne();
const updatedObject = currentObject.updateAttributes(info, t);
t.commit();
return updatedObject;
}
These queries are fired when you go to a URL in an API.
I trigger the write query first, and then in a promise that handles the successful write request, I get the updated object.
API.updateObject().then((res) => {
API.getObject();
})
Despite the GET HTTP request and read query firing after the UPDATE HTTP request returns and is handled as a promise. The read query completes first and returns an object model in a state prior to be being modified by the mentioned write query.
As in, the write query, despite being fired off first and indicating it was complete. Fires off the read query which completes and retrieves an older object modal before the write is complete.
Is there something I don't know with about PostgreSQL and how it handles the sequences of queries when reading and writing to the same object?

Related

Flutter/Dart: return not waiting "toList" with async function to finish

I'm working on an API sync using Flutter and SQFLite.
I get the data from the API, map it, and then add to SQL item by item:
return (response as List).map((tmp) {
print('• API: apiSync - Inserting News');
DBProvider.db.updateNews(ArtNews.fromJson(tmp));
}).toList();
Everything works fine, but there is a small problem: the return is called before the 'updateNews' is done.
updateNews is a simple async function that writes data on SQFLite.
This creates a big issue: the app opens before the sync is over and data is still being written on DB.
I've tried using AWAIT, but it doesn't make any effect:
(response as List).map((tmp) async{
print('• API: apiSync - Inserting $type');
await DBProvider.db.updateNews(ArtNews.fromJson(tmp));
}).toList();
return 'done';
updateNews is called dozens of times, the toList ends, returns 'done', but the updateNews is still adding content to the DB.
I guess there is something I'm missing on toList or async. Any ideas? Thanks!
Try this:
await Future.wait((response as List).map((tmp) {
print('• API: apiSync - Inserting $type');
return DBProvider.db.updateNews(ArtNews.fromJson(tmp));
}));
return 'done';
Gist for reference:
https://dartpad.dev/?id=e72b1dc9013e2add447a90979bed7aab

tronweb : how to get return value using tronweb contract send function

let contract = await window.tronWeb.contract().at(config.contract);
let result = await contract.methods.depositTron()
.send({callValue:amount*1000000})
.then(output=>transaction = output);
console.log("result", result);
I tried to get the result of depositTron method, but returned hash value.
how should I do?
please help me.
Functions invoked by transactions only return value within the EVM (usually when called from another contract).
The hash returned from the send() JS function, is the transaction hash.
You can workaround this by emitting an event log within the contract. Then you can get the value or read emitted logs from the transaction receipt (emitted in JS after the transaction is mined).
Solidity:
contract MyContract {
event Deposit(uint256 indexed amount);
function depositTron() external payable {
emit Deposit(msg.value);
}
}
JS:
contract.methods.depositTron().send({callValue:amount*1000000})
.on('receipt', (receipt) => {
console.log(receipt.logs);
})

Workbox - NetworkOnly executes even if I return false

Using Workbox, I am trying to deal with graphql.
Anyone know why I am getting this error message from NetworkOnly? I am returning false in the route matcher, so I don't know why new NetworkOnly() is even executing. This only happens in offline mode (no network available).
The strategy could not generate a response for ... The underlying error is TypeError: Failed to fetch.
at NetworkOnly._handle (webpack://service-workers/./node_modules/workbox-strategies/NetworkOnly.js?:101:19)
at async NetworkOnly._getResponse (webpack://service-workers/./node_modules/workbox-strategies/Strategy.js?:155:24)
const bgSyncPlugin = new BackgroundSyncPlugin('myQueueName', {
maxRetentionTime: 24 * 60
});
const isGraphqlSubmitForm = async(event) => {
const clonedRequest = event.request.clone();
const body = await clonedRequest.json();
if (body?.operationName === 'submitForm') {
return true;
}
return false; // I MADE SURE THIS IS BEING RETURNED
};
registerRoute(
isGraphqlSubmitForm,
new NetworkOnly({
plugins: [bgSyncPlugin]
}),
'POST'
);
Sorry about that—you're seeing that behavior because the truthiness of the return value from this function is used to determine whether a route matches, and an async function always returns a Promise, which is a "truthy" value.
There's a log message that warns about this if you're in Workbox's development mode.
If it's possible for you to add in a header on the requests you want to match, that would probably be the easiest way to synchronously trigger your route, since any attempt to access a request body needs to be async. Failing that, the cleanest approach would be to just match all of your GraphQL requests with a given route, and then inside of that route's handler, use whatever async logic you need to trigger different strategies for different types of traffic.

Cloud function http function fails on first run

I am testing with a payment processing system and every time a transaction is completed, the payment processor should hit my endpoint with a POST request with payment details so I can save it to my database (Firestore).
Only thing is the function fails on the first try. What I mean is, say a customer pays, the payment processor hits my cloud function, it fails to save to my database. When a second customer makes the transaction a minute, 5 minutes or even 18 minutes later according to my observation, everything works as expected.
Am I facing a cold start problem or what is happening. And how do I solve this.
Here is my function
exports.stkCallback = functions.https.onRequest(async (request, response) => {
if (request.method === 'POST') {
if (request.body.Body.stkCallback.ResultCode === 0) {
const jsonData = request.body.Body.CallbackMetadata;
console.log("USER HAS COMPLETED THE TRANSACTION");
var transactionID;
///This below line logs successfully everytime meaning my payment processor has sent the POST
/// request
console.log("checkoutid:", request.body.Body.CheckoutRequestID)
///I have saved the CheckoutRequestID previously to Firestore so I first query the document
//// with that ID (CheckoutRequestID) and get its data so I can update the transaction as
//// complete
var docRef=db.collection("Transactions").doc(request.body.Body.CheckoutRequestID);
await docRef.get().then((doc) =>{
// eslint-disable-next-line promise/always-return
if (doc.exists) {
//console.log("Document data:", doc.data());
transactionID=doc.id;
transactionData.push(doc.data());
} else {
// doc.data() will be undefined in this case
console.log("No such document!");
}
}).catch((error)=> {
console.log("Error getting document:", error);
});
///Once I get the data I can then go ahead and do other operations.
///Only the above query fails the first time which I don't know why
///By failing Saying No such Document. Which the document does exist
***carrying out other operations using the fetched transactionID and transactionData***
response.sendStatus(200);
} else {
console.log("USER HAS CANCELLED THE TRANSACTION");
response.sendStatus(200);
}
I have refactored my code and reproduced it to the below
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp();
const db = admin.firestore();
exports.stkCallback = functions.https.onRequest(async (request, response) => {
const accountSid = "#";
const authToken = "#";
const client = require("twilio")(accountSid, authToken);
if (request.method === 'POST') {
if (request.body.Body.ResultCode === 0) {
const jsonData = request.body.Body.CallbackMetadata;
console.log("USER HAS COMPLETED THE TRANSACTION");
var transactionID;
///This below line logs successfully everytime meaning my
/////payment processor has sent the POST request
console.log("checkoutid:",
request.body.Body.CheckoutRequestID)
////The below function is critical to all the other below functions below it as
///it supplies the necessary data all the way down
///It is also the function that fails on the first run
var docRef= await db.collection("Transactions").doc(request.body.Body.CheckoutRequestID).get()
.catch((error)=> {
console.log("Error getting document:", error);
});
//// a log of some data from the above function
//// when it fails, the below log is undefined,
console.log("tyyy",docRef.data().Home)
transactionID=docRef.id;
////the data returned from above function is used to perform other operations.
////Below is just one of them
////consequently, it will fail as some values like doc.data().Uid will be ////undefined
await db.collection("Users").doc(doc.data().Uid).collection("Transactions").doc(transactionID).update({
TransactionComplete: true,
transactionCompletedTimeDb: admin.firestore.FieldValue.serverTimestamp(),
Amount: jsonData.Item[0].Value,
ReceiptNO: jsonData.Item[1].Value,
TransactionDate: jsonData.Item[3].Value,
PhoneNumber: jsonData.Item[4].Value,
UserId: doc.data().Uid
})
// eslint-disable-next-line promise/always-return
.catch((error)=> {
// The document probably doesn't exist.
console.error("Error updating document: ", error);
});
response.sendStatus(200);
} else {
console.log("USER HAS CANCELLED THE TRANSACTION");
response.sendStatus(200);
}
});
Attaching an image of a failed function, do note the time
An image of logs of the same triggered function right after (3 minutes later). As you can see the function completes successfully
This seems like a Cold Start Issue
The mitigation of this issue will depend on many information that you are not sharing with us like the complete function, dependencies that you are using, and instance size.
Spreading a loaded function into multiple small functions will help with the cold start time, also using smaller, updated, and cloud oriented libraries will also help.
Also, the size of the payload could be an important factor here, how big is the size of the payload sent to the function and how big is the size of the info that you are writing into the logs? All these small pieces have an important influence on the performance of a cold start.
As a quick solution for your Issue, I can safely say that creating a Scheduled task that triggers your functions every 30 minutes, for example, would be enough to mitigate your issue in the short term.

How do I know if a transaction on Firestore succeded?

Is there any method to know if the transaction was successful? I need to implement a loading "widget animation" if I upload large archives and spend too much time on that. And then change the screen after success, but I don't know-how.
Thanks!
Transaction Example:
CollectionReference reference = Firestore.instance.collection("collection_example");
Firestore.instance.runTransaction((Transaction transaction) async {
await transaction.set(reference, {
"index_1":"ABC",
"index_2": 2,
"index_3": {"mapIndex_1": "ABC"}
});
});
You cannot receive that from your runTransaction call in this case because it returns a Future<Map<String, dynamic>>. As I have checked, it will always return an empty Map. Thus there is nothing to get from the runTransaction function itself.
You can easily get a Stream of updates from your reference though, which would look something like this:
DocumentReference documentReference;
firestore.runTransaction( // firestore in this case is your Firestore instance
(Transaction transaction) async {
// whatever you do here with your reference
await transaction.update(
documentReference,
...
);
documentReference.snapshots().listen((DocumentSnapshot event) {
// here you could e.g. check if the transaction on your reference was succesful
});
As you can see I used the snapshots() Stream<DocumentSnapshot) on the same DocumentReference as the transaction was run on. The Stream will update as soon as the transaction has completed and the server reached back to you.
To see why transaction results cannot be evaluated client-side check the answers on my question here.