On my react js SPA I need to call a function (that fetches an api to refresh access token) every 5 minutes. My first thought was on App.js:
useEffect(() => {
const interval = setInterval(() => {
// fetch API
}, 5*60*1000);
return () => {
clearInterval(interval);
};
}, []);
Problem is: say user refreshed page, or navigated to another page before the 5 minutes, then the action to fetch the API will be postponed for another 5 minutes, and so on.
What's the best approach to achieve what I'm expecting?
User logs in successfully
Set "timer" to fetch the API every 5 minutes regardless pages refreshes or user navigation.
Like a synchronous API fetch
I use node-schedule its a library you can use to schedule jobs, you might be able to schedule a job every 5 minutes of an hour so that even if the user refeshes it will still call the function at the 5th minute. For instance: I load the page at 12:53 and the job is scheduled for every 5th minute so it would call the function at 12:55. If I then refesh the page it will still schedule the job at 12:55. I'm not sure if this is what you're looking for but it might be an option.
For my program I have it setup so it calls a function every midnight.
const schedule = require('node-schedule');
schedule.scheduleJob('0 0 * * *', () => {
updateData()
})
You can find some examples here
you can save info about previous refresh in local storage, session storage and even cookies
Related
I am creating a function on my server which is supposed to trigger daily, but not only does it not trigger as expected it triggers every time the server is reset (which it did not do yesterday). The data only needs updated once a day and rapidapi is pay per api call after 100 calls a day, so I'm really trying to get this scheduled job working.
I've only tried node-schedule on my server, which has a dependency of CRON (which is why scheduleJob is using the CRON format). Originally the function triggered as fast as my computer could refresh the server, so I know the scheduleJob is stopping the API call from being constant.
schedule.scheduleJob('* * */23 * *', function () {
console.log('Daily API call initiated.');
unirest.get("https://unogs-unogs-v1.p.rapidapi.com/aaapi.cgi?q=get:exp:US&t=ns&st=adv&p=1")
.header("X-RapidAPI-Host", "unogs-unogs-v1.p.rapidapi.com")
.header("X-RapidAPI-Key", `${keys.RICHARD_UNOGS_KEY}`)
.end(function (result) {
console.log(result.status, result.headers);
//console.log(result.body) to see all data
let data = JSON.stringify(result.body)
fs.writeFile('./movieData.json', data)
});
})
Is there a better way to write this function or achieve the desired results? I only need it triggering once per day, but my computer isn't on 24/7. Since I'm still developing the app, I don't think hosting the server on Heroku or another platform is time-efficient, but I'm more than willing to try it if it'll solve my issue.
The main goal is to tell my server to run it once a day, but to check if it was run in the last 24 hours. If it hasn't been run, run it.
ANSWERED BY jakemingolla: My CRON expression was incorrectly formatted for my intended use. * * */23 * * has the function triggering on every 23rd day (today is the 24th, +1 for index value) with no limitation or other value. That's why my function was calling constantly today. I changed my CRON expression to 15 9 * * * to trigger my API call every morning at 0915 hours.
I'm not sure your CRON format is correct based on https://crontab.guru. Based on * * */23 * *, that would correspond to "“At every minute on every 23rd day-of-month", which does not sound like what you want.
For example, the CRON string 0 0 * * * * is every day at midnight. I would update that CRON string to see if it helps alleviate the problem.
My app makes a fetch to a web service that can sometimes be slow to respond due to circumstances out of my control. It seems that if it gets stuck waiting for a response, the solution is to fetch for the data again. How would one make a function to fetch fetch for data every 10 seconds, and stop when the endpoint delivers a result?
In plain JavaScript you can use setInterval
var myInterval = setInterval(tryToGetData, 10000); // Try to get data every 10 secs
function tryToGetData() {
// Get your data here, preferably as a promise
yourDataPromise.then((data) => {
clearInterval(myInterval); // Stop trying to get data every 10 secs
// Do stuff with
});
}
However a much better way is to retry the promise when it naturally fails, by trying to get the data again by catching the promise itself.
You need to set a timer that will fetch data every 10 seconds
and if the data is found, you will clear the timer so that data will not be fetch again
var data = setInterval(function(){
// call fetch data function
fetchData((err, data) => {
if(data) {
clearInterval(data);
}
})
}, 10000);
function fetchData(cb) {
// rightnow we are passing data '1' to the callback so the timer will run only once as data is fetched
// try removing '1' and you will see that `fetchData` function is called on every 10 seconds
cb(null, 1);
}
I am creating a dashboard for a skype bot. I am requesting data for every 10 seconds.
Problem is I am getting the same data from API. But, when I refresh app am getting update data from API.
I am using the setInterval function to request data from the server every 10 secs.
I also tried with rxjs6 timer Observable and concatmap operator but the result is same as before.
setInterval(() => {
this.initTopBlockData();
this.getGraphData(this.calenderStart, this.calenderEnd, () => { });
}, 10000);
Iam using the above function and intilizing it on ngOninit lifecycle hook
public ngOnInit(): void {
this.initTopBlockData();
this.loadGraphData(this.calenderStart, this.calenderEnd);
setInterval(() => {
this.initTopBlockData();
this.getGraphData(this.calenderStart, this.calenderEnd, () => { });
}, 10000);}
Above is how I am calling an API.
For each API call, the date I am sending is not updating. I Make sure that date is updated and am getting data updated.
You need to update the passed values of this.CalenderStart and end each time you rewuesting data
I am creating a route where a data attribute called "active" is being set to true, but after an hour is set to false. I am wondering if it is possible or bad practice to call a settimeout function in the express callback. Such as;
app.get("/test", (req, res) => {
//Some code
SetTimeout(func, 3600);
});
Is this bad for scalling, if this route was hit many times would it be very expensive? Thanks in advance.
If you store those values in a database, then you should not create a timer per entry in node that will reset this value. Especially it if it is a lang lasting timer, Session like/related data that should last longer then a few seconds should in general not be keept in the memory of the node process.
The more frequently your site is visited, the more likely it is that you have at least one timer running at any time. As soon as this is the case you are not able to restart the application without either loosing that timer. Or you need to wait until all timers are finished and while that don't accept any new ones.
And you cannot switch to clustered mode, because then if one user calls that route twice, it might end up in two different processes, each of those processes would not know of the timeouts the other process has set.
So a better idea is to add a timestamp into the database, and one cleanup timer responsible for all entries.
It seems you only need to set 1 timer. This assumes the 'hour' starts at the first request.
let timer = null
let data = true
app.get("/test", (req, res) => {
//Some code
if (!timer) {
timer = setTimeout(() => {data=false}, 3600);
}
});
Instead, for multiple users, you can avoid setting multiple timers by putting a timestamp in a hash and polling it per request or a separate interval timer.
// init
let timers = {}
// in request
if (!timers[user]) {
timers[user] = new Date().getTime() / 1000 + 3600
}
else if (timers[user] <= new Date().getTime() / 1000)
{
// update db, etc
}
// or poll for expirations in separate single timer routine
let now = new Date().getTime() / 1000
Object.keys(timers).forEach(user => {
if (timers[user] <= now) {
// update db, etc
}
})
I have an application in which a user can manage multiple alarms (set a new alarm, edit it, or snooze)
When the alarm time is reached I need to notify the user. If a user clicks snooze, the time_end field gets 5 minutes added to it.
How can I track when the alarm times have been reached?
I have tried using a collection.observe() - but it only works once, on server start
Server: Meteor Startup
var expiredAlarms = Alarms.find({$and: [{"time_end": {$lt: moment()._d}}, {notification_sent: false}]});
expiredAlarms.observe({
added: function(doc) {
console.log('alarm timeout has been reached');
processAlarmEnd(); //set notification_sent to true
},
removed: function(doc) {
console.log('A notification has been sent');
}
});
The above code only works when the app is started and processes all notifications for expired alarms - but once new alarms expire, nothing happens. My guess is because moment()._d does not change and the same old query is called over and over again.
Should I place this code in a Tracker.autorun - will that help? Any suggestions on doing this better/smarter?
To make code execute in the future, you need to use setTimeout. In your observe query, don't care about the time, and in the added callback, calculate how many milliseconds remains till the alarm should go off, and use setTimeout to call processAlarmEnd after that amount of milliseconds.
You may also need to cancel a setTimeout with clearTimeout in the removed callback.