Node-Schedule Triggering Issue - javascript

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.

Related

Call function on specific time on react js app?

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

Discord.js do something in specific time

I would like to make bot that in specific time every day will for example message but i want that the bot can still response to commands. Is there any node.js library or some function.
You can use the cron package to do this.
You first have to import CronJob:
const { CronJob } = require('cron');
If you want to scedule a message at 17:18 everyday, you define a CronJob like this:
const job = new CronJob('0 18 17 * * *', () => {
//send a message
});
and start it:
job.start();
the format for the string is 'sec min hour day of month month day of week'. You use * if all values of that parameter is accepted. Your callback function will be called everytime all 6 of the paremeters match the current time. The sec parameter must not be *, or else the message would get sent every second in that minute.

callback in node-schedule's callback

In my (express.js based) loopback app I want to schedule a task to run every 1 second. It should count every open ticket, and if they already open for a certain time, then an email should be sent. Below is a simplified code.
The problem, that 'scheduleJob' is logged, as expected, but the number of tickets is not. I think it is a context problem. How should I log the number of the found ticket? How should I communicate back from count 's callback to the schedule 's callback?
var schedule = require('node-schedule');
module.exports = function(app) {
var Ticket = app.models['Ticket']
var j = schedule.scheduleJob('* * * * * *', function(){
console.log('scheduleJob')
Ticket.count(function(err, count){
if (err) {console.log(err)}
console.log(count)
})
});
};
Do not count all the open ticket like that - It costs a lots of resources.
You should keep the number of ticket in your node.js and increase/decrease it. If you have multiple processes interacting with the database, makes one of them your master and make it handle this task.
About your problem, it seems that the library node-schedule do not support asynchronous calls.
Algorithm
At your program start, look up at the ticket in your database and retrieve the next timestamp when you should send an email.
Example, you want to send an email if a ticket is open for 1 hour, and your database have :
ticket 1 / 10 min
ticket 2 / 40 min
So your next mail should be sent in 20 min (60 min - 40 min).
use setTimeout() to wake up your node in 20 min. When you wake up, send the mail, and look at your database again for the next mail to send.
Recalcul your setTimeout if there is a new Ticket inserted in your database or If one get removed/updated.

Firestore slow performance issue on getting data

I'm having slow performance issues with Firestore while retrieving basic data stored in a document compared to the realtime database with 1/10 ratio.
Using Firestore, it takes an average of 3000 ms on the first call
this.db.collection(‘testCol’)
.doc(‘testDoc’)
.valueChanges().forEach((data) => {
console.log(data);//3000 ms later
});
Using the realtime database, it takes an average of 300 ms on the first call
this.db.database.ref(‘/test’).once(‘value’).then(data => {
console.log(data); //300ms later
});
This is a screenshot of the network console :
I'm running the Javascript SDK v4.50 with AngularFire2 v5.0 rc.2.
Did anyone experience this issue ?
UPDATE: 12th Feb 2018 - iOS Firestore SDK v0.10.0
Similar to some other commenters, I've also noticed a slower response on the first get request (with subsequent requests taking ~100ms). For me it's not as bad as 30s, but maybe around 2-3s when I have good connectivity, which is enough to provide a bad user experience when my app starts up.
Firebase have advised that they're aware of this "cold start" issue and they're working on a long term fix for it - no ETA unfortunately. I think it's a separate issue that when I have poor connectivity, it can take ages (over 30s) before get requests decide to read from cache.
Whilst Firebase fix all these issues, I've started using the new disableNetwork() and enableNetwork() methods (available in Firestore v0.10.0) to manually control the online/offline state of Firebase. Though I've had to be very careful where I use it in my code, as there's a Firestore bug that can cause a crash under certain scenarios.
UPDATE: 15th Nov 2017 - iOS Firestore SDK v0.9.2
It seems the slow performance issue has now been fixed. I've re-run the tests described below and the time it takes for Firestore to return the 100 documents now seems to be consistently around 100ms.
Not sure if this was a fix in the latest SDK v0.9.2 or if it was a backend fix (or both), but I suggest everyone updates their Firebase pods. My app is noticeably more responsive - similar to the way it was on the Realtime DB.
I've also discovered Firestore to be much slower than Realtime DB, especially when reading from lots of documents.
Updated tests (with latest iOS Firestore SDK v0.9.0):
I set up a test project in iOS Swift using both RTDB and Firestore and ran 100 sequential read operations on each. For the RTDB, I tested the observeSingleEvent and observe methods on each of the 100 top level nodes. For Firestore, I used the getDocument and addSnapshotListener methods at each of the 100 documents in the TestCol collection. I ran the tests with disk persistence on and off. Please refer to the attached image, which shows the data structure for each database.
I ran the test 10 times for each database on the same device and a stable wifi network. Existing observers and listeners were destroyed before each new run.
Realtime DB observeSingleEvent method:
func rtdbObserveSingle() {
let start = UInt64(floor(Date().timeIntervalSince1970 * 1000))
print("Started reading from RTDB at: \(start)")
for i in 1...100 {
Database.database().reference().child(String(i)).observeSingleEvent(of: .value) { snapshot in
let time = UInt64(floor(Date().timeIntervalSince1970 * 1000))
let data = snapshot.value as? [String: String] ?? [:]
print("Data: \(data). Returned at: \(time)")
}
}
}
Realtime DB observe method:
func rtdbObserve() {
let start = UInt64(floor(Date().timeIntervalSince1970 * 1000))
print("Started reading from RTDB at: \(start)")
for i in 1...100 {
Database.database().reference().child(String(i)).observe(.value) { snapshot in
let time = UInt64(floor(Date().timeIntervalSince1970 * 1000))
let data = snapshot.value as? [String: String] ?? [:]
print("Data: \(data). Returned at: \(time)")
}
}
}
Firestore getDocument method:
func fsGetDocument() {
let start = UInt64(floor(Date().timeIntervalSince1970 * 1000))
print("Started reading from FS at: \(start)")
for i in 1...100 {
Firestore.firestore().collection("TestCol").document(String(i)).getDocument() { document, error in
let time = UInt64(floor(Date().timeIntervalSince1970 * 1000))
guard let document = document, document.exists && error == nil else {
print("Error: \(error?.localizedDescription ?? "nil"). Returned at: \(time)")
return
}
let data = document.data() as? [String: String] ?? [:]
print("Data: \(data). Returned at: \(time)")
}
}
}
Firestore addSnapshotListener method:
func fsAddSnapshotListener() {
let start = UInt64(floor(Date().timeIntervalSince1970 * 1000))
print("Started reading from FS at: \(start)")
for i in 1...100 {
Firestore.firestore().collection("TestCol").document(String(i)).addSnapshotListener() { document, error in
let time = UInt64(floor(Date().timeIntervalSince1970 * 1000))
guard let document = document, document.exists && error == nil else {
print("Error: \(error?.localizedDescription ?? "nil"). Returned at: \(time)")
return
}
let data = document.data() as? [String: String] ?? [:]
print("Data: \(data). Returned at: \(time)")
}
}
}
Each method essentially prints the unix timestamp in milliseconds when the method starts executing and then prints another unix timestamp when each read operation returns. I took the difference between the initial timestamp and the last timestamp to return.
RESULTS - Disk persistence disabled:
RESULTS - Disk persistence enabled:
Data Structure:
When the Firestore getDocument / addSnapshotListener methods get stuck, it seems to get stuck for durations that are roughly multiples of 30 seconds. Perhaps this could help the Firebase team isolate where in the SDK it's getting stuck?
Update Date March 02, 2018
It looks like this is a known issue and the engineers at Firestore are working on a fix. After a few email exchanges and code sharing with a Firestore engineer on this issue, this was his response as of today.
"You are actually correct. Upon further checking, this slowness on getDocuments() API is a known behavior in Cloud Firestore beta. Our engineers are aware of this performance issue tagged as "cold starts", but don't worry as we are doing our best to improve Firestore query performance.
We are already working on a long-term fix but I can't share any timelines or specifics at the moment. While Firestore is still on beta, expect that there will be more improvements to come."
So hopefully this will get knocked out soon.
Using Swift / iOS
After dealing with this for about 3 days it seems the issue is definitely the get() ie .getDocuments and .getDocument. Things I thought were causing the extreme yet intermittent delays but don't appear to be the case:
Not so great network connectivity
Repeated calls via looping over .getDocument()
Chaining get() calls
Firestore Cold starting
Fetching multiple documents (Fetching 1 small doc caused 20sec delays)
Caching (I disabled offline persistence but this did nothing.)
I was able to rule all of these out as I noticed this issue didn't happen with every Firestore database call I was making. Only retrievals using get(). For kicks I replaced .getDocument with .addSnapshotListener to retrieve my data and voila. Instant retrieval each time including the first call. No cold starts. So far no issues with the .addSnapshotListener, only getDocument(s).
For now, I'm simply dropping the .getDocument() where time is of the essence and replacing it with .addSnapshotListener then using
for document in querySnapshot!.documents{
// do some magical unicorn stuff here with my document.data()
}
... in order to keep moving until this gets worked out by Firestore.
Almost 3 years later, firestore being well out of beta and I can confirm that this horrible problem still persists ;-(
On our mobile app we use the javascript / node.js firebase client. After a lot of testing to find out why our app's startup time is around 10sec we identified what to attribute 70% of that time to... Well, to firebase's and firestore's performance and cold start issues:
firebase.auth().onAuthStateChanged() fires approx. after 1.5 - 2sec, already quite bad.
If it returns a user, we use its ID to get the user document from firestore. This is the first call to firestore and the corresponding get() takes 4 - 5sec. Subsequent get() of the same or other documents take approx. 500ms.
So in total the user initialization takes 6 - 7 sec, completely unacceptable. And we can't do anything about it. We can't test disabling persistence, since in the javascript client there's no such option, persistence is always enabled by default, so not calling enablePersistence() won't change anything.
I had this issue until this morning. My Firestore query via iOS/Swift would take around 20 seconds to complete a simple, fully indexed query - with non-proportional query times for 1 item returned - all the way up to 3,000.
My solution was to disable offline data persistence. In my case, it didn't suit the needs of our Firestore database - which has large portions of its data updated every day.
iOS & Android users have this option enabled by default, whilst web users have it disabled by default. It makes Firestore seem insanely slow if you're querying a huge collection of documents. Basically it caches a copy of whichever data you're querying (and whichever collection you're querying - I believe it caches all documents within) which can lead to high Memory usage.
In my case, it caused a huge wait for every query until the device had cached the data required - hence the non-proportional query times for the increasing numbers of items to return from the exact same collection. This is because it took the same amount of time to cache the collection in each query.
Offline Data - from the Cloud Firestore Docs
I performed some benchmarking to display this effect (with offline persistence enabled) from the same queried collection, but with different amounts of items returned using the .limit parameter:
Now at 100 items returned (with offline persistence disabled), my query takes less than 1 second to complete.
My Firestore query code is below:
let db = Firestore.firestore()
self.date = Date()
let ref = db.collection("collection").whereField("Int", isEqualTo: SomeInt).order(by: "AnotherInt", descending: true).limit(to: 100)
ref.getDocuments() { (querySnapshot, err) in
if let err = err {
print("Error getting documents: \(err)")
} else {
for document in querySnapshot!.documents {
let data = document.data()
//Do things
}
print("QUERY DONE")
let currentTime = Date()
let components = Calendar.current.dateComponents([.second], from: self.date, to: currentTime)
let seconds = components.second!
print("Elapsed time for Firestore query -> \(seconds)s")
// Benchmark result
}
}
well, from what I'm currently doing and research by using nexus 5X in emulator and real android phone Huawei P8,
Firestore and Cloud Storage are both give me a headache of slow response
when I do first document.get() and first storage.getDownloadUrl()
It give me more than 60 seconds response on each request. The slow response only happen in real android phone. Not in emulator. Another strange thing.
After the first encounter, the rest request is smooth.
Here is the simple code where I meet the slow response.
var dbuserref = dbFireStore.collection('user').where('email','==',email);
const querySnapshot = await dbuserref.get();
var url = await defaultStorage.ref(document.data().image_path).getDownloadURL();
I also found link that is researching the same.
https://reformatcode.com/code/android/firestore-document-get-performance

MongoDB updating variable based on date

I am trying to update a database field on a MongoDB collection using Meteor at an exact time -- say 12:00 AM every Monday.
How should I go about doing this?
I am trying matching the day of the week and the exact time number but I can't seem to make it work for the server to do this more than once without using a loop that will make the website freeze.
If you can install a cron-job npm module, like: npm install cron, than you could set up a cron job with a Monday-only pattert, to call your db update code.
var CronJob = require('cron').CronJob;
var job = new CronJob('00 00 12 * * 1', function() {
/*
* Runs every weekday Monday at 12:00:00
*/
}, function () {
/* DB update code */
}
);
Docs available at https://github.com/ncb000gt/node-cron, if you need to fine tune your cron pattern or other options.

Categories

Resources