how to use process.hrtime to get execution time of async function - node.js

I am triing to get execution time of async function. Seemingly I can use process.hrtime for this. I created simple example:
console.log("starting");
var start = process.hrtime();
console.log("start");
console.log(start);
setTimeout(function(){
console.log("HELLO");
var end = process.hrtime();
console.log("end");
console.log(end);
}, 1000);
It outputs
starting
start
[ 131806, 731009597 ]
HELLO
end
[ 131807, 738212296 ]
But I don't understand where is exectuion time in miliseconds? I expect to get 1000 ms in this example.

Got it:
console.log("starting");
var start = process.hrtime();
console.log("start");
console.log(start);
setTimeout(function(){
console.log("HELLO");
var end = process.hrtime(start);
console.log("end");
console.log(end);
}, 1000);
Prints
starting
start
[ 132798, 207101051 ]
HELLO
end
[ 1, 7001730 ]
That means 1 second and 7001730 nanoseconds from start to end

Since Node 10.7.0, process.hrtime is marked as 'legacy', with the recommended method being process.hrtime.bigint. The documentation contains an example of how to use this method to time an operation:
const start = process.hrtime.bigint();
// 191051479007711n
setTimeout(() => {
const end = process.hrtime.bigint();
// 191052633396993n
console.log(`Benchmark took ${end - start} nanoseconds`);
// Benchmark took 1154389282 nanoseconds
}, 1000);

Just to add in case someone needs the execution time in ms:
console.log("starting");
var start = process.hrtime();
console.log("start");
console.log(start);
setTimeout(function(){
console.log("HELLO");
var end = process.hrtime(start); // end[0] is in seconds, end[1] is in nanoseconds
const timeInMs = (end[0]* 1000000000 + end[1]) / 1000000; // convert first to ns then to ms
console.log("timeInMs:", timeInMs);
}, 1000);

Here's a simple wrapper timing function for async functions:
// async function execution time wrapper
async function fnTime(fn, ...params) {
const start = process.hrtime()
const result = await fn(...params)
const end = process.hrtime(start)
console.log(
`[${fn.name}] Execution time:${(end[0] * 1000000000 + end[1]) /
1000000} ms`
)
return result
}
example usage (see this demo on repl.it):
// usage
const setTimeoutPromise = ms => new Promise(resolve => setTimeout(resolve, ms))
// example 2:
// get name from db
const db = {
async getUser(id){
// simulate wait for record retrival from db
await fnTime(setTimeoutPromise, 150)
return {
_id: id,
name: 'John Doe',
organisation: 'UN',
email: 'johndoe#un.org'
}
}
}
// test it
;(async function(){
const result = await fnTime(db.getUser, 'asfa98th4nfwef0qwrwef0')
console.log('result', result)
})()
// result:
// [setTimeoutPromise] Execution time:197.928094 ms
// [getUser] Execution time:199.480553 ms

Related

Run Nodejs App Every 6 Hours with Aysnc Await

I want to run a Script every 6 Hours
const { IgApiClient } = require("instagram-private-api")
const ig = new IgApiClient()
const USERNAME = "abc"
const PASSWORD = "xyz"
ig.state.generateDevice(USERNAME)
const main = async () => {
var birthday = new Date(2069, 05, 14);
var today = new Date();
birthday.setFullYear(today.getFullYear());
if (today > birthday) {
birthday.setFullYear(today.getFullYear() + 1);
}
var daystill = Math.floor((birthday - today) / (1000*60*60*24))
await ig.simulate.preLoginFlow()
await ig.account.login(USERNAME, PASSWORD)
process.nextTick(async () => await ig.simulate.postLoginFlow())
await ig.account.setBiography(`${daystill} Days till my Birthday, Today is ${new Date().getDate()}/${new Date().getMonth()}/${new Date().getFullYear()}. (AutoGenerated)`)
}
main()
instagram-private-api
About Script: update my Instagram Bio with Async Await
Problem / Goal:
I Tried using node-cron, but It returns some Error (I think Async is causing the Problem), I also tried while loops and setInterval()s
I want this Script/File to run every 6 Hours, I have a heroku account (if that helps)
Error when i use node-cron:
node:internal/process/promises:288
triggerUncaughtException(err, true /* fromPromise */);
Code for node-cron:
cron.schedule('* * * * *', () => { // this is not every 6hrs
const main = async () => {
//same as above
}
main()
})
Doing it the async await way as the title says.
// used to measure time
import { performance } from 'perf_hooks';
const interval = 1000; // in ms
(async function main(){
let start_time = performance.now();
// do stuff
let stop_time = performance.now();
let timeout = interval - (stop_time - start_time);
setTimeout(main, timeout);
})();
edit:
To explain the syntax behind the main function.
()(); will automatically call the function inside of first braces on script start.

Node-Cron: Running multiple schedules a day

Tags:
node-cron, ExpressJs, NodeJs, Replit, Uptimerobot
Situation:
Hey all!
I am trying to get my discord bot to send multiple messages every day on specific times.
I deployed my bot on Replit and use Uptimerobot to ping my app every 10 min to keep the bot live.
In my code I used node-cron shedules for each spicific time it should send a message:
imports
const express = require("express");
const router = express.Router();
const { Client, Intents, Guild } = require("discord.js");
const cron = require("node-cron");
const token = process.env['BOT_TOKEN']
const { promotions } = require("./promotions");
const { testServers } = require("./test-servers");
const { buildMessage } = require("./generateMessage");
Message generator
router.get("/", function(req, res, next) {
const client = new Client({
intents: [Intents.FLAGS.GUILDS],
allowedMentions: { parse: ["users", "roles"] }
});
const composeMessage = guilds => {
let thisGuild;
let discordChannel;
let role;
let holidays;
let start;
let end;
guilds.map((guild, key) => {
guild.channels.cache.map(channel => {
testServers.forEach((promo, index) => {
thisGuild = promo.guild_id;
discordChannel = promo.channel_id;
role = promo.role_id;
holidays = promo.holidays;
start = promo.start;
end = promo.end;
// All relevant promotions
if (discordChannel === channel.id.toString()) {
const notAHoliday = [];
const currentDate = new Date();
holidays.forEach(holiday => {
if (
currentDate >= holiday.start &&
currentDate.setUTCHours(23, 59, 59) <= holiday.end
) {
notAHoliday.push(false);
}
});
if (
notAHoliday.length === 0 &&
(currentDate >= promo.start &&
currentDate.setUTCHours(23, 59, 59) <= promo.end)
) {
const unfilteredMessage = buildMessage(role);
channel.send(unfilteredMessage);
}
}
});
});
});
};
When running the Bot
client.once("ready", () => {
console.log("READY!");
const guilds = client.guilds.cache.map(guild => guild);
cron.schedule("0 55 7 * * Mon,Tue,Wed,Thu,Fri", () => {
console.log("morning");
composeMessage(guilds);
});
cron.schedule("0 31 11 * * Mon,Tue,Wed,Thu,Fri", () => {
console.log("start lunch");
composeMessage(guilds);
});
cron.schedule("0 25 12 * * Mon,Tue,Wed,Thu,Fri", () => {
console.log("end lunch");
composeMessage(guilds);
});
cron.schedule("0 0 16 * * Mon,Tue,Wed,Thu,Fri", () => {
console.log("evening");
composeMessage(guilds);
});
});
client.login(token);
botStatus = "Active";
res.render('index', { status: botStatus, version: "1.0.0" })
});
module.exports = router;
Issue:
The timers work but every time it runs a schedule, I get back a bunch of messages (the longer between schedules, the more messages my bot sends)
I suspect that it has to do with the pinging and the schedules stocking those runs until the shedule runs active and releases it all..
But how should I fix this?
Thanks in advance!

Converting process.hrtime() to milliseconds

I have existing code that does the following use of hrtime
before = process.hrtime()
// stuff happens...
after = process.hrtime(before)
latency = (after[0] * 1000000000 + after[1]) / 1000000;
What unit is latency above?
Turns out the above is in fact milliseconds. Since setTimeout takes the delay value in milliseconds, it's easy to validate my hrtime juggling:
const times = []
const delays = [1, 10, 100, 1000, 1001, 1100];
function sleep(ms) {
return new Promise((res) => {
setTimeout(res, ms);
});
}
async function main() {
for (let ms of delays) {
const ping = process.hrtime();
await sleep(ms);
const pong = process.hrtime(ping);
const latency = (pong[0] * 1000000000 + pong[1]) / 1000000;
times.push(latency);
}
console.log(times);
// >>> [2.031091, 11.623596, 101.971041, 1000.554953, 1001.192077, 1104.29338]
}
main();

How to assert on callback when using jest.useFakeTimers

I'm trying to understand how to correctly unit test a custom debounce method we have:
// function we want to test
function debounce(func, wait = 100) {
let timeout;
return (...args) => {
clearTimeout(timeout);
timeout = setTimeout(() => {
func.apply(this, args);
}, wait);
};
}
Here is the Jest unit test that is failing:
describe('DebounceExample', () => {
beforeAll(jest.useFakeTimers);
afterAll(jest.useRealTimers);
it('should debounce', () => {
// given
const data = 'Chuck Norris is faster than you think';
const debounceTime = 5000;
const callback = jest.fn();
const debouncedFunction = debounce(callback, debounceTime);
// when
debouncedFunction(data);
// then
expect(callback).not.toHaveBeenCalled();
// when
jest.runAllTimers(); // jest.advanceTimersByTime(debounceTime);
// then
expect(callback).toHaveBeenCalled();
});
});
Failure:
Error: expect(jest.fn()).toHaveBeenCalled()
Expected number of calls: >= 1
Received number of calls: 0 Jest
I've also tried the solution here: https://stackoverflow.com/a/52638566/704681 without success
Workaround: the only way I'm able to test it so far:
it('should denounce - workaround', (done) => {
// given
const data = 'Chuck Norris is faster than you think';
const debounceTime = 5000;
const callback = jest.fn((param) => {
// then
expect(param).toEqual(data);
done();
});
const debouncedFunction = debounce(callback, debounceTime);
// when
debouncedFunction(data);
// then
expect(callback).not.toHaveBeenCalled();
// when (see 'then' inside callback implementation)
jest.runAllTimers(); // jest.advanceTimersByTime(debounceTime);
});

8 logical cpu's should give *8 run time benefit?

the code i am running when using promise.all should run at about \8 the time when i am using regular "blocking" for, but the result is very similar not even half the time.
i have tried to run this 2 NODEJS programs in the same computer.
WHEN USING PROMISE.ALL
let user = { "name": "shay", "interests": ["category1", "category2", "category3", "category4", "category5", "category6", "category7", "category8", "category9", "category10"] }
let result = [];
let Companies = [];
for (i = 0; i < 3000000; i++) {
let company = { "name": "company" + i, "interest": "category" + (Math.floor(Math.random() * 10) + 1) };
Companies.push(company);
}
const successRate = () => {
return (Math.floor(Math.random() * 100) + 1) + "%"
}
const task = function (interest) {
return new Promise((resolve, reject) => {
Companies.forEach(company => {
if (company.interest == interest)
result.push({ "company": company.name, "interest": company.interest, "success": successRate() })
});
resolve('succeed!');
});
};
const run = async function () {
let tasks = user.interests.map(interest => {
return task(interest)
});
await Promise.all(tasks);
}
const start = Date.now();
run();
WHEN USING REGULAR FOR
let user = {"name":"shay","interests":["category1","category2","category3","category4","category5","category6","category7","category8","category9","category10"]}
let result =[];
let Companies = [];
for (i=0;i<3000000;i++)
{
let company = {"name":"company"+i,"interest":"category"+(Math.floor(Math.random() * 10) + 1)};
Companies.push(company);
}
const successRate=()=>{
return (Math.floor(Math.random() * 100) + 1)+"%"
}
const start = Date.now();
user.interests.forEach(interest => {
Companies.forEach(company => {
if (company.interest==interest)
result.push({"company":company.name,"interest":company.interest,"success":successRate()})
});
});
console.log("run time",Date.now()-start);
the promise.all total run time is 1314
the regular for total run time is 1430
Node.js follows a single threaded architecture, it doesn't create a new thread for a new promise - everything runs in the same thread. Asynchronous behaviour is achieved via event loop, underlying OS concurrency and libuv. If you're familiar with Nginx - it actually works pretty much the same way. So don't mix JavaScript's Promise<> with Java's Future<>.

Resources