Trigger a function at particular time everyday in javascript - node.js

I'm creating a birthday app where I want to trigger a function at a particular time Eg. At 6 AM. But I'm not getting any idea of how to implement that. Please give a suggestion. Using react as frontend and express as backend and database I use MongoDB. Also, any code reference will help .Thank you in advance.

You can try smth like this, after component rendered setInterval function will check if it is your birthday now or not.Finally, in right moment will invoke some func and disable itself.
import React, { useEffect } from 'react';
const BirthDay = () => {
const date = new Date('2022-12-17T03:24:00') //your birthday here
const birthdayFunc = () => {console.log('Birthday!!!')}
const checkBirthday = () => {
if(new Date() >= date) birthdayFunc()
else return
}
useEffect(
() => {
const id = setInterval(function()
{
if(new Date() >= date)
{
birthdayFunc()
clearInterval(id)
}
else return
}, 1000);
return () => clearInterval(id);
},
[]
);
return <div></div>;
};

A solution can be using a job scheduler such as crontab on Linux machine. If its Windows, cron is called scheduled tasks and It's in the Control Panel. It allows to trigger periodically perform a task.

Related

reload API call at intervals based on the current path via svelte-pathfinder

I'm using svelte-pathfinder to observe URL parameters that are then sent to a method which runs an async API call. I'd like to be able to re-run my API call based on the current path at an interval (for example, every 50 seconds).
stores.js (note that fetchContests is a method that runs a await fetch() call to an external API based on the pattern and query values from svelte-pathfinder:
// routing
export const resultStore = derived([pattern, query], ([$pattern, $query], set) => {
if ($pattern('/search/') && $query.params.q) {
new Promise((resolve) => {
setTimeout(() => {
fetchContests('title', $query.params.q, true)
.then(set);
resolve()
}, delay)
})
} else if ($pattern('/')) {
new Promise((resolve) => {
setTimeout(() => {
fetchContests('contest_ids', dashboard, true)
.then(set);
resolve({name: "testing"})
}, delay)
})
}
}, []);
Results.svelte (where I display the results of the API call):
<script>
// data
export let promise;
import { resultStore } from './../stores.js';
// layout components
import Contest from "./Contest.svelte";
</script>
{#await promise}
<p>Loading contests</p>
{:then}
<ul>
{#each $resultStore as contest}
<Contest contest="{contest}"/>
{/each}
</ul>
{:catch error}
<p>Something went wrong: {error.message}</p>
{/await}
This works really well in a non-repetitive way:
On initial page load, it runs an API call based on the current path
Whenever the path changes (a link click or a form submission or whatever), it runs another API call with those parameters. Each call gets the appropriate data from the API.
What I haven't been able to do is add setInterval to this in a way that preserves the path. So if the path is http://localhost:8080/#!/search?q=governor and 50 seconds have elapsed, the interval would make an API call with those current parameters to retrieve updated data. If the path is http://localhost:8080/, or http://localhost:8080/#!/search?q=senator instead when the next 50 seconds have elapsed, it would do the same with those parameters.
Originally, I thought maybe I could add setInterval to the API call itself, which is an async function that runs await fetch. But this didn't work, it would run multiple API calls ignoring the current path and parameter settings. I thought maybe I could run it within resultStore instead (above), but then it only ran after 50 seconds instead of running on initial page load and then again after each 50 second interval.
When extracting the logic that should run every time pattern or query changes and after a given interval after that, I think this might match what you want to do?
let delay = 50000
// routing
export const resultStore = derived([pattern, query], ([$pattern, $query], set) => {
fetchAndSet($pattern, $query, set)
const interval = setInterval(() => {
fetchAndSet($pattern, $query, set)
}, delay);
// If you return a function from the callback, it will be called when
// a) the callback runs again, or b) the last subscriber unsubscribes.
return () => {
clearInterval(interval);
};
}, []);
function fetchAndSet($pattern, $query, set) {
if ($pattern('/search/') && $query.params.q) {
fetchContests('title', $query.params.q, true).then(set)
} else if ($pattern('/')) {
fetchContests('contest_ids', dashboard, true).then(set)
}
}

Is there any way to call useeffect until the data had been fetched properly?

I want to fetch my data from backend mongodb but the useeffect is rendering only once and at that moment data is not fetched quickly resulting in lots of undefined errors.
Here is my code:
const [xnaLogData,setXnaLogData]=useState([]);
const [xnaLogMember,setXnaLogMember]=useState("");
const [balance,setBalance]=useState(0);
useEffect(() => {
setXnaLogMember(Cookies.get('member_userr'));
alert(xnaLogMember);
const calBal = () => {
var sum = xnaLogData.reduce(function(prev, current) {
return prev + +current.balance
}, 0);
setBalance(sum);
}
const fetchXna = async () => {
const response = await fetch('/xnaloginforoute');
const json = await response.json();
setXnaLogData(json.xnacomp);
calBal();
console.log(json.xnacomp)
console.log(xnaLogData);
}
fetchXna();
},[]);
If i put },[xnaLogData]); inside the useeffect line },[]); it will start a continous chain of useeffect and the data is fetching in 3rd or 4th attempt of effect. I am unable to solve this issue
Ok, this is a typical useEffect question.
Let's revisit your logic a bit.
useEffect(() => {
setAbc(value)
}, [abc])
The problem of the above is an endless loop, unless the value can reach a stable value after couple of runs. Thus most of time, we have a short circuit line installed to break it off.
useEffect(() => {
if (count > 2) return
setCount(v => v + 1)
}, [count])
Either way i think you get the idea, either loop or not, it's entirely controlled by YOU, react is not going to make a decision what to do. You can rethink why you want to re-run the effect upon the value change.

Correct way to organise this process in Node

I need some advice on how to structure this function as at the moment it is not happening in the correct order due to node being asynchronous.
This is the flow I want to achieve; I don't need help with the code itself but with the order to achieve the end results and any suggestions on how to make it efficient
Node routes a GET request to my controller.
Controller reads a .csv file on local system and opens a read stream using fs module
Then use csv-parse module to convert that to an array line by line (many 100,000's of lines)
Start a try/catch block
With the current row from the csv, take a value and try to find it in a MongoDB
If found, take the ID and store the line from the CSV and this id as a foreign ID in a separate database
If not found, create an entry into the DB and take the new ID and then do 6.
Print out to terminal the row number being worked on (ideally at some point I would like to be able to send this value to the page and have it update like a progress bar as the rows are completed)
Here is a small part of the code structure that I am currently using;
const fs = require('fs');
const parse = require('csv-parse');
function addDataOne(req, id) {
const modelOneInstance = new InstanceOne({ ...code });
const resultOne = modelOneInstance.save();
return resultOne;
}
function addDataTwo(req, id) {
const modelTwoInstance = new InstanceTwo({ ...code });
const resultTwo = modelTwoInstance.save();
return resultTwo;
}
exports.add_data = (req, res) => {
const fileSys = 'public/data/';
const parsedData = [];
let i = 0;
fs.createReadStream(`${fileSys}${req.query.file}`)
.pipe(parse({}))
.on('data', (dataRow) => {
let RowObj = {
one: dataRow[0],
two: dataRow[1],
three: dataRow[2],
etc,
etc
};
try {
ModelOne.find(
{ propertyone: RowObj.one, propertytwo: RowObj.two },
'_id, foreign_id'
).exec((err, searchProp) => {
if (err) {
console.log(err);
} else {
if (searchProp.length > 1) {
console.log('too many returned from find function');
}
if (searchProp.length === 1) {
addDataOne(RowObj, searchProp[0]).then((result) => {
searchProp[0].foreign_id.push(result._id);
searchProp[0].save();
});
}
if (searchProp.length === 0) {
let resultAddProp = null;
addDataTwo(RowObj).then((result) => {
resultAddProp = result;
addDataOne(req, resultAddProp._id).then((result) => {
resultAddProp.foreign_id.push(result._id);
resultAddProp.save();
});
});
}
}
});
} catch (error) {
console.log(error);
}
i++;
let iString = i.toString();
process.stdout.clearLine();
process.stdout.cursorTo(0);
process.stdout.write(iString);
})
.on('end', () => {
res.send('added');
});
};
I have tried to make the functions use async/await but it seems to conflict with the fs.openReadStream or csv parse functionality, probably due to my inexperience and lack of correct use of code...
I appreciate that this is a long question about the fundamentals of the code but just some tips/advice/pointers on how to get this going would be appreciated. I had it working when the data was sent one at a time via a post request from postman but can't implement the next stage which is to read from the csv file which contains many records
First of all you can make the following checks into one query:
if (searchProp.length === 1) {
if (searchProp.length === 0) {
Use upsert option in mongodb findOneAndUpdate query to update or upsert.
Secondly don't do this in main thread. Use a queue mechanism it will be much more efficient.
Queue which I personally use is Bull Queue.
https://github.com/OptimalBits/bull#basic-usage
This also provides the functionality you need of showing progress.
Also regarding using Async Await with ReadStream, a lot of example can be found on net such as : https://humanwhocodes.com/snippets/2019/05/nodejs-read-stream-promise/

setInterval() with fresh database data?

Hello and thank you in advance for taking your time to help me,
I've a setInterval() script who change some data in my MongoDB.
For example:
const isOn = mySavedDatabase.isOn;
var timer = setInterval(function() {
fetch('https://thewebsite.com', options)
.then(res => {
return res.json();
}).then(async data => {
if(data.data[0] && isOn == false) {
await xx.updateMe(xxx.id, { "isOn": true });
// some others actions here
} else if(isOn && !data.data[0]) {
await xx.updateMe(xxx.id, { "isOn": false });
} else if(isOn && data.data[0]) {
// nothing to do here.
}
})
}, 60000);
This script works fine, but it does not take the new changed data from the database.
If in the database, when the script starts, the value of "isOn" is true, it will remain true until the end of the script even if, in this one, I changed the data.
I checked, the value is changed by the setInterval() but, as long as it is in the loop, it does not take data from the database that it itself has changed.
Currently, for setInterval() work, I have to add each time :
clearInterval(timer);
But, it does not respect the time of one minute that I put and it sends way more requests than 1 per minute.
You will need to re-evaluate mySavedDatabase.isOn
I would just remove constant isOn, and use mySavedDatabase.isOn instaed.
Resolved.
Just pass the:
const isOn = mySavedDatabase.isOn;
In the setInterval() to get fresh data.

Capture Total Time or duration of a Test Suite using Jasmine Hook

I have been trying to retrieve 'totalTime' from the jasmineDone hook or 'duration' from SuiteResult as documented at [https://jasmine.github.io/api/edge/global.html#] but they don't seem to be available. Would be grateful for any pointers?
I found #DublinDev answer to this Jasmine get current test result which was so helpful. This allows me to get the duration per test using the specDone hook which I could potentially use and add each result, but I am curious to know if I am doing something wrong.
I am using the following code from the link above( 2nd link) and would expect either of the console.logs to output a time but neither are outputting anything
function dbReporter() {
this.jasmineStarted = function (options) { };
this.specStarted = function (result) { };
this.specDone = async function (result) { };
this.suiteStarted = function (result) { };
this.suiteDone = function (result) {
console.log('duration=', result.duration)
}
this.jasmineDone = async function (result) {
console.log('totalTime=', result.totalTime)
}
}
module.exports = dbReporter;
Given that you have the latest version of Jasmine already I would recommend just making your own timer which starts in jasmineStarted hook and ends in JasmineDone hook.
onPrepare: () => {
//Create a global variable to be used for the timer
global.jasmineTimer = 0;
jasmine.getEnv().addReporter({
jasmineStarted: function (options) {
jasmineTimer = Date.now();
console.log(`Starting execution ${jasmineTimer}`)
},
jasmineDone: async function (result) {
console.log(`Finished execution in ${(Date.now() - jasmineTimer) / 1000}s`)
}
})
}

Resources