how to await date in js? - javascript

I am adding some epoch time to my date variable and then converting it to iso to put it inside db. but my code is not geting correct time.
my code is not stoping to execute => var releaseDate = new Date(epochDate).toISOString();
how should I make it happen
my code output is
epoch and now =
Mon Dec 21 2020 02:16:56 GMT+0530 (IST)604800000
1618003233700
2020-12-20T20:46:56.000Z
date should be today + 7 days but it didn't change.
async function schedule(data, epochDate) {
const endpoint = config.main+"/schedule"
const opt = {
headers: {
"id": 0
}
}
//add 7 days in epoch time milliseconds
epochDate += 604800000;
const now = Date.now();
console.log("epoch and now =")
console.log(epochDate)
console.log(now)
if(epochDate <= now){
epochDate = now + 604800000;
}
var releaseDate = new Date(epochDate).toISOString();
console.log(releaseDate);
const payload = {
Id: data,
date: new Date(epochDate).toISOString()
}
return await axios.post(endpoint, payload, opt)
.then((result)=> result.data)
.catch((error) => {
console.log('error in axios post catch %j', error.response.data)
throw error
})
}

You have declared function schedule() as async meaning that it must return a promise that will be fulfilled. At the end of your function, you are returning the promise made by axios but you are also attaching then and catch functions to that promise which is likely producing very confusing results. If I was doing it, I would declare schedule() as you have but make its implementation specifically a promise. Within that promise, you would invoke axios() and, in its then and/or catch, you would call either the accept handler or the reject handler.

Related

Sleep / delay inside promise.all

I am building a backend to handle pulling data from a third party API.
There are three large steps to this, which are:
Delete the existing db data (before any new data is inserted)
Get a new dataset from the API
Insert that data.
Each of these three steps must happen for a variety of datasets - i.e. clients, appointments, products etc.
To handle this, I have three Promise.all functions, and each of these are being passed individual async functions for handling the deleting, getting, and finally inserting of the data. I have this code working just for clients so far.
What I'm now trying to do is limit the API calls, as the API I am pulling data from can only accept up to 200 calls per minute. To quickly test the rate limiting functionality in code I have set it to a max of 5 api calls per 10 seconds, so I can see if it's working properly.
This is the code I have so far - note I have replaced the name of the system in the code with 'System'. I have not included all code as there's a lot of data that is being iterated through further down.
let patientsCombinedData = [];
let overallAPICallCount = 0;
let maxAPICallsPerMinute = 5;
let startTime, endTime, timeDiff, secondsElapsed;
const queryString = `UPDATE System SET ${migration_status_column} = 'In Progress' WHERE uid = '${uid}'`;
migrationDB.query(queryString, (err, res) => {
async function deleteSystemData() {
async function deleteSystemPatients() {
return (result = await migrationDB.query("DELETE FROM System_patients WHERE id_System_account = ($1) AND migration_type = ($2)", [
System_account_id,
migrationType,
]));
}
await Promise.all([deleteSystemPatients()]).then(() => {
startTime = new Date(); // Initialise timer before kicking off API calls
async function sleep(ms) {
return new Promise((resolve) => setTimeout(resolve, ms));
}
async function getSystemAPIData() {
async function getSystemPatients() {
endTime = new Date();
timeDiff = endTime - startTime;
timeDiff /= 1000;
secondsElapsed = Math.round(timeDiff);
if (secondsElapsed < 10) {
if (overallAPICallCount > maxAPICallsPerMinute) {
// Here I want to sleep for one second, then check again as the timer may have passed 10 seconds
getSystemPatients();
} else {
// Proceed with calls
dataInstance = await axios.get(`${patientsPage}`, {
headers: {
Authorization: completeBase64String,
Accept: "application/json",
"User-Agent": "TEST_API (email#email.com)",
},
});
dataInstance.data.patients.forEach((data) => {
patientsCombinedData.push(data);
});
overallAPICallCount++;
console.log(`Count is: ${overallAPICallCount}. Seconds are: ${secondsElapsed}. URL is: ${dataInstance.data.links.self}`);
if (dataInstance.data.links.next) {
patientsPage = dataInstance.data.links.next;
await getSystemPatients();
} else {
console.log("Finished Getting Clients.");
return;
}
}
} else {
console.log(`Timer reset! Now proceed with API calls`);
startTime = new Date();
overallAPICallCount = 0;
getSystemPatients();
}
}
await Promise.all([getSystemPatients()]).then((response) => {
async function insertSystemData() {
async function insertClinkoPatients() {
const SystemPatients = patientsCombinedData;
Just under where it says ' if (secondsElapsed < 10) ' is where I want to check the code every second to see if the timer has passed 10 seconds, in which case the timer and the count will be reset, so I can then start counting again over the next 10 seconds. Currently the recursive function is running so often that an error displayed related to the call stack.
I have tried to add a variety of async timer functions here but every time the function is returned it causes the parent promise to finish executing.
Hope that makes sense
I ended up using the Bottleneck library, which made it very easy to implement rate limiting.
const Bottleneck = require("bottleneck/es5");
const limiter = new Bottleneck({
minTime: 350
});
await limiter.schedule(() => getSystemPatients());

web3.eth.contracts.method await function never returns

I'm working on a project to interact with a smart contract in ethereum. Everything was working fine, the transactions was working properly and so on... but I realized that when I tried to run some code after an specifically await function, that code never ran and I really don't know why. Others contract methods that I invoked is working well and the code is executed normally.
The code:
onSubmit = async (event) => {
event.preventDefault()
console.log("Submitting the form...")
var day = new Date(Date.now()).getDate()
var month = new Date(Date.now()).getMonth() + 1
var year = new Date(Date.now()).getFullYear()
var today = new Date(year, month -1, 1)
var todayTime = today.getTime()
const ipfsadded = await ipfs.add({path:this.state.fileName, content:this.state.buffer})
var ipfsHash = ipfsadded.cid.toString()
this.setState({ipfsHash: ipfsHash})
console.log('hash:', ipfsHash, " / name =", this.state.fileName )
console.log("inserindo na blockchain..")
const accounts = await web3.eth.getAccounts()
//ERROR HERE!!
//THIS FUNCTION IS EXECUTED, THE TRANSACTION IS CONFIRMED IN METAMASK BUT AFTER THAT NOTHING HAPPENS
var result = await contract.methods.add(ipfsHash, this.state.fileName, this.state.fileType, todayTime).send({from:accounts[0], gas:300000});
console.log("resultado =", result) //IS NEVER EXECUTED EVEN WITH TRANSACTION OK
console.log("File submitted on blockchain!") //IS NEVER EXECUTED
}
It's likely that is because the transaction wasn't mined within 750 seconds and .send threw an error, but wasn't caught. You can prove this by by wrapping it with a try/catch block and inspect the error.
try {
var result = await contract.methods.add(ipfsHash, this.state.fileName, this.state.fileType, todayTime).send({from:accounts[0], gas:300000});
} catch(err) {
console.error(err);
}
A better way is to subscribe to either receipt, transactionHash or confirmation event, which is exposed by send.
contract.methods.add(ipfsHash, this.state.fileName, this.state.fileType, todayTime)
.send({from:accounts[0], gas:300000})
.on('transactionHash', resolve)
.on('error', reject);
In your case it would be
onSubmit = async (event) => {
event.preventDefault()
console.log("Submitting the form...")
var day = new Date(Date.now()).getDate()
var month = new Date(Date.now()).getMonth() + 1
var year = new Date(Date.now()).getFullYear()
var today = new Date(year, month -1, 1)
var todayTime = today.getTime()
const ipfsadded = await ipfs.add({path:this.state.fileName, content:this.state.buffer})
var ipfsHash = ipfsadded.cid.toString()
this.setState({ipfsHash: ipfsHash})
console.log('hash:', ipfsHash, " / name =", this.state.fileName )
console.log("inserindo na blockchain..")
const accounts = await web3.eth.getAccounts()
//ERROR HERE!!
//THIS FUNCTION IS EXECUTED, THE TRANSACTION IS CONFIRMED IN METAMASK BUT AFTER THAT NOTHING HAPPENS
const promise = new Promise()
contract.methods.add(ipfsHash, this.state.fileName, this.state.fileType, todayTime)
.send({from:accounts[0], gas:300000})
.on('receipt', (receipt) => {
console.log('this should be executed now')
console.log("resultado =", receipt)
console.log("File submitted on blockchain!")
})
.on('error', console.error)
}
Either of these answers https://ethereum.stackexchange.com/a/58936/6814 and https://ethereum.stackexchange.com/a/59114/6814 are correct.

Calendar.events.lists callback parameter doesn't get called

I'm building chatbot using Dialogflow. I wanted to integrate it with Google Calendar, I followed the Google official tutorial on youtube. My code looks as follows:
function makeAppointment (agent) {
// Calculate appointment start and end datetimes (end = +1hr from start)
//console.log("Parameters", agent.parameters.date);
const appointment_type = agent.parameters.AppointmentType;
const dateTimeStart = new Date(Date.parse(agent.parameters.date.split('T')[0] + 'T' + agent.parameters.time.split('T')[1].split('-')[0] + timeZoneOffset));
const dateTimeEnd = new Date(new Date(dateTimeStart).setHours(dateTimeStart.getHours() + 1));
const appointmentTimeString = dateTimeStart.toLocaleString(
'en-US',
{ month: 'long', day: 'numeric', hour: 'numeric', timeZone: timeZone }
);
// Check the availibility of the time, and make an appointment if there is time on the calendar
var result = undefined;
var not_needed = createCalendarEvent(dateTimeStart, dateTimeEnd, appointment_type).then(() => {
agent.add(Ok, let me see if we can fit you in. ${appointmentTimeString} is fine!.);
result = 1;
}).catch(() => {
agent.add(I'm sorry, there are no slots available for ${appointmentTimeString}.);
result = 1
});
while(result == undefined) continue;
return not_needed;
}
function createCalendarEvent (dateTimeStart, dateTimeEnd, appointment_type) {
return new Promise((resolve, reject) => {
calendar.events.list({
auth: serviceAccountAuth, // List events for time period
calendarId: calendarId,
timeMin: dateTimeStart.toISOString(),
timeMax: dateTimeEnd.toISOString()
}, (err, calendarResponse) => {
// Check if there is a event already on the Calendar
if (err || calendarResponse.data.items.length > 0) {
reject(err || new Error('Requested time conflicts with another appointment'));
} else {
// Create event for the requested time period
calendar.events.insert({ auth: serviceAccountAuth,
calendarId: calendarId,
resource: {summary: appointment_type +' Appointment', description: appointment_type,
start: {dateTime: dateTimeStart},
end: {dateTime: dateTimeEnd}}
}, (err, event) => {
err ? reject(err) : resolve(event);
}
);
}
});
});
}
There is nothing in the response so I created an infinite while loop which is waiting for the promise to get resolved or rejected. Since than cloud function is getting timed out after 60 seconds because the while loop never breaks. Why is the callback passed to calendar.events.lists never called?
Thank you
The Dialogflow library is aware of promises. In fact, it is so aware of them that you must return a Promise if you are doing any asynchronous operations in your Handler function. It will wait for the Promise to be resolved before it sends anything back.
Since createCalendarEvent() returns a Promise already, you can return this Promise from makeAppointment().
You don't need the while loop - in fact, that is probably a big part of what isn't working. Since node is single-threaded, the thread never leaves the while loop to process the Promise, so result will never actually be set to 1.
Additionally, you probably don't need to wrap the calls to calendar.events.list() and calendar.events.insert() inside a new Promise(). If you don't provide a callback function for these, they will return a Promise, and you can handle them with standard then/catch blocks or await (if you're using a sufficiently modern version of node).

Parse Scheduled Background Jobs

I am trying to make an app which has daily quotes logic and shows quotes. It should picks random object in my parse class and shows them to user. If users saw the todays object they should be can't see different random object in same day.
I made this algorithm with Swift. But I think Cloud Code and Background Job is the more clear and right way to do this algorithm. I researched background job tutorials guides etc to made that but I couldn't because I don't have enough JavaScript knowledge to do that. Whatever I created Background Job in my Parse server like that;
Parse.Cloud.define('todaysMentor', async (request) => {
var Mentor = Parse.Object.extend('Mentor');
var countQuery = new Parse.Query(Mentor);
const count = await countQuery.count();
const query = new Parse.Query('Mentor');
const randomInt = Math.floor(Math.random() * count);
query.equalTo('position', randomInt);
query.limit(1); // limit to at most 10 results
const results = await query.find();
const Today = Parse.Object.extend('Today');
const today = new Today();
today.set('mentor', results[0]);
today.save()
.then((today) => {
// Execute any logic that should take place after the object is saved.
}, (error) => {
});
return results;
});
Parse.Cloud.job('pickTodaysMentor', async function(request) {
const { params, headers, log, message } = request;
Parse.Cloud.run('todaysMentor', (request) => {
if (!passesValidation(request.object)) {
throw 'Ooops something went wrong';
}
});
});
I want to get random Mentor object from my Mentor class and add it to Today class. In this way I can get Today object in my mobile apps. First function is working well when I call it with Swift.
My server logs like that;
May 13, 2019, 22:22:45 +03:00- ERROR
(node:41) UnhandledPromiseRejectionWarning: TypeError: Parse.Cloud.run is not a function
at Parse.Cloud.job (/opt/app-root/src/repo/cloud/functions.js:28:19)
at Object.agenda.define [as fn] (/opt/app-root/src/build/agenda/agenda.js:74:25)
at process._tickCallback (internal/process/next_tick.js:68:7)
May 13, 2019, 22:22:45 +03:00- ERROR
(node:41) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 4)
I googled this error and learned it is a syntax error with Parse 3.0 they changed some function syntax. How can I fix that? or Do you have any suggestion to make this algorithm ?
Thank you!
I'd suggest you to go with something like this:
async function todaysMentor() {
var Mentor = Parse.Object.extend('Mentor');
var countQuery = new Parse.Query(Mentor);
const count = await countQuery.count();
const query = new Parse.Query('Mentor');
const randomInt = Math.floor(Math.random() * count);
query.equalTo('position', randomInt);
query.limit(1); // limit to at most 10 results
const results = await query.find();
const Today = Parse.Object.extend('Today');
const today = new Today();
today.set('mentor', results[0]);
await today.save();
return results;
}
Parse.Cloud.define('todaysMentor', async (request) => {
return await todaysMentor();
});
Parse.Cloud.job('pickTodaysMentor', async function(request) {
return await todaysMentor();
});

Calculate total elapsed time of Promises till reject?

I want to test how much requests i can do and get their total time elapsed. My Promise function
async execQuery(response, query) {
let request = new SQL.Request();
return new Promise((resolve, reject) => {
request.query(query, (error, result) => {
if (error) {
reject(error);
} else {
resolve(result);
}
});
});
}
And my api
app.get('/api/bookings/:uid', (req, res) => {
let st = new stopwatch();
let id = req.params.uid;
let query = `SELECT * FROM booking.TransactionDetails WHERE UID='${id}'`;
for (let i = 0; i < 10000; i++) {
st.start();
db.execQuery(res, query);
}
});
I can't stop the for loop since its async but I also don't know how can I stop executing other calls after the one which first rejects so i can get the counter and the elapsed time of all successful promises. How can i achieve that?
You can easily create a composable wrapper for this, or a subclass:
Inheritance:
class TimedPromise extends Promise {
constructor(executor) {
this.startTime = performance.now(); // or Date.now
super(executor);
let end = () => this.endTime = performance.now();
this.then(end, end); // replace with finally when available
}
get time() {
return this.startTime - this.endTime; // time in milliseconds it took
}
}
Then you can use methods like:
TimedPromise.all(promises);
TimedPromise.race(promises);
var foo = new TimedPromise(resolve => setTimeout(resolve, 100);
let res = await foo;
console.log(foo.time); // how long foo took
Plus then chaining would work, async functions won't (since they always return native promises).
Composition:
function time(promise) {
var startTime = performance.now(), endTime;
let end = () => endTime = performance.now();
promise.then(end, end); // replace with finally when appropriate.
return () => startTime - endTime;
}
Then usage is:
var foo = new Promise(resolve => setTimeout(resolve, 100);
var timed = time(foo);
await foo;
console.log(timed()); // how long foo took
This has the advantage of working everywhere, but the disadvantage of manually having to time every promise. I prefer this approach for its explicitness and arguably nicer design.
As a caveat, since a rejection handler is attached, you have to be 100% sure you're adding your own .catch or then handler since otherwise the error will not log to the console.
Wouldn't this work in your promise ?
new Promise((resolve, reject) => {
var time = Date.now();
request.query(query, (error, result) => {
if (error) {
reject(error);
} else {
resolve(result);
}
});
}).then(function(r){
//code
}).catch(function(e){
console.log('it took : ', Date.now() - time);
});
Or put the .then and .catch after your db.execQuery() call
You made 2 comments that would indicate you want to stop all on going queries when a promise fails but fail to mention what SQL is and if request.query is something that you can cancel.
In your for loop you already ran all the request.query statements, if you want to run only one query and then the other you have to do request.query(query).then(-=>request.query(query)).then... but it'll take longer because you don't start them all at once.
Here is code that would tell you how long all the queries took but I think you should tell us what SQL is so we could figure out how to set connection pooling and caching (probably the biggest performance gainer).
//removed the async, this function does not await anything
// so there is no need for async
//removed initializing request, you can re use the one created in
// the run function, that may shave some time off total runtime
// but not sure if request can share connections (in that case)
// it's better to create a couple and pass them along as their
// connection becomes available (connection pooling)
const execQuery = (response, query, request) =>
new Promise(
(resolve, reject) =>
request.query(
query
,(error, result) =>
(error)
? reject(error)
: resolve(result)
)
);
// save failed queries and resolve them with Fail object
const Fail = function(detail){this.detail=detail;};
// let request = new SQL.Request();
const run = (numberOfTimes) => {
const start = new Date().getTime();
const request = new SQL.Request();
Promise.all(
(x=>{
for (let i = 0; i < numberOfTimes; i++) {
let query = `SELECT * FROM booking.TransactionDetails WHERE UID='${i}'`;
db.execQuery(res, query, request)
.then(
x=>[x,query]
,err=>[err,query]
)
}
})()//IIFE creating array of promises
)
.then(
results => {
const totalRuntime = new Date().getTime()-start;
const failed = results.filter(r=>(r&&r.constructor)===Fail);
console.log(`Total runtime in ms:${totalRuntime}
Failed:${failed.length}
Succeeded:${results.length-failed.length}`);
}
)
};
//start the whole thing with:
run(10000);

Categories

Resources